diff --git a/README.md b/README.md index e9191ac..dc95ae9 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,7 @@ pnpm i #### 设置相关 -> #chat切换浏览器/API/API2/API3/Bing +> #chatgpt切换浏览器/API/API2/API3/Bing > > #chatgpt设置[必应]Token > diff --git a/apps/chat.js b/apps/chat.js index 0290dcd..25b1465 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -9,6 +9,7 @@ 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 fs from 'fs' import { render, renderUrl, getMessageById, @@ -119,11 +120,11 @@ export class chatgpt extends plugin { permission: 'master' }, { - reg: '^#(chatgpt)?结束对话([sS]*)', + reg: '^#(chatgpt)?(结束|新开|摧毁|毁灭|完结)对话([sS]*)', fnc: 'destroyConversations' }, { - reg: '^#(chatgpt)?结束全部对话$', + reg: '^#(chatgpt)?(结束|新开|摧毁|毁灭|完结)全部对话$', fnc: 'endAllConversations', permission: 'master' }, @@ -1046,7 +1047,7 @@ export class chatgpt extends plugin { } try { try { - let sendable = await uploadRecord(wav) + let sendable = await uploadRecord(wav, Config.ttsMode === 'azure') if (sendable) { await e.reply(sendable) } else { @@ -1061,6 +1062,14 @@ export class chatgpt extends plugin { logger.error(err) await this.reply('合成语音发生错误~') } + if (Config.ttsMode === 'azure' && Config.azureTTSKey) { + // 清理文件 + try { + fs.unlinkSync(wav) + } catch (err) { + logger.warn(err) + } + } } else if (userSetting.usePicture || (Config.autoUsePicture && response.length > Config.autoUsePictureThreshold)) { // todo use next api of chatgpt to complete incomplete respoonse try { diff --git a/apps/help.js b/apps/help.js index 23707ef..610b80b 100644 --- a/apps/help.js +++ b/apps/help.js @@ -38,17 +38,17 @@ let helpData = [ }, { icon: 'destroy', - title: '#结束对话', + title: '#(结束|新开|摧毁|毁灭|完结)对话', desc: '结束自己当前对话,下次开启对话机器人将遗忘掉本次对话内容。' }, { icon: 'destroy', - title: '#结束全部对话', + title: '#(结束|新开|摧毁|毁灭|完结)全部对话', desc: '结束正在与本机器人进行对话的全部用户的对话。' }, { icon: 'destroy-other', - title: '#结束对话 @某人', + title: '#(结束|新开|摧毁|毁灭|完结)对话 @某人', desc: '结束该用户当前对话,下次开启对话机器人将遗忘掉本次对话内容。' }, { @@ -104,7 +104,7 @@ let helpData = [ { icon: 'game', title: '#chatgpt设置语音角色', - desc: '设置语音模式下回复的角色音色' + desc: '设置语音模式下回复的角色音色。优先级高于默认语音角色' }, { icon: 'list', diff --git a/guoba.support.js b/guoba.support.js index d4bc80d..9f28ab9 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -595,13 +595,13 @@ export function supportGuoba () { { field: 'cloudMode', label: '云转码API发送数据模式', - bottomHelpMessage: '默认发送数据链接,如果你部署的是本地服务,请改为文件', + bottomHelpMessage: '默认发送数据链接,如果你部署的是本地vits服务或使用的是微软azure,请改为文件', component: 'Select', componentProps: { options: [ { label: '文件', value: 'file' }, - { label: '链接', value: 'url' }, - { label: '数据', value: 'buffer' } + { label: '链接', value: 'url' } + // { label: '数据', value: 'buffer' } ] } }, diff --git a/utils/uploadRecord.js b/utils/uploadRecord.js index ee1a339..bc417d0 100644 --- a/utils/uploadRecord.js +++ b/utils/uploadRecord.js @@ -1,6 +1,6 @@ // import Contactable, { core } from 'oicq' import querystring from 'querystring' -import fetch, { File } from 'node-fetch' +import fetch, { File, fileFromSync, FormData } from 'node-fetch' import fs from 'fs' import os from 'os' import util from 'util' @@ -12,70 +12,65 @@ let module try { module = await import('oicq') } catch (err) { - module = await import('icqq') + try { + module = await import('icqq') + } catch (err1) { + // 可能是go-cqhttp之类的 + } } -const { core } = module -const Contactable = module.default -// import { pcm2slk } from 'node-silk' -let errors = {} -let pcm2slk -try { - pcm2slk = (await import('node-silk')).pcm2slk -} catch (e) { - if (Config.cloudTranscode) { - logger.warn('未安装node-silk,将尝试使用云转码服务进行合成') - } else { - Config.debug && logger.error(e) - logger.warn('未安装node-silk,如ffmpeg不支持amr编码请安装node-silk以支持语音模式') +let pcm2slk, core, Contactable +if (module) { + core = module.core + Contactable = module.default + try { + pcm2slk = (await import('node-silk')).pcm2slk + } catch (e) { + if (Config.cloudTranscode) { + logger.warn('未安装node-silk,将尝试使用云转码服务进行合成') + } else { + Config.debug && logger.error(e) + logger.warn('未安装node-silk,如ffmpeg不支持amr编码请安装node-silk以支持语音模式') + } } } -async function uploadRecord (recordUrl) { +// import { pcm2slk } from 'node-silk' +let errors = {} + +async function uploadRecord (recordUrl, forceFile) { let result if (pcm2slk) { result = await getPttBuffer(recordUrl, Bot.config.ffmpeg_path) } else if (Config.cloudTranscode) { try { - if (Config.cloudMode === 'buffer' || Config.cloudMode === 'file') { - let response = await fetch(recordUrl, { - method: 'GET', - headers: { - 'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 12; MI 9 Build/SKQ1.211230.001)' - } - }) - if (Config.cloudMode === 'file') { + if (forceFile || Config.cloudMode === 'file') { + const formData = new FormData() + let buffer + if (!recordUrl.startsWith('http')) { + // 本地文件 + formData.append('file', fileFromSync(recordUrl)) + } else { + let response = await fetch(recordUrl, { + method: 'GET', + headers: { + 'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 12; MI 9 Build/SKQ1.211230.001)' + } + }) const blob = await response.blob() const arrayBuffer = await blob.arrayBuffer() - const buffer = Buffer.from(arrayBuffer) - const formData = new FormData() + buffer = Buffer.from(arrayBuffer) formData.append('file', new File([buffer], 'audio.wav')) - const resultres = await fetch(`${Config.cloudTranscode}/audio`, { - method: 'POST', - body: formData - }) - let t = await resultres.text() - try { - result = JSON.parse(t) - } catch (e) { - logger.error(t) - throw e - } - } else { - const buf = Buffer.from(await response.arrayBuffer()) - const resultres = await fetch(`${Config.cloudTranscode}/audio`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ recordBuffer: buf }) - }) - let t = await resultres.text() - try { - result = JSON.parse(t) - } catch (e) { - logger.error(t) - throw e - } + } + const resultres = await fetch(`${Config.cloudTranscode}/audio`, { + method: 'POST', + body: formData + }) + let t = await resultres.text() + try { + result = JSON.parse(t) + } catch (e) { + logger.error(t) + throw e } } else { const resultres = await fetch(`${Config.cloudTranscode}/audio`, {