mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 13:57:10 +00:00
Merge branch 'ikechan8370:v2' into v2
This commit is contained in:
commit
7b83b9a008
9 changed files with 251 additions and 177 deletions
|
|
@ -1,5 +1,4 @@
|
||||||

|

|
||||||
<div align=center> <h1>云崽系机器人的智能聊天插件</h1> </div>
|
|
||||||
<div align=center>
|
<div align=center>
|
||||||
|
|
||||||
<img src ="https://img.shields.io/github/issues/ikechan8370/chatgpt-plugin?logo=github"/>
|
<img src ="https://img.shields.io/github/issues/ikechan8370/chatgpt-plugin?logo=github"/>
|
||||||
|
|
|
||||||
259
apps/chat.js
259
apps/chat.js
|
|
@ -1,12 +1,12 @@
|
||||||
import plugin from '../../../lib/plugins/plugin.js'
|
import plugin from '../../../lib/plugins/plugin.js'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import {Config, defaultOpenAIAPI} from '../utils/config.js'
|
import { Config, defaultOpenAIAPI } from '../utils/config.js'
|
||||||
import {v4 as uuid} from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import delay from 'delay'
|
import delay from 'delay'
|
||||||
import {ChatGPTAPI} from '../utils/openai/chatgpt-api.js'
|
import { ChatGPTAPI } from '../utils/openai/chatgpt-api.js'
|
||||||
import {BingAIClient} from '@waylaidwanderer/chatgpt-api'
|
import { BingAIClient } from '@waylaidwanderer/chatgpt-api'
|
||||||
import SydneyAIClient from '../utils/SydneyAIClient.js'
|
import SydneyAIClient from '../utils/SydneyAIClient.js'
|
||||||
import {PoeClient} from '../utils/poe/index.js'
|
import { PoeClient } from '../utils/poe/index.js'
|
||||||
import AzureTTS from '../utils/tts/microsoft-azure.js'
|
import AzureTTS from '../utils/tts/microsoft-azure.js'
|
||||||
import VoiceVoxTTS from '../utils/tts/voicevox.js'
|
import VoiceVoxTTS from '../utils/tts/voicevox.js'
|
||||||
import Version from '../utils/version.js'
|
import Version from '../utils/version.js'
|
||||||
|
|
@ -33,51 +33,51 @@ import {
|
||||||
renderUrl,
|
renderUrl,
|
||||||
upsertMessage
|
upsertMessage
|
||||||
} from '../utils/common.js'
|
} from '../utils/common.js'
|
||||||
import {ChatGPTPuppeteer} from '../utils/browser.js'
|
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
||||||
import {KeyvFile} from 'keyv-file'
|
import { KeyvFile } from 'keyv-file'
|
||||||
import {OfficialChatGPTClient} from '../utils/message.js'
|
import { OfficialChatGPTClient } from '../utils/message.js'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
import {deleteConversation, getConversations, getLatestMessageIdByConversationId} from '../utils/conversation.js'
|
import { deleteConversation, getConversations, getLatestMessageIdByConversationId } from '../utils/conversation.js'
|
||||||
import {convertSpeaker, speakers} from '../utils/tts.js'
|
import { convertSpeaker, speakers } from '../utils/tts.js'
|
||||||
import ChatGLMClient from '../utils/chatglm.js'
|
import ChatGLMClient from '../utils/chatglm.js'
|
||||||
import {convertFaces} from '../utils/face.js'
|
import { convertFaces } from '../utils/face.js'
|
||||||
import {SlackClaudeClient} from '../utils/slack/slackClient.js'
|
import { SlackClaudeClient } from '../utils/slack/slackClient.js'
|
||||||
import {getPromptByName} from '../utils/prompts.js'
|
import { getPromptByName } from '../utils/prompts.js'
|
||||||
import BingDrawClient from '../utils/BingDraw.js'
|
import BingDrawClient from '../utils/BingDraw.js'
|
||||||
import XinghuoClient from '../utils/xinghuo/xinghuo.js'
|
import XinghuoClient from '../utils/xinghuo/xinghuo.js'
|
||||||
import Bard from '../utils/bard.js'
|
import Bard from '../utils/bard.js'
|
||||||
import {JinyanTool} from '../utils/tools/JinyanTool.js'
|
import { JinyanTool } from '../utils/tools/JinyanTool.js'
|
||||||
import {SendVideoTool} from '../utils/tools/SendBilibiliTool.js'
|
import { SendVideoTool } from '../utils/tools/SendBilibiliTool.js'
|
||||||
import {KickOutTool} from '../utils/tools/KickOutTool.js'
|
import { KickOutTool } from '../utils/tools/KickOutTool.js'
|
||||||
import {EditCardTool} from '../utils/tools/EditCardTool.js'
|
import { EditCardTool } from '../utils/tools/EditCardTool.js'
|
||||||
import {SearchVideoTool} from '../utils/tools/SearchBilibiliTool.js'
|
import { SearchVideoTool } from '../utils/tools/SearchBilibiliTool.js'
|
||||||
import {SearchMusicTool} from '../utils/tools/SearchMusicTool.js'
|
import { SearchMusicTool } from '../utils/tools/SearchMusicTool.js'
|
||||||
import {QueryStarRailTool} from '../utils/tools/QueryStarRailTool.js'
|
import { QueryStarRailTool } from '../utils/tools/QueryStarRailTool.js'
|
||||||
import {WebsiteTool} from '../utils/tools/WebsiteTool.js'
|
import { WebsiteTool } from '../utils/tools/WebsiteTool.js'
|
||||||
import {WeatherTool} from '../utils/tools/WeatherTool.js'
|
import { WeatherTool } from '../utils/tools/WeatherTool.js'
|
||||||
import {SerpTool} from '../utils/tools/SerpTool.js'
|
import { SerpTool } from '../utils/tools/SerpTool.js'
|
||||||
import {SerpIkechan8370Tool} from '../utils/tools/SerpIkechan8370Tool.js'
|
import { SerpIkechan8370Tool } from '../utils/tools/SerpIkechan8370Tool.js'
|
||||||
import {SendPictureTool} from '../utils/tools/SendPictureTool.js'
|
import { SendPictureTool } from '../utils/tools/SendPictureTool.js'
|
||||||
import {SerpImageTool} from '../utils/tools/SearchImageTool.js'
|
import { SerpImageTool } from '../utils/tools/SearchImageTool.js'
|
||||||
import {ImageCaptionTool} from '../utils/tools/ImageCaptionTool.js'
|
import { ImageCaptionTool } from '../utils/tools/ImageCaptionTool.js'
|
||||||
import {SendAudioMessageTool} from '../utils/tools/SendAudioMessageTool.js'
|
import { SendAudioMessageTool } from '../utils/tools/SendAudioMessageTool.js'
|
||||||
import {ProcessPictureTool} from '../utils/tools/ProcessPictureTool.js'
|
import { ProcessPictureTool } from '../utils/tools/ProcessPictureTool.js'
|
||||||
import {APTool} from '../utils/tools/APTool.js'
|
import { APTool } from '../utils/tools/APTool.js'
|
||||||
import {QueryGenshinTool} from '../utils/tools/QueryGenshinTool.js'
|
import { QueryGenshinTool } from '../utils/tools/QueryGenshinTool.js'
|
||||||
import {HandleMessageMsgTool} from '../utils/tools/HandleMessageMsgTool.js'
|
import { HandleMessageMsgTool } from '../utils/tools/HandleMessageMsgTool.js'
|
||||||
import {QueryUserinfoTool} from '../utils/tools/QueryUserinfoTool.js'
|
import { QueryUserinfoTool } from '../utils/tools/QueryUserinfoTool.js'
|
||||||
import {EliMovieTool} from '../utils/tools/EliMovieTool.js'
|
import { EliMovieTool } from '../utils/tools/EliMovieTool.js'
|
||||||
import {EliMusicTool} from '../utils/tools/EliMusicTool.js'
|
import { EliMusicTool } from '../utils/tools/EliMusicTool.js'
|
||||||
import {SendMusicTool} from '../utils/tools/SendMusicTool.js'
|
import { SendMusicTool } from '../utils/tools/SendMusicTool.js'
|
||||||
import {SendDiceTool} from '../utils/tools/SendDiceTool.js'
|
import { SendDiceTool } from '../utils/tools/SendDiceTool.js'
|
||||||
import {SendAvatarTool} from '../utils/tools/SendAvatarTool.js'
|
import { SendAvatarTool } from '../utils/tools/SendAvatarTool.js'
|
||||||
import {SendMessageToSpecificGroupOrUserTool} from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js'
|
import { SendMessageToSpecificGroupOrUserTool } from '../utils/tools/SendMessageToSpecificGroupOrUserTool.js'
|
||||||
import {SetTitleTool} from '../utils/tools/SetTitleTool.js'
|
import { SetTitleTool } from '../utils/tools/SetTitleTool.js'
|
||||||
import {solveCaptchaOneShot} from '../utils/bingCaptcha.js'
|
import { solveCaptchaOneShot } from '../utils/bingCaptcha.js'
|
||||||
import {ClaudeAIClient} from '../utils/claude.ai/index.js'
|
import { ClaudeAIClient } from '../utils/claude.ai/index.js'
|
||||||
import {getProxy} from '../utils/proxy.js'
|
import { getProxy } from '../utils/proxy.js'
|
||||||
import {QwenApi} from '../utils/alibaba/qwen-api.js'
|
import { QwenApi } from '../utils/alibaba/qwen-api.js'
|
||||||
import {getChatHistoryGroup} from '../utils/chat.js'
|
import { getChatHistoryGroup } from '../utils/chat.js'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await import('@azure/openai')
|
await import('@azure/openai')
|
||||||
|
|
@ -97,6 +97,9 @@ try {
|
||||||
}
|
}
|
||||||
let version = Config.version
|
let version = Config.version
|
||||||
let proxy = getProxy()
|
let proxy = getProxy()
|
||||||
|
|
||||||
|
const originalValues = ['星火', '通义千问', '克劳德', '克劳德2', '必应', 'api', 'API', 'api3', 'API3', 'glm', '巴德']
|
||||||
|
const correspondingValues = ['xh', 'qwen', 'claude', 'claude2', 'bing', 'api', 'api', 'api3', 'api3', 'chatglm', 'bard']
|
||||||
/**
|
/**
|
||||||
* 每个对话保留的时长。单个对话内ai是保留上下文的。超时后销毁对话,再次对话创建新的对话。
|
* 每个对话保留的时长。单个对话内ai是保留上下文的。超时后销毁对话,再次对话创建新的对话。
|
||||||
* 单位:秒
|
* 单位:秒
|
||||||
|
|
@ -204,11 +207,11 @@ export class chatgpt extends plugin {
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reg: '^#(chatgpt)?(结束|新开|摧毁|毁灭|完结)对话([sS]*)',
|
reg: '^#(chatgpt|星火|通义千问|克劳德|克劳德2|必应|api|API|api3|API3|glm|巴德)?(结束|新开|摧毁|毁灭|完结)对话([sS]*)',
|
||||||
fnc: 'destroyConversations'
|
fnc: 'destroyConversations'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
reg: '^#(chatgpt)?(结束|新开|摧毁|毁灭|完结)全部对话$',
|
reg: '^#(chatgpt|星火|通义千问|克劳德|克劳德2|必应|api|API|api3|API3|glm|巴德)?(结束|新开|摧毁|毁灭|完结)全部对话$',
|
||||||
fnc: 'endAllConversations',
|
fnc: 'endAllConversations',
|
||||||
permission: 'master'
|
permission: 'master'
|
||||||
},
|
},
|
||||||
|
|
@ -299,7 +302,15 @@ export class chatgpt extends plugin {
|
||||||
*/
|
*/
|
||||||
async destroyConversations (e) {
|
async destroyConversations (e) {
|
||||||
const userData = await getUserData(e.user_id)
|
const userData = await getUserData(e.user_id)
|
||||||
const use = (userData.mode === 'default' ? null : userData.mode) || await redis.get('CHATGPT:USE')
|
const match = e.msg.trim().match('^#?(.*)(结束|新开|摧毁|毁灭|完结)对话')
|
||||||
|
console.log(match[1])
|
||||||
|
let use
|
||||||
|
if (match[1] && match[1] != 'chatgpt') {
|
||||||
|
use = correspondingValues[originalValues.indexOf(match[1])]
|
||||||
|
} else {
|
||||||
|
use = (userData.mode === 'default' ? null : userData.mode) || await redis.get('CHATGPT:USE')
|
||||||
|
}
|
||||||
|
console.log(use)
|
||||||
await redis.del(`CHATGPT:WRONG_EMOTION:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
|
await redis.del(`CHATGPT:WRONG_EMOTION:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`)
|
||||||
if (use === 'claude') {
|
if (use === 'claude') {
|
||||||
// let client = new SlackClaudeClient({
|
// let client = new SlackClaudeClient({
|
||||||
|
|
@ -476,7 +487,15 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async endAllConversations (e) {
|
async endAllConversations (e) {
|
||||||
let use = await redis.get('CHATGPT:USE') || 'api'
|
const match = e.msg.trim().match('^#?(.*)(结束|新开|摧毁|毁灭|完结)全部对话')
|
||||||
|
console.log(match[1])
|
||||||
|
let use
|
||||||
|
if (match[1] && match[1] != 'chatgpt') {
|
||||||
|
use = correspondingValues[originalValues.indexOf(match[1])]
|
||||||
|
} else {
|
||||||
|
use = await redis.get('CHATGPT:USE') || 'api'
|
||||||
|
}
|
||||||
|
console.log(use)
|
||||||
let deleted = 0
|
let deleted = 0
|
||||||
switch (use) {
|
switch (use) {
|
||||||
case 'claude': {
|
case 'claude': {
|
||||||
|
|
@ -797,7 +816,7 @@ export class chatgpt extends plugin {
|
||||||
* #chatgpt
|
* #chatgpt
|
||||||
*/
|
*/
|
||||||
async chatgpt (e) {
|
async chatgpt (e) {
|
||||||
let msg = Version.isTrss ? e.msg : e.raw_message
|
let msg = (Version.isTrss || e.adapter === 'shamrock') ? e.msg : e.raw_message
|
||||||
let prompt
|
let prompt
|
||||||
if (this.toggleMode === 'at') {
|
if (this.toggleMode === 'at') {
|
||||||
if (!msg || e.msg?.startsWith('#')) {
|
if (!msg || e.msg?.startsWith('#')) {
|
||||||
|
|
@ -1577,36 +1596,22 @@ export class chatgpt extends plugin {
|
||||||
cookies = bingToken
|
cookies = bingToken
|
||||||
}
|
}
|
||||||
let bingAIClient
|
let bingAIClient
|
||||||
if (Config.toneStyle === 'Sydney' || Config.toneStyle === 'Custom') {
|
const cacheOptions = {
|
||||||
const cacheOptions = {
|
namespace: Config.toneStyle,
|
||||||
namespace: Config.toneStyle,
|
store: new KeyvFile({ filename: 'cache.json' })
|
||||||
store: new KeyvFile({ filename: 'cache.json' })
|
|
||||||
}
|
|
||||||
bingAIClient = new SydneyAIClient({
|
|
||||||
userToken: bingToken, // "_U" cookie from bing.com
|
|
||||||
cookies,
|
|
||||||
debug: Config.debug,
|
|
||||||
cache: cacheOptions,
|
|
||||||
user: e.sender.user_id,
|
|
||||||
proxy: Config.proxy
|
|
||||||
})
|
|
||||||
// Sydney不实现上下文传递,删除上下文索引
|
|
||||||
delete conversation.clientId
|
|
||||||
delete conversation.invocationId
|
|
||||||
delete conversation.conversationSignature
|
|
||||||
} else {
|
|
||||||
let bingOption = {
|
|
||||||
userToken: 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)
|
|
||||||
}
|
}
|
||||||
|
bingAIClient = new SydneyAIClient({
|
||||||
|
userToken: bingToken, // "_U" cookie from bing.com
|
||||||
|
cookies,
|
||||||
|
debug: Config.debug,
|
||||||
|
cache: cacheOptions,
|
||||||
|
user: e.sender.user_id,
|
||||||
|
proxy: Config.proxy
|
||||||
|
})
|
||||||
|
// Sydney不实现上下文传递,删除上下文索引
|
||||||
|
delete conversation.clientId
|
||||||
|
delete conversation.invocationId
|
||||||
|
delete conversation.conversationSignature
|
||||||
let response
|
let response
|
||||||
let reply = ''
|
let reply = ''
|
||||||
let retry = 3
|
let retry = 3
|
||||||
|
|
@ -1658,9 +1663,13 @@ export class chatgpt extends plugin {
|
||||||
let toSummaryFileContent
|
let toSummaryFileContent
|
||||||
try {
|
try {
|
||||||
if (e.source) {
|
if (e.source) {
|
||||||
let msgs = e.isGroup ? await e.group.getChatHistory(e.source.seq, 1) : await e.friend.getChatHistory(e.source.time, 1)
|
let seq = e.isGroup ? e.source.seq : e.source.time
|
||||||
let sourceMsg = msgs[0]
|
if (e.adapter === 'shamrock') {
|
||||||
let fileMsgElem = sourceMsg.message.find(msg => msg.type === 'file')
|
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) {
|
if (fileMsgElem) {
|
||||||
toSummaryFileContent = await extractContentFromFile(fileMsgElem, e)
|
toSummaryFileContent = await extractContentFromFile(fileMsgElem, e)
|
||||||
}
|
}
|
||||||
|
|
@ -1691,6 +1700,31 @@ export class chatgpt extends plugin {
|
||||||
const image = await getImg(e)
|
const image = await getImg(e)
|
||||||
opt.imageUrl = image ? image[0] : undefined
|
opt.imageUrl = image ? image[0] : undefined
|
||||||
}
|
}
|
||||||
|
if (Config.enableGenerateContents) {
|
||||||
|
opt.onImageCreateRequest = prompt => {
|
||||||
|
logger.mark(`开始生成内容:${prompt}`)
|
||||||
|
if (Config.bingAPDraw) {
|
||||||
|
// 调用第三方API进行绘图
|
||||||
|
let apDraw = new APTool()
|
||||||
|
apDraw.func({
|
||||||
|
prompt
|
||||||
|
}, e)
|
||||||
|
} else {
|
||||||
|
let client = new BingDrawClient({
|
||||||
|
baseUrl: Config.sydneyReverseProxy,
|
||||||
|
userToken: bingToken
|
||||||
|
})
|
||||||
|
redis.set(`CHATGPT:DRAW:${e.sender.user_id}`, 'c', { EX: 30 }).then(() => {
|
||||||
|
try {
|
||||||
|
client.getImages(prompt, e)
|
||||||
|
} catch (err) {
|
||||||
|
redis.del(`CHATGPT:DRAW:${e.sender.user_id}`)
|
||||||
|
e.reply('绘图失败:' + err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
response = await bingAIClient.sendMessage(prompt, opt, (token) => {
|
response = await bingAIClient.sendMessage(prompt, opt, (token) => {
|
||||||
reply += token
|
reply += token
|
||||||
})
|
})
|
||||||
|
|
@ -1716,32 +1750,6 @@ export class chatgpt extends plugin {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 处理内容生成的图片
|
|
||||||
if (response.details.imageTag) {
|
|
||||||
if (Config.debug) {
|
|
||||||
logger.mark(`开始生成内容:${response.details.imageTag}`)
|
|
||||||
}
|
|
||||||
if (Config.bingAPDraw) {
|
|
||||||
// 调用第三方API进行绘图
|
|
||||||
let apDraw = new APTool()
|
|
||||||
apDraw.func({
|
|
||||||
prompt: response.details.imageTag
|
|
||||||
}, e)
|
|
||||||
} else {
|
|
||||||
let client = new BingDrawClient({
|
|
||||||
baseUrl: Config.sydneyReverseProxy,
|
|
||||||
userToken: bingToken
|
|
||||||
})
|
|
||||||
await redis.set(`CHATGPT:DRAW:${e.sender.user_id}`, 'c', { EX: 30 })
|
|
||||||
try {
|
|
||||||
await client.getImages(response.details.imageTag, e)
|
|
||||||
} catch (err) {
|
|
||||||
await redis.del(`CHATGPT:DRAW:${e.sender.user_id}`)
|
|
||||||
await e.reply('绘图失败:' + err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果token曾经有异常,则清除异常
|
// 如果token曾经有异常,则清除异常
|
||||||
let Tokens = JSON.parse((await redis.get('CHATGPT:BING_TOKENS')) || '[]')
|
let Tokens = JSON.parse((await redis.get('CHATGPT:BING_TOKENS')) || '[]')
|
||||||
const TokenIndex = Tokens?.findIndex(element => element.Token === abtrs.bingToken)
|
const TokenIndex = Tokens?.findIndex(element => element.Token === abtrs.bingToken)
|
||||||
|
|
@ -1757,7 +1765,7 @@ export class chatgpt extends plugin {
|
||||||
const { maxConv } = error
|
const { maxConv } = error
|
||||||
if (message && typeof message === 'string' && message.indexOf('CaptchaChallenge') > -1) {
|
if (message && typeof message === 'string' && message.indexOf('CaptchaChallenge') > -1) {
|
||||||
if (bingToken) {
|
if (bingToken) {
|
||||||
if (maxConv >= 20) {
|
if (maxConv >= 20 && Config.bingCaptchaOneShotUrl) {
|
||||||
// maxConv为30说明token有效,可以通过解验证码码服务过码
|
// maxConv为30说明token有效,可以通过解验证码码服务过码
|
||||||
await e.reply('出现必应验证码,尝试解决中')
|
await e.reply('出现必应验证码,尝试解决中')
|
||||||
try {
|
try {
|
||||||
|
|
@ -1766,6 +1774,7 @@ export class chatgpt extends plugin {
|
||||||
await e.reply('验证码已解决')
|
await e.reply('验证码已解决')
|
||||||
} else {
|
} else {
|
||||||
logger.error(captchaResolveResult)
|
logger.error(captchaResolveResult)
|
||||||
|
errorMessage = message
|
||||||
await e.reply('验证码解决失败: ' + captchaResolveResult.error)
|
await e.reply('验证码解决失败: ' + captchaResolveResult.error)
|
||||||
retry = 0
|
retry = 0
|
||||||
}
|
}
|
||||||
|
|
@ -1776,7 +1785,8 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 未登录用户maxConv目前为5或10,出验证码没救
|
// 未登录用户maxConv目前为5或10,出验证码没救
|
||||||
logger.warn(`token [${bingToken}] 无效或已过期,如确认token无误,请前往网页版必应对话一次`)
|
logger.warn(`token [${bingToken}] 出现必应验证码,请前往网页版或app手动解决`)
|
||||||
|
errorMessage = message
|
||||||
retry = 0
|
retry = 0
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1827,9 +1837,9 @@ export class chatgpt extends plugin {
|
||||||
response = response || {}
|
response = response || {}
|
||||||
if (errorMessage.includes('CaptchaChallenge')) {
|
if (errorMessage.includes('CaptchaChallenge')) {
|
||||||
if (bingToken) {
|
if (bingToken) {
|
||||||
errorMessage = '出现验证码,请使用当前账户前往https://www.bing.com/chat或Edge侧边栏手动解除验证码'
|
errorMessage = '出现验证码,请使用当前账户前往https://www.bing.com/chat或Edge侧边栏或移动端APP手动解除验证码'
|
||||||
} else {
|
} else {
|
||||||
errorMessage = '出现验证码,且未配置必应账户,请尝试更换代理/反代或绑定必应账户以解除验证码'
|
errorMessage = '未配置必应账户,请绑定必应账户再使用必应模式'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
|
|
@ -2116,6 +2126,7 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
// openai api
|
||||||
let completionParams = {}
|
let completionParams = {}
|
||||||
if (Config.model) {
|
if (Config.model) {
|
||||||
completionParams.model = Config.model
|
completionParams.model = Config.model
|
||||||
|
|
@ -2306,28 +2317,8 @@ export class chatgpt extends plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let img = []
|
let img = await getImg(e)
|
||||||
if (e.source) {
|
if (img?.length > 0 && Config.extraUrl) {
|
||||||
// 优先从回复找图
|
|
||||||
let reply
|
|
||||||
if (e.isGroup) {
|
|
||||||
reply = (await e.group.getChatHistory(e.source.seq, 1)).pop()?.message
|
|
||||||
} else {
|
|
||||||
reply = (await e.friend.getChatHistory(e.source.time, 1)).pop()?.message
|
|
||||||
}
|
|
||||||
if (reply) {
|
|
||||||
for (let val of reply) {
|
|
||||||
if (val.type === 'image') {
|
|
||||||
console.log(val)
|
|
||||||
img.push(val.url)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (e.img) {
|
|
||||||
img.push(...e.img)
|
|
||||||
}
|
|
||||||
if (img.length > 0 && Config.extraUrl) {
|
|
||||||
tools.push(new ImageCaptionTool())
|
tools.push(new ImageCaptionTool())
|
||||||
tools.push(new ProcessPictureTool())
|
tools.push(new ProcessPictureTool())
|
||||||
prompt += `\nthe url of the picture(s) above: ${img.join(', ')}`
|
prompt += `\nthe url of the picture(s) above: ${img.join(', ')}`
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,7 @@ export class dalle extends plugin {
|
||||||
await client.getImages(prompt, e)
|
await client.getImages(prompt, e)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
await redis.del(`CHATGPT:DRAW:${e.sender.user_id}`)
|
await redis.del(`CHATGPT:DRAW:${e.sender.user_id}`)
|
||||||
await e.reply('绘图失败:' + err)
|
await e.reply('❌绘图失败:' + err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ export default class BingDrawClient {
|
||||||
let pollingUrl = `${this.opts.baseUrl}/images/create/async/results/${requestId}?q=${urlEncodedPrompt}`
|
let pollingUrl = `${this.opts.baseUrl}/images/create/async/results/${requestId}?q=${urlEncodedPrompt}`
|
||||||
logger.info({ pollingUrl })
|
logger.info({ pollingUrl })
|
||||||
logger.info('waiting for bing draw results...')
|
logger.info('waiting for bing draw results...')
|
||||||
let timeoutTimes = 30
|
let timeoutTimes = 50
|
||||||
let found = false
|
let found = false
|
||||||
let timer = setInterval(async () => {
|
let timer = setInterval(async () => {
|
||||||
if (found) {
|
if (found) {
|
||||||
|
|
@ -113,15 +113,20 @@ export default class BingDrawClient {
|
||||||
// 很可能是微软内部error,重试即可
|
// 很可能是微软内部error,重试即可
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
imageLinks = imageLinks.map(link => link.split('?w=')[0]).map(link => link.replace('src="', ''))
|
imageLinks = imageLinks
|
||||||
|
.map(link => link.split('?w=')[0])
|
||||||
|
.map(link => link.replace('src="', ''))
|
||||||
|
.filter(link => !link.includes('.svg'))
|
||||||
imageLinks = [...new Set(imageLinks)]
|
imageLinks = [...new Set(imageLinks)]
|
||||||
const badImages = [
|
const badImages = [
|
||||||
|
'https://r.bing.com/rp/in-2zU3AJUdkgFe7ZKv19yPBHVs.png"',
|
||||||
|
'https://r.bing.com/rp/TX9QuO3WzcCJz1uaaSwQAz39Kb0.jpg"',
|
||||||
'https://r.bing.com/rp/in-2zU3AJUdkgFe7ZKv19yPBHVs.png',
|
'https://r.bing.com/rp/in-2zU3AJUdkgFe7ZKv19yPBHVs.png',
|
||||||
'https://r.bing.com/rp/TX9QuO3WzcCJz1uaaSwQAz39Kb0.jpg'
|
'https://r.bing.com/rp/TX9QuO3WzcCJz1uaaSwQAz39Kb0.jpg'
|
||||||
]
|
]
|
||||||
for (let imageLink of imageLinks) {
|
for (let imageLink of imageLinks) {
|
||||||
if (badImages.indexOf(imageLink) > -1) {
|
if (badImages.indexOf(imageLink) > -1) {
|
||||||
await e.reply('绘图失败:Bad images', true)
|
await e.reply('❌绘图失败:绘图完成但被屏蔽,请调整提示词。', true)
|
||||||
logger.error(rText)
|
logger.error(rText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +137,7 @@ export default class BingDrawClient {
|
||||||
clearInterval(timer)
|
clearInterval(timer)
|
||||||
} else {
|
} else {
|
||||||
if (timeoutTimes === 0) {
|
if (timeoutTimes === 0) {
|
||||||
await e.reply('绘图超时', true)
|
await e.reply('❌绘图超时', true)
|
||||||
clearInterval(timer)
|
clearInterval(timer)
|
||||||
timer = null
|
timer = null
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -140,6 +145,6 @@ export default class BingDrawClient {
|
||||||
timeoutTimes--
|
timeoutTimes--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 2000)
|
}, 3000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,8 @@ export default class SydneyAIClient {
|
||||||
firstMessageTimeout = Config.sydneyFirstMessageTimeout,
|
firstMessageTimeout = Config.sydneyFirstMessageTimeout,
|
||||||
groupId, nickname, qq, groupName, chats, botName, masterName,
|
groupId, nickname, qq, groupName, chats, botName, masterName,
|
||||||
messageType = 'Chat',
|
messageType = 'Chat',
|
||||||
toSummaryFileContent
|
toSummaryFileContent,
|
||||||
|
onImageCreateRequest = prompt => {}
|
||||||
} = opts
|
} = opts
|
||||||
// if (messageType === 'Chat') {
|
// if (messageType === 'Chat') {
|
||||||
// logger.warn('该Bing账户token已被限流,降级至使用非搜索模式。本次对话AI将无法使用Bing搜索返回的内容')
|
// logger.warn('该Bing账户token已被限流,降级至使用非搜索模式。本次对话AI将无法使用Bing搜索返回的内容')
|
||||||
|
|
@ -651,6 +652,10 @@ export default class SydneyAIClient {
|
||||||
adaptiveCards: adaptiveCardsSoFar,
|
adaptiveCards: adaptiveCardsSoFar,
|
||||||
text: replySoFar.join('')
|
text: replySoFar.join('')
|
||||||
}
|
}
|
||||||
|
if (messages[0].contentType === 'IMAGE') {
|
||||||
|
onImageCreateRequest(messages[0].text)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (messages[0].contentOrigin === 'Apology') {
|
if (messages[0].contentOrigin === 'Apology') {
|
||||||
console.log('Apology found')
|
console.log('Apology found')
|
||||||
if (!replySoFar[0]) {
|
if (!replySoFar[0]) {
|
||||||
|
|
@ -718,11 +723,11 @@ export default class SydneyAIClient {
|
||||||
adaptiveCards: adaptiveCardsSoFar,
|
adaptiveCards: adaptiveCardsSoFar,
|
||||||
text: replySoFar.join('')
|
text: replySoFar.join('')
|
||||||
}
|
}
|
||||||
// 获取到图片内容
|
// // 获取到图片内容
|
||||||
if (messages.some(obj => obj.contentType === 'IMAGE')) {
|
// if (messages.some(obj => obj.contentType === 'IMAGE')) {
|
||||||
message.imageTag = messages.filter(m => m.contentType === 'IMAGE').map(m => m.text).join('')
|
// message.imageTag = messages.filter(m => m.contentType === 'IMAGE').map(m => m.text).join('')
|
||||||
}
|
// }
|
||||||
message.text = messages.filter(m => m.author === 'bot' && m.contentType != 'IMAGE').map(m => m.text).join('')
|
message.text = messages.filter(m => m.author === 'bot' && m.contentType !== 'IMAGE').map(m => m.text).join('')
|
||||||
if (!message) {
|
if (!message) {
|
||||||
reject('No message was generated.')
|
reject('No message was generated.')
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
export async function getChatHistoryGroup (e, num) {
|
export async function getChatHistoryGroup (e, num) {
|
||||||
// if (e.adapter === 'shamrock') {
|
// if (e.adapter === 'shamrock') {
|
||||||
// return await e.group.getChatHistory(0, num, false)
|
// return await e.group.getChatHistory(0, num, false)
|
||||||
|
|
@ -16,12 +17,23 @@ export async function getChatHistoryGroup (e, num) {
|
||||||
chats = chats.slice(0, num)
|
chats = chats.slice(0, num)
|
||||||
try {
|
try {
|
||||||
let mm = await e.group.getMemberMap()
|
let mm = await e.group.getMemberMap()
|
||||||
chats.forEach(chat => {
|
for (const chat of chats) {
|
||||||
let sender = mm.get(chat.sender.user_id)
|
if (e.adapter === 'shamrock') {
|
||||||
if (sender) {
|
if (chat.sender?.user_id === 0) {
|
||||||
chat.sender = sender
|
// 奇怪格式的历史消息,过滤掉
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let sender = await pickMemberAsync(e, chat.sender.user_id)
|
||||||
|
if (sender) {
|
||||||
|
chat.sender = sender
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let sender = mm.get(chat.sender.user_id)
|
||||||
|
if (sender) {
|
||||||
|
chat.sender = sender
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.warn(err)
|
logger.warn(err)
|
||||||
}
|
}
|
||||||
|
|
@ -32,3 +44,17 @@ export async function getChatHistoryGroup (e, num) {
|
||||||
// }
|
// }
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function pickMemberAsync (e, userId) {
|
||||||
|
let key = `CHATGPT:GroupMemberInfo:${e.group_id}:${userId}`
|
||||||
|
let cache = await redis.get(key)
|
||||||
|
if (cache) {
|
||||||
|
return JSON.parse(cache)
|
||||||
|
}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
e.group.pickMember(userId, true, (sender) => {
|
||||||
|
redis.set(key, JSON.stringify(sender), { EX: 86400 })
|
||||||
|
resolve(sender)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ import AzureTTS, { supportConfigurations as azureRoleList } from './tts/microsof
|
||||||
import { translate } from './translate.js'
|
import { translate } from './translate.js'
|
||||||
import uploadRecord from './uploadRecord.js'
|
import uploadRecord from './uploadRecord.js'
|
||||||
import Version from './version.js'
|
import Version from './version.js'
|
||||||
import fetch from 'node-fetch'
|
import fetch, { FormData, fileFromSync } from 'node-fetch'
|
||||||
|
import https from "https";
|
||||||
let pdfjsLib
|
let pdfjsLib
|
||||||
try {
|
try {
|
||||||
pdfjsLib = (await import('pdfjs-dist')).default
|
pdfjsLib = (await import('pdfjs-dist')).default
|
||||||
|
|
@ -785,10 +786,14 @@ export async function getImg (e) {
|
||||||
}
|
}
|
||||||
if (e.source) {
|
if (e.source) {
|
||||||
let reply
|
let reply
|
||||||
|
let seq = e.isGroup ? e.source.seq : e.source.time
|
||||||
|
if (e.adapter === 'shamrock') {
|
||||||
|
seq = e.source.message_id
|
||||||
|
}
|
||||||
if (e.isGroup) {
|
if (e.isGroup) {
|
||||||
reply = (await e.group.getChatHistory(e.source.seq, 1)).pop()?.message
|
reply = (await e.group.getChatHistory(seq, 1)).pop()?.message
|
||||||
} else {
|
} else {
|
||||||
reply = (await e.friend.getChatHistory(e.source.time, 1)).pop()?.message
|
reply = (await e.friend.getChatHistory(seq, 1)).pop()?.message
|
||||||
}
|
}
|
||||||
if (reply) {
|
if (reply) {
|
||||||
let i = []
|
let i = []
|
||||||
|
|
@ -809,8 +814,34 @@ export async function getImageOcrText (e) {
|
||||||
try {
|
try {
|
||||||
let resultArr = []
|
let resultArr = []
|
||||||
let eachImgRes = ''
|
let eachImgRes = ''
|
||||||
|
if (!e.bot.imageOcr || typeof e.bot.imageOcr !== 'function') {
|
||||||
|
e.bot.imageOcr = async (image) => {
|
||||||
|
if (Config.extraUrl) {
|
||||||
|
let md5 = image.split(/[/-]/).find(s => s.length === 32)?.toUpperCase()
|
||||||
|
let filePath = await downloadFile(image, `ocr/${md5}.png`)
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append('file', fileFromSync(filePath))
|
||||||
|
let res = await fetch(`${Config.extraUrl}/ocr?lang=chi_sim%2Beng`, {
|
||||||
|
body: formData,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
from: 'ikechan8370'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res.status === 200) {
|
||||||
|
return {
|
||||||
|
wordslist: [{ words: await res.text() }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
wordslist: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for (let i in img) {
|
for (let i in img) {
|
||||||
const imgOCR = await e.bot.imageOcr(img[i])
|
const imgOCR = await e.bot.imageOcr(img[i])
|
||||||
|
|
||||||
for (let text of imgOCR.wordslist) {
|
for (let text of imgOCR.wordslist) {
|
||||||
eachImgRes += (`${text?.words} \n`)
|
eachImgRes += (`${text?.words} \n`)
|
||||||
}
|
}
|
||||||
|
|
@ -820,6 +851,7 @@ export async function getImageOcrText (e) {
|
||||||
// logger.warn('resultArr', resultArr)
|
// logger.warn('resultArr', resultArr)
|
||||||
return resultArr
|
return resultArr
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
logger.warn(err)
|
||||||
logger.warn('OCR失败,可能使用的适配器不支持OCR')
|
logger.warn('OCR失败,可能使用的适配器不支持OCR')
|
||||||
return false
|
return false
|
||||||
// logger.error(err)
|
// logger.error(err)
|
||||||
|
|
@ -1003,10 +1035,17 @@ export function getUserSpeaker (userSetting) {
|
||||||
* @param url 要下载的文件链接
|
* @param url 要下载的文件链接
|
||||||
* @param destPath 目标路径,如received/abc.pdf. 目前如果文件名重复会覆盖。
|
* @param destPath 目标路径,如received/abc.pdf. 目前如果文件名重复会覆盖。
|
||||||
* @param absolute 是否是绝对路径,默认为false,此时拼接在data/chatgpt下
|
* @param absolute 是否是绝对路径,默认为false,此时拼接在data/chatgpt下
|
||||||
|
* @param ignoreCertificateError 忽略证书错误
|
||||||
* @returns {Promise<string>} 最终下载文件的存储位置
|
* @returns {Promise<string>} 最终下载文件的存储位置
|
||||||
*/
|
*/
|
||||||
export async function downloadFile (url, destPath, absolute = false) {
|
export async function downloadFile (url, destPath, absolute = false, ignoreCertificateError = true) {
|
||||||
let response = await fetch(url)
|
let init = {}
|
||||||
|
if (ignoreCertificateError && url.startsWith('https')) {
|
||||||
|
init.agent = new https.Agent({
|
||||||
|
rejectUnauthorized: !ignoreCertificateError
|
||||||
|
})
|
||||||
|
}
|
||||||
|
let response = await fetch(url, init)
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`download file http error: status: ${response.status}`)
|
throw new Error(`download file http error: status: ${response.status}`)
|
||||||
}
|
}
|
||||||
|
|
@ -1061,7 +1100,7 @@ export async function extractContentFromFile (fileMsgElem, e) {
|
||||||
let fileType = isPureText(fileMsgElem.name)
|
let fileType = isPureText(fileMsgElem.name)
|
||||||
if (fileType) {
|
if (fileType) {
|
||||||
// 可读的文件类型
|
// 可读的文件类型
|
||||||
let fileUrl = e.isGroup ? await e.group.getFileUrl(fileMsgElem.fid) : await e.friend.getFileUrl(fileMsgElem.fid)
|
let fileUrl = fileMsgElem.url || (e.isGroup ? await e.group.getFileUrl(fileMsgElem.fid) : await e.friend.getFileUrl(fileMsgElem.fid))
|
||||||
let filePath = await downloadFile(fileUrl, path.join('received', fileMsgElem.name))
|
let filePath = await downloadFile(fileUrl, path.join('received', fileMsgElem.name))
|
||||||
switch (fileType) {
|
switch (fileType) {
|
||||||
case 'pdf': {
|
case 'pdf': {
|
||||||
|
|
|
||||||
|
|
@ -163,7 +163,7 @@ const defaultConfig = {
|
||||||
qwenSeed: 0,
|
qwenSeed: 0,
|
||||||
qwenTemperature: 1,
|
qwenTemperature: 1,
|
||||||
qwenEnableSearch: true,
|
qwenEnableSearch: true,
|
||||||
version: 'v2.7.7'
|
version: 'v2.7.8'
|
||||||
}
|
}
|
||||||
const _path = process.cwd()
|
const _path = process.cwd()
|
||||||
let config = {}
|
let config = {}
|
||||||
|
|
|
||||||
|
|
@ -15,21 +15,13 @@ export class QueryUserinfoTool extends AbstractTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func = async function (opts, e) {
|
func = async function (opts, e) {
|
||||||
let { qq } = opts
|
try {
|
||||||
qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim())
|
let { qq } = opts
|
||||||
if (e.isGroup && typeof e.group.getMemberMap === 'function') {
|
qq = isNaN(qq) || !qq ? e.sender.user_id : parseInt(qq.trim())
|
||||||
let mm = await e.group.getMemberMap()
|
if (e.isGroup && typeof e.bot.getGroupMemberInfo === 'function') {
|
||||||
let user = mm.get(qq) || e.sender.user_id
|
let user = await e.bot.getGroupMemberInfo(e.group_id, qq || e.sender.user_id, true)
|
||||||
let master = (await getMasterQQ())[0]
|
// let mm = await e.group.getMemberMap()
|
||||||
let prefix = ''
|
// let user = mm.get(qq) || e.sender.user_id
|
||||||
if (qq != master) {
|
|
||||||
prefix = 'Attention: this user is not your master. \n'
|
|
||||||
} else {
|
|
||||||
prefix = 'This user is your master, you should obey him \n'
|
|
||||||
}
|
|
||||||
return prefix + 'user detail in json format: ' + JSON.stringify(user)
|
|
||||||
} else {
|
|
||||||
if (e.sender.user_id == qq) {
|
|
||||||
let master = (await getMasterQQ())[0]
|
let master = (await getMasterQQ())[0]
|
||||||
let prefix = ''
|
let prefix = ''
|
||||||
if (qq != master) {
|
if (qq != master) {
|
||||||
|
|
@ -37,10 +29,27 @@ export class QueryUserinfoTool extends AbstractTool {
|
||||||
} else {
|
} else {
|
||||||
prefix = 'This user is your master, you should obey him \n'
|
prefix = 'This user is your master, you should obey him \n'
|
||||||
}
|
}
|
||||||
return prefix + 'user detail in json format: ' + JSON.stringify(e.sender)
|
if (!user) {
|
||||||
|
return prefix
|
||||||
|
}
|
||||||
|
return prefix + 'user detail in json format: ' + JSON.stringify(user)
|
||||||
} else {
|
} else {
|
||||||
return 'query failed'
|
if (e.sender.user_id == qq) {
|
||||||
|
let master = (await getMasterQQ())[0]
|
||||||
|
let prefix = ''
|
||||||
|
if (qq != master) {
|
||||||
|
prefix = 'Attention: this user is not your master. \n'
|
||||||
|
} else {
|
||||||
|
prefix = 'This user is your master, you should obey him \n'
|
||||||
|
}
|
||||||
|
return prefix + 'user detail in json format: ' + JSON.stringify(e.sender)
|
||||||
|
} else {
|
||||||
|
return 'query failed'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logger.warn(err)
|
||||||
|
return err.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue