Merge branch 'ikechan8370:v2' into v2

This commit is contained in:
ifeif 2023-12-21 16:42:16 +08:00 committed by GitHub
commit d537e8abc6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 1218 additions and 2838 deletions

View file

@ -4,34 +4,34 @@ import { Config, defaultOpenAIAPI } from '../utils/config.js'
import { v4 as uuid } from 'uuid'
import delay from 'delay'
import { ChatGPTAPI } from '../utils/openai/chatgpt-api.js'
import { BingAIClient } from '@waylaidwanderer/chatgpt-api'
import SydneyAIClient from '../utils/SydneyAIClient.js'
import { PoeClient } from '../utils/poe/index.js'
import AzureTTS from '../utils/tts/microsoft-azure.js'
import VoiceVoxTTS from '../utils/tts/voicevox.js'
import Version from '../utils/version.js'
import {
completeJSON,
extractContentFromFile,
formatDate,
formatDate2,
generateAudio,
getDefaultReplySetting,
getImageOcrText,
getImg,
getMasterQQ,
getMaxModelTokens,
getMessageById,
getUin,
getUserData,
getUserReplySetting,
isCN,
isImage,
makeForwardMsg,
randomString,
render,
renderUrl,
upsertMessage
completeJSON,
extractContentFromFile,
formatDate,
formatDate2,
generateAudio,
getDefaultReplySetting,
getImageOcrText,
getImg,
getMasterQQ,
getMaxModelTokens,
getMessageById,
getOrDownloadFile,
getUin,
getUserData,
getUserReplySetting,
isCN,
isImage,
makeForwardMsg,
randomString,
render,
renderUrl,
upsertMessage
} from '../utils/common.js'
import { ChatGPTPuppeteer } from '../utils/browser.js'
import { KeyvFile } from 'keyv-file'
@ -78,6 +78,14 @@ import { ClaudeAIClient } from '../utils/claude.ai/index.js'
import { getProxy } from '../utils/proxy.js'
import { QwenApi } from '../utils/alibaba/qwen-api.js'
import { getChatHistoryGroup } from '../utils/chat.js'
import { CustomGoogleGeminiClient } from '../client/CustomGoogleGeminiClient.js'
import { resizeAndCropImage } from '../utils/dalle.js'
import fs from 'fs'
const roleMap = {
owner: 'group owner',
admin: 'group administrator'
}
try {
await import('@azure/openai')
@ -98,7 +106,7 @@ try {
let version = Config.version
let proxy = getProxy()
const originalValues = ['星火', '通义千问', '克劳德', '克劳德2', '必应', 'api', 'API', 'api3', 'API3', 'glm', '巴德']
const originalValues = ['星火', '通义千问', '克劳德', '克劳德2', '必应', 'api', 'API', 'api3', 'API3', 'glm', '巴德']
const correspondingValues = ['xh', 'qwen', 'claude', 'claude2', 'bing', 'api', 'api', 'api3', 'api3', 'chatglm', 'bard']
/**
* 每个对话保留的时长单个对话内ai是保留上下文的超时后销毁对话再次对话创建新的对话
@ -194,6 +202,12 @@ export class chatgpt extends plugin {
/** 执行方法 */
fnc: 'qwen'
},
{
/** 命令正则匹配 */
reg: '^#gemini[sS]*',
/** 执行方法 */
fnc: 'gemini'
},
{
/** 命令正则匹配 */
reg: toggleMode === 'at' ? '^[^#][sS]*' : '^#chat[^gpt][sS]*',
@ -397,6 +411,14 @@ export class chatgpt extends plugin {
await redis.del(`CHATGPT:CONVERSATIONS_QWEN:${e.sender.user_id}`)
await this.reply('已结束当前对话,请@我进行聊天以开启新的对话', true)
}
} else if (use === 'gemini') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_GEMINI:${e.sender.user_id}`)
if (!c) {
await this.reply('当前没有开启对话', true)
} else {
await redis.del(`CHATGPT:CONVERSATIONS_GEMINI:${e.sender.user_id}`)
await this.reply('已结束当前对话,请@我进行聊天以开启新的对话', true)
}
} else if (use === 'bing') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${e.sender.user_id}`)
if (!c) {
@ -466,6 +488,14 @@ export class chatgpt extends plugin {
await redis.del(`CHATGPT:CONVERSATIONS_QWEN:${qq}`)
await this.reply(`已结束${atUser}的对话TA仍可以@我进行聊天以开启新的对话`, true)
}
} else if (use === 'gemini') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_GEMINI:${qq}`)
if (!c) {
await this.reply(`当前${atUser}没有开启对话`, true)
} else {
await redis.del(`CHATGPT:CONVERSATIONS_GEMINI:${qq}`)
await this.reply(`已结束${atUser}的对话TA仍可以@我进行聊天以开启新的对话`, true)
}
} else if (use === 'bing') {
let c = await redis.get(`CHATGPT:CONVERSATIONS_BING:${qq}`)
if (!c) {
@ -597,6 +627,18 @@ export class chatgpt extends plugin {
}
break
}
case 'gemini': {
let qcs = await redis.keys('CHATGPT:CONVERSATIONS_GEMINI:*')
for (let i = 0; i < qcs.length; i++) {
await redis.del(qcs[i])
// todo clean last message id
if (Config.debug) {
logger.info('delete gemini conversation bind: ' + qcs[i])
}
deleted++
}
break
}
}
await this.reply(`结束了${deleted}个用户的对话。`, true)
}
@ -1092,6 +1134,10 @@ export class chatgpt extends plugin {
key = `CHATGPT:CONVERSATIONS_QWEN:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
break
}
case 'gemini': {
key = `CHATGPT:CONVERSATIONS_GEMINI:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`
break
}
}
let ctime = new Date()
previousConversation = (key ? await redis.get(key) : null) || JSON.stringify({
@ -1376,155 +1422,39 @@ export class chatgpt extends plugin {
}
async chatgpt1 (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#chat1')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#chat1', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'api')
return true
return await this.otherMode(e, 'api', '#chat1')
}
async chatgpt3 (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#chat3')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#chat3', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'api3')
return true
return await this.otherMode(e, 'api3', '#chat3')
}
async chatglm (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#chatglm')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#chatglm', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'chatglm')
return true
return await this.otherMode(e, 'chatglm')
}
async bing (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#bing')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#bing', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'bing')
return true
return await this.otherMode(e, 'bing')
}
async claude2 (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#claude2')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#claude2', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'claude2')
return true
return await this.otherMode(e, 'claude2')
}
async claude (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#claude')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#claude', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'claude')
return true
return await this.otherMode(e, 'claude')
}
async qwen (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#xh')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#qwen', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'qwen')
return true
return await this.otherMode(e, 'gemini')
}
async gemini (e) {
return await this.otherMode(e, 'gemini')
}
async xh (e) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略#xh')
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), '#xh', '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, 'xh')
return true
return await this.otherMode(e, 'xh')
}
async cacheContent (e, use, content, prompt, quote = [], mood = '', suggest = '', imgUrls = []) {
@ -1584,13 +1514,17 @@ export class chatgpt extends plugin {
}
const userData = await getUserData(e.user_id)
const useCast = userData.cast || {}
switch (use) {
case 'browser': {
if (use === 'browser') {
{
return await this.chatgptBrowserBased(prompt, conversation)
}
case 'bing': {
} else if (use === 'bing') {
{
let throttledTokens = []
let { bingToken, allThrottled } = await getAvailableBingToken(conversation, throttledTokens)
let {
bingToken,
allThrottled
} = await getAvailableBingToken(conversation, throttledTokens)
let cookies
if (bingToken?.indexOf('=') > -1) {
cookies = bingToken
@ -1628,73 +1562,55 @@ export class chatgpt extends plugin {
}
// 重新拿存储的token因为可能之前有过期的被删了
let abtrs = await getAvailableBingToken(conversation, throttledTokens)
if (Config.toneStyle === 'Sydney' || Config.toneStyle === 'Custom') {
bingToken = abtrs.bingToken
// eslint-disable-next-line no-unused-vars
allThrottled = abtrs.allThrottled
if (bingToken?.indexOf('=') > -1) {
cookies = bingToken
}
if (!bingAIClient.opts) {
bingAIClient.opts = {}
}
bingAIClient.opts.userToken = bingToken
bingAIClient.opts.cookies = cookies
// opt.messageType = allThrottled ? 'Chat' : 'SearchQuery'
if (Config.enableGroupContext && e.isGroup && typeof e.group.getMemberMap === 'function') {
try {
opt.groupId = e.group_id
opt.qq = e.sender.user_id
opt.nickname = e.sender.card
opt.groupName = e.group.name || e.group_name
opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname
let master = (await getMasterQQ())[0]
if (master && e.group) {
opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname
}
if (master && !e.group) {
opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname
}
opt.chats = await getChatHistoryGroup(e, Config.groupContextLength)
} catch (err) {
logger.warn('获取群聊聊天记录失败,本次对话不携带聊天记录', err)
}
}
let toSummaryFileContent
try {
if (e.source) {
let seq = e.isGroup ? e.source.seq : e.source.time
if (e.adapter === 'shamrock') {
seq = e.source.message_id
}
let msgs = e.isGroup ? await e.group.getChatHistory(seq, 1) : await e.friend.getChatHistory(seq, 1)
let sourceMsg = msgs[msgs.length - 1]
let fileMsgElem = sourceMsg.file || sourceMsg.message.find(msg => msg.type === 'file')
if (fileMsgElem) {
toSummaryFileContent = await extractContentFromFile(fileMsgElem, e)
}
}
} catch (err) {
logger.warn('读取文件内容出错, 忽略文件内容', err)
}
opt.toSummaryFileContent = toSummaryFileContent
} else {
// 重新创建client因为token可能换到别的了
if (bingToken?.indexOf('=') > -1) {
cookies = bingToken
}
let bingOption = {
userToken: abtrs.bingToken, // "_U" cookie from bing.com
cookies,
debug: Config.debug,
proxy: Config.proxy,
host: Config.sydneyReverseProxy
}
if (Config.proxy && Config.sydneyReverseProxy && !Config.sydneyForceUseReverse) {
delete bingOption.host
}
bingAIClient = new BingAIClient(bingOption)
bingToken = abtrs.bingToken
// eslint-disable-next-line no-unused-vars
allThrottled = abtrs.allThrottled
if (bingToken?.indexOf('=') > -1) {
cookies = bingToken
}
if (!bingAIClient.opts) {
bingAIClient.opts = {}
}
bingAIClient.opts.userToken = bingToken
bingAIClient.opts.cookies = cookies
// opt.messageType = allThrottled ? 'Chat' : 'SearchQuery'
if (Config.enableGroupContext && e.isGroup && typeof e.group.getMemberMap === 'function') {
try {
opt.groupId = e.group_id
opt.qq = e.sender.user_id
opt.nickname = e.sender.card
opt.groupName = e.group.name || e.group_name
opt.botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname
let master = (await getMasterQQ())[0]
if (master && e.group) {
opt.masterName = e.group.pickMember(parseInt(master)).card || e.group.pickMember(parseInt(master)).nickname
}
if (master && !e.group) {
opt.masterName = e.bot.getFriendList().get(parseInt(master))?.nickname
}
opt.chats = await getChatHistoryGroup(e, Config.groupContextLength)
} catch (err) {
logger.warn('获取群聊聊天记录失败,本次对话不携带聊天记录', err)
}
}
let toSummaryFileContent
try {
if (e.source) {
let seq = e.isGroup ? e.source.seq : e.source.time
if (e.adapter === 'shamrock') {
seq = e.source.message_id
}
let msgs = e.isGroup ? await e.group.getChatHistory(seq, 1) : await e.friend.getChatHistory(seq, 1)
let sourceMsg = msgs[msgs.length - 1]
let fileMsgElem = sourceMsg.file || sourceMsg.message.find(msg => msg.type === 'file')
if (fileMsgElem) {
toSummaryFileContent = await extractContentFromFile(fileMsgElem, e)
}
}
} catch (err) {
logger.warn('读取文件内容出错, 忽略文件内容', err)
}
opt.toSummaryFileContent = toSummaryFileContent
// 写入图片数据
if (Config.sydneyImageRecognition) {
const image = await getImg(e)
@ -1792,45 +1708,44 @@ export class chatgpt extends plugin {
} else {
retry = 0
}
} else
if (message && typeof message === 'string' && message.indexOf('限流') > -1) {
throttledTokens.push(bingToken)
let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
const badBingToken = bingTokens.findIndex(element => element.Token === bingToken)
const now = new Date()
const hours = now.getHours()
now.setHours(hours + 6)
bingTokens[badBingToken].State = '受限'
bingTokens[badBingToken].DisactivationTime = now
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
} else if (message && typeof message === 'string' && message.indexOf('限流') > -1) {
throttledTokens.push(bingToken)
let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
const badBingToken = bingTokens.findIndex(element => element.Token === bingToken)
const now = new Date()
const hours = now.getHours()
now.setHours(hours + 6)
bingTokens[badBingToken].State = '受限'
bingTokens[badBingToken].DisactivationTime = now
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
// 不减次数
} else if (message && typeof message === 'string' && message.indexOf('UnauthorizedRequest') > -1) {
} else if (message && typeof message === 'string' && message.indexOf('UnauthorizedRequest') > -1) {
// token过期了
let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
const badBingToken = bingTokens.findIndex(element => element.Token === bingToken)
if (badBingToken > 0) {
// 可能是微软抽风,给三次机会
if (bingTokens[badBingToken]?.exception) {
if (bingTokens[badBingToken].exception <= 3) {
bingTokens[badBingToken].exception += 1
} else {
bingTokens[badBingToken].exception = 0
bingTokens[badBingToken].State = '过期'
}
let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
const badBingToken = bingTokens.findIndex(element => element.Token === bingToken)
if (badBingToken > 0) {
// 可能是微软抽风,给三次机会
if (bingTokens[badBingToken]?.exception) {
if (bingTokens[badBingToken].exception <= 3) {
bingTokens[badBingToken].exception += 1
} else {
bingTokens[badBingToken].exception = 1
bingTokens[badBingToken].exception = 0
bingTokens[badBingToken].State = '过期'
}
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
} else {
retry = retry - 1
bingTokens[badBingToken].exception = 1
}
errorMessage = 'UnauthorizedRequest必应token不正确或已过期'
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
} else {
retry = retry - 1
}
errorMessage = 'UnauthorizedRequest必应token不正确或已过期'
// logger.warn(`token${bingToken}疑似不存在或已过期,再试试`)
// retry = retry - 1
} else {
retry--
errorMessage = message === 'Timed out waiting for response. Try enabling debug mode to see more information.' ? (reply ? `${reply}\n不行了,我的大脑过载了,处理不过来了!` : '必应的小脑瓜不好使了,不知道怎么回答!') : message
}
} else {
retry--
errorMessage = message === 'Timed out waiting for response. Try enabling debug mode to see more information.' ? (reply ? `${reply}\n不行了,我的大脑过载了,处理不过来了!` : '必应的小脑瓜不好使了,不知道怎么回答!') : message
}
}
} while (retry > 0)
if (errorMessage) {
@ -1865,7 +1780,8 @@ export class chatgpt extends plugin {
}
}
}
case 'api3': {
} else if (use === 'api3') {
{
// official without cloudflare
let accessToken = await redis.get('CHATGPT:TOKEN')
if (!accessToken) {
@ -1889,7 +1805,8 @@ export class chatgpt extends plugin {
}
return sendMessageResult
}
case 'chatglm': {
} else if (use === 'chatglm') {
{
const cacheOptions = {
namespace: 'chatglm_6b',
store: new KeyvFile({ filename: 'cache.json' })
@ -1901,7 +1818,8 @@ export class chatgpt extends plugin {
let sendMessageResult = await this.chatGPTApi.sendMessage(prompt, conversation)
return sendMessageResult
}
case 'poe': {
} else if (use === 'poe') {
{
const cookie = await redis.get('CHATGPT:POE_TOKEN')
if (!cookie) {
throw new Error('未绑定Poe Cookie请使用#chatgpt设置Poe token命令绑定cookie')
@ -1919,7 +1837,8 @@ export class chatgpt extends plugin {
text: response.data
}
}
case 'claude': {
} else if (use === 'claude') {
{
let client = new SlackClaudeClient({
slackUserToken: Config.slackUserToken,
slackChannelId: Config.slackChannelId
@ -1943,7 +1862,8 @@ export class chatgpt extends plugin {
text
}
}
case 'claude2': {
} else if (use === 'claude2') {
{
let { conversationId } = conversation
let client = new ClaudeAIClient({
organizationId: Config.claudeAIOrganizationId,
@ -1983,7 +1903,8 @@ export class chatgpt extends plugin {
return await client.sendMessage(prompt, conv.uuid, attachments)
}
}
case 'xh': {
} else if (use === 'xh') {
{
const cacheOptions = {
namespace: 'xh',
store: new KeyvFile({ filename: 'cache.json' })
@ -2006,7 +1927,8 @@ export class chatgpt extends plugin {
})
return response
}
case 'azure': {
} else if (use === 'azure') {
{
let azureModel
try {
azureModel = await import('@azure/openai')
@ -2016,15 +1938,22 @@ export class chatgpt extends plugin {
let OpenAIClient = azureModel.OpenAIClient
let AzureKeyCredential = azureModel.AzureKeyCredential
let msg = conversation.messages
let content = { role: 'user', content: prompt }
let content = {
role: 'user',
content: prompt
}
msg.push(content)
const client = new OpenAIClient(Config.azureUrl, new AzureKeyCredential(Config.azApiKey))
const deploymentName = Config.azureDeploymentName
const { choices } = await client.getChatCompletions(deploymentName, msg)
let completion = choices[0].message
return { text: completion.content, message: completion }
return {
text: completion.content,
message: completion
}
}
case 'qwen': {
} else if (use === 'qwen') {
{
let completionParams = {
parameters: {
top_p: Config.qwenTopP || 0.5,
@ -2038,12 +1967,15 @@ export class chatgpt extends plugin {
completionParams.model = Config.qwenModel
}
const currentDate = new Date().toISOString().split('T')[0]
async function um (message) {
async function um(message) {
return await upsertMessage(message, 'QWEN')
}
async function gm (id) {
async function gm(id) {
return await getMessageById(id, 'QWEN')
}
let opts = {
apiKey: Config.qwenApiKey,
debug: false,
@ -2075,7 +2007,8 @@ export class chatgpt extends plugin {
}
return msg
}
case 'bard': {
} else if (use === 'bard') {
{
// 处理cookie
const matchesPSID = /__Secure-1PSID=([^;]+)/.exec(Config.bardPsid)
const matchesPSIDTS = /__Secure-1PSIDTS=([^;]+)/.exec(Config.bardPsid)
@ -2105,13 +2038,13 @@ export class chatgpt extends plugin {
bardURL: Config.bardForceUseReverse ? Config.bardReverseProxy : 'https://bard.google.com'
})
let chat = await bot.createChat(conversation?.conversationId
? {
? {
conversationID: conversation.conversationId,
responseID: conversation.parentMessageId,
choiceID: conversation.clientId,
_reqID: conversation.invocationId
}
: {})
: {})
let response = await chat.ask(prompt, {
image: imageBuff,
format: Bard.JSON
@ -2125,7 +2058,125 @@ export class chatgpt extends plugin {
images: response.images
}
}
default: {
} else if (use === 'gemini') {
{
let client = new CustomGoogleGeminiClient({
e,
userId: e.sender.user_id,
key: Config.geminiKey,
model: Config.geminiModel,
baseUrl: Config.geminiBaseUrl,
debug: Config.debug
})
let option = {
stream: false,
onProgress: (data) => {
if (Config.debug) {
logger.info(data)
}
},
parentMessageId: conversation.parentMessageId,
conversationId: conversation.conversationId
}
if (Config.geminiModel.includes('vision')) {
const image = await getImg(e)
let imageUrl = image ? image[0] : undefined
if (imageUrl) {
let md5 = imageUrl.split(/[/-]/).find(s => s.length === 32)?.toUpperCase()
let imageLoc = await getOrDownloadFile(`ocr/${md5}.png`, imageUrl)
let outputLoc = imageLoc.replace(`${md5}.png`, `${md5}_512.png`)
await resizeAndCropImage(imageLoc, outputLoc, 512)
let buffer = fs.readFileSync(outputLoc)
option.image = buffer.toString('base64')
}
}
if (Config.smartMode) {
/**
* @type {AbstractTool[]}
*/
let tools = [
new QueryStarRailTool(),
new WebsiteTool(),
new SendPictureTool(),
new SendVideoTool(),
// new ImageCaptionTool(),
new SearchVideoTool(),
new SendAvatarTool(),
new SerpImageTool(),
new SearchMusicTool(),
new SendMusicTool(),
// new SerpIkechan8370Tool(),
// new SerpTool(),
new SendAudioMessageTool(),
// new ProcessPictureTool(),
new APTool(),
// new HandleMessageMsgTool(),
new SendMessageToSpecificGroupOrUserTool(),
// new SendDiceTool(),
new QueryGenshinTool()
]
if (Config.amapKey) {
tools.push(new WeatherTool())
}
if (e.isGroup) {
tools.push(new QueryUserinfoTool())
// let self = e.group.pickMember(e.self_id)
if (e.group.is_admin || e.group.is_owner) {
tools.push(new EditCardTool())
tools.push(new JinyanTool())
tools.push(new KickOutTool())
}
if (e.group.is_owner) {
tools.push(new SetTitleTool())
}
}
switch (Config.serpSource) {
case 'ikechan8370': {
tools.push(new SerpIkechan8370Tool())
break
}
case 'azure': {
if (!Config.azSerpKey) {
logger.warn('未配置bing搜索密钥转为使用ikechan8370搜索源')
tools.push(new SerpIkechan8370Tool())
} else {
tools.push(new SerpTool())
}
break
}
default: {
tools.push(new SerpIkechan8370Tool())
}
}
client.addTools(tools)
}
let system = Config.geminiPrompt
if (Config.enableGroupContext && e.isGroup) {
let chats = await getChatHistoryGroup(e, Config.groupContextLength)
const namePlaceholder = '[name]'
const defaultBotName = 'GeminiPro'
const groupContextTip = Config.groupContextTip
let botName = e.isGroup ? (e.group.pickMember(getUin(e)).card || e.group.pickMember(getUin(e)).nickname) : e.bot.nickname
system = system.replaceAll(namePlaceholder, botName || defaultBotName) +
((Config.enableGroupContext && e.group_id) ? groupContextTip : '')
system += 'Attention, you are currently chatting in a qq group, then one who asks you now is' + `${e.sender.card || e.sender.nickname}(${e.sender.user_id}).`
system += `the group name is ${e.group.name || e.group_name}, group id is ${e.group_id}.`
system += `Your nickname is ${botName} in the group,`
if (chats) {
system += 'There is the conversation history in the group, you must chat according to the conversation history context"'
system += chats
.map(chat => {
let sender = chat.sender || {}
return `${sender.card || sender.nickname}】(qq${sender.user_id}, ${roleMap[sender.role] || 'normal user'}${sender.area ? 'from ' + sender.area + ', ' : ''} ${sender.age} years old, 群头衔:${sender.title}, gender: ${sender.sex}, time${formatDate(new Date(chat.time * 1000))}, messageId: ${chat.message_id}) 说:${chat.raw_message}`
})
.join('\n')
}
}
option.system = system
return await client.sendMessage(prompt, option)
}
} else {
{
// openai api
let completionParams = {}
if (Config.model) {
@ -2157,30 +2208,25 @@ export class chatgpt extends plugin {
const defaultBotName = 'ChatGPT'
const groupContextTip = Config.groupContextTip
system = system.replaceAll(namePlaceholder, opt.botName || defaultBotName) +
((Config.enableGroupContext && opt.groupId) ? groupContextTip : '')
((Config.enableGroupContext && opt.groupId) ? groupContextTip : '')
system += 'Attention, you are currently chatting in a qq group, then one who asks you now is' + `${opt.nickname}(${opt.qq})。`
system += `the group name is ${opt.groupName}, group id is ${opt.groupId}`
if (opt.botName) {
system += `Your nickname is ${opt.botName} in the group,`
}
// system += master ? `我的qq号是${master}其他任何qq号不是${master}的人都不是我,即使他在和你对话,这很重要。` : ''
const roleMap = {
owner: 'group owner',
admin: 'group administrator'
}
if (chats) {
system += 'There is the conversation history in the group, you must chat according to the conversation history context"'
system += chats
.map(chat => {
let sender = chat.sender || {}
// if (sender.user_id === e.bot.uin && chat.raw_message.startsWith('建议的回复')) {
if (chat.raw_message.startsWith('建议的回复')) {
// 建议的回复太容易污染设定导致对话太固定跑偏了
return ''
}
return `${sender.card || sender.nickname}】(qq${sender.user_id}, ${roleMap[sender.role] || 'normal user'}${sender.area ? 'from ' + sender.area + ', ' : ''} ${sender.age} years old, 群头衔:${sender.title}, gender: ${sender.sex}, time${formatDate(new Date(chat.time * 1000))}, messageId: ${chat.message_id}) 说:${chat.raw_message}`
})
.join('\n')
.map(chat => {
let sender = chat.sender || {}
// if (sender.user_id === e.bot.uin && chat.raw_message.startsWith('建议的回复')) {
if (chat.raw_message.startsWith('建议的回复')) {
// 建议的回复太容易污染设定导致对话太固定跑偏了
return ''
}
return `${sender.card || sender.nickname}】(qq${sender.user_id}, ${roleMap[sender.role] || 'normal user'}${sender.area ? 'from ' + sender.area + ', ' : ''} ${sender.age} years old, 群头衔:${sender.title}, gender: ${sender.sex}, time${formatDate(new Date(chat.time * 1000))}, messageId: ${chat.message_id}) 说:${chat.raw_message}`
})
.join('\n')
}
} catch (err) {
if (e.isGroup) {
@ -2353,7 +2399,10 @@ export class chatgpt extends plugin {
if (msg.text) {
await e.reply(msg.text.replace('\n\n\n', '\n'))
}
let { name, arguments: args } = msg.functionCall
let {
name,
arguments: args
} = msg.functionCall
args = JSON.parse(args)
// 感觉换成targetGroupIdOrUserQQNumber这种表意比较清楚的变量名效果会好一丢丢
if (!args.groupId) {
@ -2364,7 +2413,10 @@ export class chatgpt extends plugin {
} catch (err) {
args.groupId = e.group_id + '' || e.sender.user_id + ''
}
let functionResult = await fullFuncMap[name.trim()].exec(Object.assign({ isAdmin, sender }, args), e)
let functionResult = await fullFuncMap[name.trim()].exec(Object.assign({
isAdmin,
sender
}, args), e)
logger.mark(`function ${name} execution result: ${functionResult}`)
option.parentMessageId = msg.id
option.name = name
@ -2692,6 +2744,25 @@ export class chatgpt extends plugin {
}
return await this.chatGPTApi.sendMessage(prompt, sendMessageOption)
}
async otherMode (e, mode, pattern = `#${mode}`) {
if (!Config.allowOtherMode) {
return false
}
let ats = e.message.filter(m => m.type === 'at')
if (!(e.atme || e.atBot) && ats.length > 0) {
if (Config.debug) {
logger.mark('艾特别人了,没艾特我,忽略' + pattern)
}
return false
}
let prompt = _.replace(e.raw_message.trimStart(), pattern, '').trim()
if (prompt.length === 0) {
return false
}
await this.abstractChat(e, prompt, mode)
return true
}
}
async function getAvailableBingToken (conversation, throttled = []) {