feat: 添加Azure语音支持

This commit is contained in:
ikechan8370 2023-04-22 22:54:03 +08:00
parent 20f6cd5390
commit cf992bbc2c
6 changed files with 396 additions and 36 deletions

View file

@ -7,6 +7,7 @@ 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 {
render, renderUrl,
getMessageById,
@ -141,6 +142,10 @@ export class chatgpt extends plugin {
reg: '^#chatgpt语音模式$',
fnc: 'switch2Audio'
},
{
reg: '^#chatgpt语音换源',
fnc: 'switchTTSSource'
},
{
reg: '^#chatgpt设置(语音角色|角色语音|角色)',
fnc: 'setDefaultRole'
@ -519,26 +524,71 @@ export class chatgpt extends plugin {
await this.reply('ChatGPT回复已转换为语音模式')
}
async switchTTSSource (e) {
let target = e.msg.replace(/^#chatgpt语音换源/, '')
switch (target.trim()) {
case '1': {
Config.ttsMode = 'vits-uma-genshin-honkai'
break
}
case '2': {
Config.ttsMode = 'azure'
break
}
default: {
await e.reply('请使用#chatgpt语音换源+数字进行换源。1为vits-uma-genshin-honkai2为微软Azure')
return
}
}
await e.reply('语音转换源已切换为' + Config.ttsMode)
}
async setDefaultRole (e) {
if (!Config.ttsSpace) {
await this.reply('您没有配置VITS API请前往锅巴面板进行配置')
if (Config.ttsMode === 'vits-uma-genshin-honkai' && !Config.ttsSpace) {
await this.reply('您没有配置vits-uma-genshin-honkai API请前往后台管理或锅巴面板进行配置')
return
}
let userSetting = await redis.get(`CHATGPT:USER:${e.sender.user_id}`)
if (!userSetting) {
userSetting = getDefaultReplySetting()
} else {
userSetting = JSON.parse(userSetting)
if (Config.ttsMode === 'azure' && !Config.azureTTSKey) {
await this.reply('您没有配置azure 密钥,请前往后台管理或锅巴面板进行配置')
return
}
const regex = /^#chatgpt设置(语音角色|角色语音|角色)/
// let speaker = _.trimStart(e.msg, regex) || '随机'
let speaker = e.msg.replace(regex, '').trim() || '随机'
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}`)
} else {
await this.reply(`”抱歉,${userSetting.ttsRole}“我还不认识呢`)
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)
}
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}`)
} else {
await this.reply(`抱歉,"${userSetting.ttsRole}"我还不认识呢`)
}
break
}
case 'azure': {
let chosen = AzureTTS.supportConfigurations.filter(s => s.name === speaker)
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
await this.reply(`您的默认语音角色已被设置为”${speaker}-${chosen[0].gender}-${chosen[0].languageDetail}`)
}
break
}
}
}
@ -639,7 +689,12 @@ export class chatgpt extends plugin {
userSetting = getDefaultReplySetting()
}
let useTTS = !!userSetting.useTTS
let speaker = convertSpeaker(userSetting.ttsRole || Config.defaultTTSRole)
let speaker
if (Config.ttsMode === 'vits-uma-genshin-honkai') {
speaker = convertSpeaker(userSetting.ttsRole || Config.defaultTTSRole)
} else if (Config.ttsMode === 'azure') {
speaker = userSetting.ttsRoleAzure || Config.defaultTTSRole
}
// 每个回答可以指定
let trySplit = prompt.split('回答:')
if (trySplit.length > 1 && speakers.indexOf(convertSpeaker(trySplit[0])) > -1) {
@ -904,7 +959,7 @@ export class chatgpt extends plugin {
ttsResponse = response.replace(ttsRegex, '')
// 先把文字回复发出去,避免过久等待合成语音
if (Config.alsoSendText || ttsResponse.length > Config.ttsAutoFallbackThreshold) {
if (ttsResponse.length > Config.ttsAutoFallbackThreshold) {
if (Config.ttsMode === 'vits-uma-genshin-honkai' && ttsResponse.length > Config.ttsAutoFallbackThreshold) {
await this.reply('回复的内容过长,已转为文本模式')
}
await this.reply(await convertFaces(response, Config.enableRobotAt, e), e.isGroup)
@ -915,28 +970,38 @@ export class chatgpt extends plugin {
this.reply(`建议的回复:\n${chatMessage.suggestedResponses}`)
}
}
if (Config.ttsSpace && ttsResponse.length <= Config.ttsAutoFallbackThreshold) {
let wav
if (Config.ttsMode === 'vits-uma-genshin-honkai' && Config.ttsSpace) {
try {
let wav = await generateAudio(ttsResponse, speaker, '中日混合(中文用[ZH][ZH]包裹起来,日文用[JA][JA]包裹起来)')
try {
let sendable = await uploadRecord(wav)
if (sendable) {
await e.reply(sendable)
} else {
// 如果合成失败尝试使用ffmpeg合成
await e.reply(segment.record(wav))
}
} catch (err) {
logger.error(err)
await e.reply(segment.record(wav))
}
wav = await generateAudio(ttsResponse, speaker, '中日混合(中文用[ZH][ZH]包裹起来,日文用[JA][JA]包裹起来)')
} catch (err) {
logger.error(err)
await this.reply('合成语音发生错误~')
}
} else if (!Config.ttsSpace) {
} else if (Config.ttsMode === 'azure' && Config.azureTTSKey) {
wav = await AzureTTS.generateAudio(ttsResponse, {
speaker: speaker
})
} else {
await this.reply('你没有配置转语音API哦')
}
try {
try {
let sendable = await uploadRecord(wav)
if (sendable) {
await e.reply(sendable)
} else {
// 如果合成失败尝试使用ffmpeg合成
await e.reply(segment.record(wav))
}
} catch (err) {
logger.error(err)
await e.reply(segment.record(wav))
}
} catch (err) {
logger.error(err)
await this.reply('合成语音发生错误~')
}
} else if (userSetting.usePicture || (Config.autoUsePicture && response.length > Config.autoUsePictureThreshold)) {
// todo use next api of chatgpt to complete incomplete respoonse
try {