feat(voice): 语音参数移入 config.js + 设置页男女声切换
- config: 新增 tts.female/male 两组参数(voiceType/volume/speed), 直接改数字即可调音色,无需改逻辑代码 - storage: getSettings 兜底 voiceGender(旧用户迁移为女声) - voice: 新增 _getTtsParams 读 config+性别;缓存 key 含完整参数, 改音色/音量/性别自动重新合成,无需手动清缓存 - settings: 训练偏好加"语音音色"segmented(女声/男声) - tts 云函数: _synthesize 用传入 opts 合成;_upload 路径含 voiceType (男/女不同文件);需重新部署 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@ const PROMPTS = {
|
||||
|
||||
const CACHE_DIR = 'tts-cache'
|
||||
|
||||
const _synthesize = async (text, promptKey) => {
|
||||
const _synthesize = async (text, promptKey, opts) => {
|
||||
let TtsClient
|
||||
try {
|
||||
TtsClient = require('tencentcloud-sdk-nodejs').tts.v20190823.Client
|
||||
@@ -52,17 +52,17 @@ const _synthesize = async (text, promptKey) => {
|
||||
const res = await client.TextToVoice({
|
||||
Text: text,
|
||||
SessionId: `${promptKey}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`,
|
||||
VoiceType: 101001, // 智瑜,温柔女声
|
||||
VoiceType: (opts && opts.voiceType) || 101001, // 智瑜,温柔女声
|
||||
Codec: 'mp3',
|
||||
SampleRate: 16000,
|
||||
Speed: 0,
|
||||
Volume: 5
|
||||
Speed: (opts && opts.speed != null) ? opts.speed : 0,
|
||||
Volume: (opts && opts.volume != null) ? opts.volume : 5
|
||||
})
|
||||
return Buffer.from(res.Audio, 'base64')
|
||||
}
|
||||
|
||||
const _upload = async (key, buffer) => {
|
||||
const cloudPath = `${CACHE_DIR}/${key}.mp3`
|
||||
const _upload = async (key, buffer, voiceType) => {
|
||||
const cloudPath = `${CACHE_DIR}/${key}-${voiceType || 'default'}.mp3`
|
||||
// uploadFile returns the canonical fileID (e.g. "cloud://env.xxx/...").
|
||||
// We must use THAT — not the relative cloudPath we passed in — when
|
||||
// calling getTempFileURL. A self-constructed fileID is invalid.
|
||||
@@ -71,7 +71,7 @@ const _upload = async (key, buffer) => {
|
||||
}
|
||||
|
||||
exports.main = async (event) => {
|
||||
const { promptKey, fileID } = event || {}
|
||||
const { promptKey, fileID, voiceType, volume, speed } = event || {}
|
||||
const text = PROMPTS[promptKey]
|
||||
if (!text) {
|
||||
return { success: false, error: `Unknown prompt key: ${promptKey}` }
|
||||
@@ -93,8 +93,8 @@ exports.main = async (event) => {
|
||||
|
||||
// Slow path: synthesize + upload + return fresh fileID for caching
|
||||
try {
|
||||
const buffer = await _synthesize(text, promptKey)
|
||||
const newFileID = await _upload(promptKey, buffer)
|
||||
const buffer = await _synthesize(text, promptKey, { voiceType, volume, speed })
|
||||
const newFileID = await _upload(promptKey, buffer, voiceType)
|
||||
const urlRes = await cloud.getTempFileURL({ fileList: [newFileID] })
|
||||
const url = urlRes.fileList[0].tempFileURL
|
||||
if (!url) {
|
||||
|
||||
Reference in New Issue
Block a user