mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-17 13:57:10 +00:00
Merge branch 'v2' into v2
This commit is contained in:
commit
be91e25415
26 changed files with 1029 additions and 632 deletions
211
apps/chat.js
211
apps/chat.js
|
|
@ -7,11 +7,10 @@ import { ChatGPTAPI } from 'chatgpt'
|
|||
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 AzureTTS, { supportConfigurations } from '../utils/tts/microsoft-azure.js'
|
||||
import VoiceVoxTTS from '../utils/tts/voicevox.js'
|
||||
import { translate } from '../utils/translate.js'
|
||||
import fs from 'fs'
|
||||
import { getImg, getImageOcrText } from './entertainment.js'
|
||||
import {
|
||||
render, renderUrl,
|
||||
getMessageById,
|
||||
|
|
@ -21,7 +20,7 @@ import {
|
|||
completeJSON,
|
||||
isImage,
|
||||
getUserData,
|
||||
getDefaultReplySetting, isCN, getMasterQQ
|
||||
getDefaultReplySetting, isCN, getMasterQQ, getUserReplySetting, getImageOcrText, getImg, processList
|
||||
} from '../utils/common.js'
|
||||
import { ChatGPTPuppeteer } from '../utils/browser.js'
|
||||
import { KeyvFile } from 'keyv-file'
|
||||
|
|
@ -544,12 +543,7 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
|
||||
async switch2Text (e) {
|
||||
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||
if (!userSetting) {
|
||||
userSetting = getDefaultReplySetting()
|
||||
} else {
|
||||
userSetting = JSON.parse(userSetting)
|
||||
}
|
||||
let userSetting = await getUserReplySetting(this.e)
|
||||
userSetting.usePicture = false
|
||||
userSetting.useTTS = false
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
|
|
@ -577,12 +571,7 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
break
|
||||
}
|
||||
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||
if (!userSetting) {
|
||||
userSetting = getDefaultReplySetting()
|
||||
} else {
|
||||
userSetting = JSON.parse(userSetting)
|
||||
}
|
||||
let userSetting = await getUserReplySetting(this.e)
|
||||
userSetting.useTTS = true
|
||||
userSetting.usePicture = false
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
|
|
@ -629,37 +618,35 @@ export class chatgpt extends plugin {
|
|||
let speaker = e.msg.replace(regex, '').trim() || '随机'
|
||||
switch (Config.ttsMode) {
|
||||
case 'vits-uma-genshin-honkai': {
|
||||
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||
if (!userSetting) {
|
||||
userSetting = getDefaultReplySetting()
|
||||
} else {
|
||||
userSetting = JSON.parse(userSetting)
|
||||
}
|
||||
let userSetting = await getUserReplySetting(this.e)
|
||||
userSetting.ttsRole = convertSpeaker(speaker)
|
||||
if (speakers.indexOf(userSetting.ttsRole) >= 0) {
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
await this.reply(`您的默认语音角色已被设置为”${userSetting.ttsRole}“`)
|
||||
await this.reply(`当前语音模式为${Config.ttsMode},您的默认语音角色已被设置为 "${userSetting.ttsRole}" `)
|
||||
} else if (speaker === '随机') {
|
||||
userSetting.ttsRole = '随机'
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
await this.reply(`当前语音模式为${Config.ttsMode},您的默认语音角色已被设置为 "随机" `)
|
||||
} else {
|
||||
await this.reply(`抱歉,"${userSetting.ttsRole}"我还不认识呢`)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'azure': {
|
||||
let userSetting = await getUserReplySetting(this.e)
|
||||
let chosen = AzureTTS.supportConfigurations.filter(s => s.name === speaker)
|
||||
if (chosen.length === 0) {
|
||||
if (speaker === '随机') {
|
||||
userSetting.ttsRoleAzure = '随机'
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
await this.reply(`当前语音模式为${Config.ttsMode},您的默认语音角色已被设置为 "随机" `)
|
||||
} else if (chosen.length === 0) {
|
||||
await this.reply(`抱歉,没有"${speaker}"这个角色,目前azure模式下支持的角色有${AzureTTS.supportConfigurations.map(item => item.name).join('、')}`)
|
||||
} else {
|
||||
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||
if (!userSetting) {
|
||||
userSetting = getDefaultReplySetting()
|
||||
} else {
|
||||
userSetting = JSON.parse(userSetting)
|
||||
}
|
||||
userSetting.ttsRoleAzure = chosen[0].code
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
// Config.azureTTSSpeaker = chosen[0].code
|
||||
const supportEmotion = AzureTTS.supportConfigurations.find(config => config.name === speaker)?.emotion
|
||||
await this.reply(`您的默认语音角色已被设置为 ${speaker}-${chosen[0].gender}-${chosen[0].languageDetail} ${supportEmotion && Config.azureTTSEmotion ? ',此角色支持多情绪配置,建议重新使用设定并结束对话以获得最佳体验!' : ''}`)
|
||||
await this.reply(`当前语音模式为${Config.ttsMode},您的默认语音角色已被设置为 ${speaker}-${chosen[0].gender}-${chosen[0].languageDetail} ${supportEmotion && Config.azureTTSEmotion ? ',此角色支持多情绪配置,建议重新使用设定并结束对话以获得最佳体验!' : ''}`)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
@ -671,6 +658,13 @@ export class chatgpt extends plugin {
|
|||
speaker = match[1]
|
||||
style = match[2]
|
||||
}
|
||||
let userSetting = await getUserReplySetting(e)
|
||||
if (speaker === '随机') {
|
||||
userSetting.ttsRoleVoiceVox = '随机'
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
await this.reply(`当前语音模式为${Config.ttsMode},您的默认语音角色已被设置为 "随机" `)
|
||||
break
|
||||
}
|
||||
let chosen = VoiceVoxTTS.supportConfigurations.filter(s => s.name === speaker)
|
||||
if (chosen.length === 0) {
|
||||
await this.reply(`抱歉,没有"${speaker}"这个角色,目前voicevox模式下支持的角色有${VoiceVoxTTS.supportConfigurations.map(item => item.name).join('、')}`)
|
||||
|
|
@ -680,15 +674,9 @@ export class chatgpt extends plugin {
|
|||
await this.reply(`抱歉,"${speaker}"这个角色没有"${style}"这个风格,目前支持的风格有${chosen[0].styles.map(item => item.name).join('、')}`)
|
||||
break
|
||||
}
|
||||
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||
if (!userSetting) {
|
||||
userSetting = getDefaultReplySetting()
|
||||
} else {
|
||||
userSetting = JSON.parse(userSetting)
|
||||
}
|
||||
userSetting.ttsRoleVoiceVox = chosen[0].name + (style ? `-${style}` : '')
|
||||
await redis.set(`CHATGPT:USER:${e.sender.user_id}`, JSON.stringify(userSetting))
|
||||
await this.reply(`您的默认语音角色已被设置为”${userSetting.ttsRoleVoiceVox}“`)
|
||||
await this.reply(`当前语音模式为${Config.ttsMode},您的默认语音角色已被设置为 "${userSetting.ttsRoleVoiceVox}" `)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -698,23 +686,6 @@ export class chatgpt extends plugin {
|
|||
* #chatgpt
|
||||
*/
|
||||
async chatgpt (e) {
|
||||
if (!e.isMaster && e.isPrivate && !Config.enablePrivateChat) {
|
||||
// await this.reply('ChatGpt私聊通道已关闭。')
|
||||
return false
|
||||
}
|
||||
if (e.isGroup) {
|
||||
let cm = new ChatgptManagement()
|
||||
let [groupWhitelist, groupBlacklist] = await cm.processList(Config.groupWhitelist, Config.groupBlacklist)
|
||||
// logger.info('groupWhitelist:', Config.groupWhitelist, 'groupBlacklist', Config.groupBlacklist)
|
||||
const whitelist = groupWhitelist.filter(group => group.trim())
|
||||
if (whitelist.length > 0 && !whitelist.includes(e.group_id.toString())) {
|
||||
return false
|
||||
}
|
||||
const blacklist = groupBlacklist.filter(group => group.trim())
|
||||
if (blacklist.length > 0 && blacklist.includes(e.group_id.toString())) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
let prompt
|
||||
if (this.toggleMode === 'at') {
|
||||
if (!e.raw_message || e.msg?.startsWith('#')) {
|
||||
|
|
@ -781,15 +752,24 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
|
||||
async abstractChat (e, prompt, use) {
|
||||
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||
if (userSetting) {
|
||||
userSetting = JSON.parse(userSetting)
|
||||
if (Object.keys(userSetting).indexOf('useTTS') < 0) {
|
||||
userSetting.useTTS = Config.defaultUseTTS
|
||||
}
|
||||
} else {
|
||||
userSetting = getDefaultReplySetting()
|
||||
// 关闭私聊通道后不回复
|
||||
if (!e.isMaster && e.isPrivate && !Config.enablePrivateChat) {
|
||||
return false
|
||||
}
|
||||
// 黑白名单过滤对话
|
||||
let [whitelist, blacklist] = processList(Config.whitelist, Config.blacklist)
|
||||
if (whitelist.length > 0) {
|
||||
if (e.isGroup && !whitelist.includes(e.group_id.toString())) return false
|
||||
const list = whitelist.filter(elem => elem.startsWith('^')).map(elem => elem.slice(1))
|
||||
if (!list.includes(e.sender.user_id.toString())) return false
|
||||
}
|
||||
if (blacklist.length > 0) {
|
||||
if (e.isGroup && blacklist.includes(e.group_id.toString())) return false
|
||||
const list = blacklist.filter(elem => elem.startsWith('^')).map(elem => elem.slice(1))
|
||||
if (list.includes(e.sender.user_id.toString())) return false
|
||||
}
|
||||
|
||||
let userSetting = await getUserReplySetting(this.e)
|
||||
let useTTS = !!userSetting.useTTS
|
||||
let speaker
|
||||
if (Config.ttsMode === 'vits-uma-genshin-honkai') {
|
||||
|
|
@ -869,10 +849,7 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
}
|
||||
const emotionFlag = await redis.get(`CHATGPT:WRONG_EMOTION:${e.sender.user_id}`)
|
||||
let userReplySetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
|
||||
userReplySetting = !userReplySetting
|
||||
? getDefaultReplySetting()
|
||||
: JSON.parse(userReplySetting)
|
||||
let userReplySetting = await getUserReplySetting(this.e)
|
||||
// 图片模式就不管了,降低抱歉概率
|
||||
if (Config.ttsMode === 'azure' && Config.enhanceAzureTTSEmotion && userReplySetting.useTTS === true && await AzureTTS.getEmotionPrompt(e)) {
|
||||
switch (emotionFlag) {
|
||||
|
|
@ -1163,10 +1140,23 @@ export class chatgpt extends plugin {
|
|||
await this.reply('合成语音发生错误~')
|
||||
}
|
||||
} else if (Config.ttsMode === 'azure' && Config.azureTTSKey) {
|
||||
const ttsRoleAzure = userReplySetting.ttsRoleAzure
|
||||
const isEn = AzureTTS.supportConfigurations.find(config => config.code === ttsRoleAzure)?.language.includes('en')
|
||||
if (isEn) {
|
||||
ttsResponse = (await translate(ttsResponse, '英')).replace('\n', '')
|
||||
if (speaker !== '随机') {
|
||||
let languagePrefix = AzureTTS.supportConfigurations.find(config => config.code === speaker).languageDetail.charAt(0)
|
||||
languagePrefix = languagePrefix.startsWith('E') ? '英' : languagePrefix
|
||||
ttsResponse = (await translate(ttsResponse, languagePrefix)).replace('\n', '')
|
||||
} else {
|
||||
let role, languagePrefix
|
||||
role = AzureTTS.supportConfigurations[Math.floor(Math.random() * supportConfigurations.length)]
|
||||
speaker = role.code
|
||||
languagePrefix = role.languageDetail.charAt(0).startsWith('E') ? '英' : role.languageDetail.charAt(0)
|
||||
ttsResponse = (await translate(ttsResponse, languagePrefix)).replace('\n', '')
|
||||
if (role?.emotion) {
|
||||
const keys = Object.keys(role.emotion)
|
||||
emotion = keys[Math.floor(Math.random() * keys.length)]
|
||||
}
|
||||
logger.info('using speaker: ' + speaker)
|
||||
logger.info('using language: ' + languagePrefix)
|
||||
logger.info('using emotion: ' + emotion)
|
||||
}
|
||||
let ssml = AzureTTS.generateSsml(ttsResponse, {
|
||||
speaker,
|
||||
|
|
@ -1177,6 +1167,7 @@ export class chatgpt extends plugin {
|
|||
speaker
|
||||
}, await ssml)
|
||||
} else if (Config.ttsMode === 'voicevox' && Config.voicevoxSpace) {
|
||||
ttsResponse = (await translate(ttsResponse, '日')).replace('\n', '')
|
||||
wav = await VoiceVoxTTS.generateAudio(ttsResponse, {
|
||||
speaker
|
||||
})
|
||||
|
|
@ -1256,10 +1247,6 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
|
||||
async chatgpt1 (e) {
|
||||
if (!e.isMaster && e.isPrivate && !Config.enablePrivateChat) {
|
||||
await this.reply('ChatGpt私聊通道已关闭。')
|
||||
return false
|
||||
}
|
||||
if (!Config.allowOtherMode) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1279,10 +1266,6 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
|
||||
async chatgpt3 (e) {
|
||||
if (!e.isMaster && e.isPrivate && !Config.enablePrivateChat) {
|
||||
await this.reply('ChatGpt私聊通道已关闭。')
|
||||
return false
|
||||
}
|
||||
if (!Config.allowOtherMode) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1321,10 +1304,6 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
|
||||
async bing (e) {
|
||||
if (!e.isMaster && e.isPrivate && !Config.enablePrivateChat) {
|
||||
await this.reply('ChatGpt私聊通道已关闭。')
|
||||
return false
|
||||
}
|
||||
if (!Config.allowOtherMode) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1344,10 +1323,6 @@ export class chatgpt extends plugin {
|
|||
}
|
||||
|
||||
async claude (e) {
|
||||
if (!e.isMaster && e.isPrivate && !Config.enablePrivateChat) {
|
||||
// await this.reply('ChatGpt私聊通道已关闭。')
|
||||
return false
|
||||
}
|
||||
if (!Config.allowOtherMode) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1365,11 +1340,8 @@ export class chatgpt extends plugin {
|
|||
await this.abstractChat(e, prompt, 'claude')
|
||||
return true
|
||||
}
|
||||
|
||||
async xh (e) {
|
||||
if (!e.isMaster && e.isPrivate && !Config.enablePrivateChat) {
|
||||
// await this.reply('ChatGpt私聊通道已关闭。')
|
||||
return false
|
||||
}
|
||||
if (!Config.allowOtherMode) {
|
||||
return false
|
||||
}
|
||||
|
|
@ -1650,7 +1622,7 @@ export class chatgpt extends plugin {
|
|||
// 如果token曾经有异常,则清除异常
|
||||
let Tokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
|
||||
const TokenIndex = Tokens.findIndex(element => element.Token === abtrs.bingToken)
|
||||
if (Tokens[TokenIndex].exception) {
|
||||
if (TokenIndex > 0 && Tokens[TokenIndex].exception) {
|
||||
delete Tokens[TokenIndex].exception
|
||||
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(Tokens))
|
||||
}
|
||||
|
|
@ -1672,21 +1644,22 @@ export class chatgpt extends plugin {
|
|||
// 不减次数
|
||||
} 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 (bingTokens[badBingToken].exception) {
|
||||
if (bingTokens[badBingToken].exception <= 3) {
|
||||
bingTokens[badBingToken].exception += 1
|
||||
} else {
|
||||
bingTokens[badBingToken].exception = 0
|
||||
bingTokens[badBingToken].State = '过期'
|
||||
}
|
||||
} else {
|
||||
bingTokens[badBingToken].exception = 1
|
||||
}
|
||||
await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
|
||||
logger.warn(`token${bingToken}已过期`)
|
||||
// let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS'))
|
||||
// const badBingToken = bingTokens.findIndex(element => element.Token === bingToken)
|
||||
// // 可能是微软抽风,给三次机会
|
||||
// if (bingTokens[badBingToken].exception) {
|
||||
// if (bingTokens[badBingToken].exception <= 3) {
|
||||
// bingTokens[badBingToken].exception += 1
|
||||
// } else {
|
||||
// bingTokens[badBingToken].exception = 0
|
||||
// bingTokens[badBingToken].State = '过期'
|
||||
// }
|
||||
// } else {
|
||||
// bingTokens[badBingToken].exception = 1
|
||||
// }
|
||||
// await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens))
|
||||
logger.warn(`token${bingToken}疑似不存在或已过期,再试试`)
|
||||
retry = retry - 0.1
|
||||
} else {
|
||||
retry--
|
||||
errorMessage = message === 'Timed out waiting for response. Try enabling debug mode to see more information.' ? (reply ? `${reply}\n不行了,我的大脑过载了,处理不过来了!` : '必应的小脑瓜不好使了,不知道怎么回答!') : message
|
||||
|
|
@ -1778,9 +1751,11 @@ export class chatgpt extends plugin {
|
|||
if (Config.slackClaudeEnableGlobalPreset && (useCast?.slack || Config.slackClaudeGlobalPreset)) {
|
||||
// 先发送设定
|
||||
let prompt = (useCast?.slack || Config.slackClaudeGlobalPreset)
|
||||
let emotion = await AzureTTS.getEmotionPrompt(e)
|
||||
if (emotion) {
|
||||
prompt = prompt + '\n' + emotion
|
||||
}
|
||||
await client.sendMessage(prompt, e)
|
||||
// 处理可能由情绪参数导致的设定超限问题
|
||||
await client.sendMessage(await AzureTTS.getEmotionPrompt(e), e)
|
||||
logger.info('claudeFirst:', prompt)
|
||||
}
|
||||
}
|
||||
|
|
@ -1829,10 +1804,10 @@ export class chatgpt extends plugin {
|
|||
timeoutMs: 120000
|
||||
// systemMessage: promptPrefix
|
||||
}
|
||||
if (Math.floor(Math.random() * 100) < 5) {
|
||||
// 小概率再次发送系统消息
|
||||
option.systemMessage = promptPrefix
|
||||
}
|
||||
// if (Math.floor(Math.random() * 100) < 5) {
|
||||
// // 小概率再次发送系统消息
|
||||
// option.systemMessage = promptPrefix
|
||||
// }
|
||||
if (conversation) {
|
||||
option = Object.assign(option, conversation)
|
||||
}
|
||||
|
|
@ -2098,7 +2073,11 @@ export class chatgpt extends plugin {
|
|||
async function getAvailableBingToken (conversation, throttled = []) {
|
||||
let allThrottled = false
|
||||
if (!await redis.get('CHATGPT:BING_TOKENS')) {
|
||||
throw new Error('未绑定Bing Cookie,请使用#chatgpt设置必应token命令绑定Bing Cookie')
|
||||
return {
|
||||
bingToken: null,
|
||||
allThrottled
|
||||
}
|
||||
// throw new Error('未绑定Bing Cookie,请使用#chatgpt设置必应token命令绑定Bing Cookie')
|
||||
}
|
||||
|
||||
let bingToken = ''
|
||||
|
|
@ -2128,7 +2107,11 @@ async function getAvailableBingToken (conversation, throttled = []) {
|
|||
})
|
||||
bingToken = minElement.Token
|
||||
} else {
|
||||
throw new Error('全部Token均已失效,暂时无法使用')
|
||||
// throw new Error('全部Token均已失效,暂时无法使用')
|
||||
return {
|
||||
bingToken: null,
|
||||
allThrottled
|
||||
}
|
||||
}
|
||||
if (Config.toneStyle != 'Sydney' && Config.toneStyle != 'Custom') {
|
||||
// bing 下,需要保证同一对话使用同一账号的token
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue