mirror of
https://github.com/ikechan8370/chatgpt-plugin.git
synced 2025-12-16 13:27:08 +00:00
feat: 黑白名单支持配置qq号;支持所有语音模式下的随机角色对话;新增查看当前用户的回复设置;完善全局设置的相关功能;支持为Azure语音服务随机选择角色;优化设置全局语音角色和查看角色列表的功能;重构了代码以支持现有语音服务的打招呼功能;修复了Guoba面板上Azure语音角色选择的显示问题。 (#436)
* feat: add support for ‘greeting’ and ‘global reply mode’ commands, improve variable naming and remove unnecessary backend output. * feat: Add support for black and white lists, global reply mode and voice role settings, private chat switch, and active greeting configuration. Refactor some variable names and comment out redundant code for better readability and reduced backend output. * feat: 为新功能完善了帮助面板 * docs: 完善了‘打招呼’的帮助说明 * Commit Type: feat, bugfix Add functionality to view plugin command table, fix bug in blacklist/whitelist, and fix bug where chat mode can still be used in private messaging when disabled. * Commit Type: feat, bugfix Add functionality to view plugin command table, fix bug in blacklist/whitelist, and fix bug where chat mode can still be used in private messaging when disabled. * refactor: Remove redundant log output. * Refactor: optimize code logic * Fix: 修复绘图指令表被抢指令的bug。 * Refactor:1. Add support for automatically translating replies to Japanese and generating voice messages in VITS voice mode (please monitor remaining quota after enabling). 2. Add translation function. 3. Add emotion configuration for Azure voice mode, allowing the robot to select appropriate emotional styles for replies. * Refactor:Handle the issue of exceeding character setting limit caused by adding emotion configuration. * Fix: fix bugs * Refactor: Added error feedback to translation service * Refactor: Added support for viewing the list of supported roles for each language mode, and fixed some bugs in the emotion switching feature of the auzre mode. * Refactor: Optimized some command feedback and added owner restriction to chat record export function. * Refactor: Optimized feedback when viewing role list to avoid excessive messages. * Refactor: Optimized feedback when configuring multi-emotion mode. * Feature: Added help instructions for translation feature. * chore: Adjust help instructions for mood settings * Fix: Fixed issue where only first line of multi-line replies were being read and Azure voice was pronouncing punctuation marks. * Fix: Fixed bug where switching to Azure voice mode prompted for missing key and restricted ability to view voice role list to only when in voice mode. * Refactor: Add image OCR function and support translation for both quoted text and image. * fix: Fix issue with error caused by non-image input. * Refactor: Optimize code to filter emojis that cannot be displayed properly in claude mode. * Refactor: Optimize some code structures. * fix: Fix the bug of returning only one result when entering multiple lines of text on Windows system. * Refactor: Optimize code logic for better user experience * Refactor: Fix the conflict issue with other plugin translation commands * Refactor: Replace Baidu Translation with Youdao Translation to eliminate configuration steps; optimize translation experience; add missing dependency prompts instead of causing program errors.Optimize the experience of switching between voice mode and setting global reply mode. * Refactor: Remove unused files and dependencies in the project. * Feature: Add Youdao translation service to provide more comprehensive translation support. * Refactor: Optimize translation experience * Refactor: Optimize translation experience * Feature: Add functionality of keyword search command * Feature: Add functionality of keyword search command. * Refactor: Remove redundant code * Add: Add feature to support randomly selecting roles for Azure voice. Refactor the code to support existing voice services for the ‘greeting’ feature. Fix the display issue of Azure voice role selection on the Guoba panel. * Refactor: Remove redundant code * Refactor: Improve the function of setting global voice roles and viewing role lists. Now you can set default roles for each voice service separately or view the supported role list. * Refactor: Remove redundant code * Feature: Add new function to support random character dialogues in all voice modes, add the ability to view the current user’s reply settings, and improve related functions in the global settings. * Refactor: Add compatibility directive for viewing reply settings feature * Feature: support adding QQ number to blacklist/whitelist * fix: 处理全局设置指令被上下班指令占用的问题 * fix: 处理全局设置指令被上下班指令占用的问题 --------- Co-authored-by: Sean <1519059137@qq.com> Co-authored-by: ikechan8370 <geyinchibuaa@gmail.com>
This commit is contained in:
parent
7007cacf6f
commit
bdad936c70
8 changed files with 704 additions and 447 deletions
152
apps/chat.js
152
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
|
||||
})
|
||||
|
|
@ -1267,10 +1258,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
|
||||
}
|
||||
|
|
@ -1290,10 +1277,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
|
||||
}
|
||||
|
|
@ -1332,10 +1315,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
|
||||
}
|
||||
|
|
@ -1355,10 +1334,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
|
||||
}
|
||||
|
|
@ -1376,11 +1351,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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue