From 5d4e07d4f4081f03f5a1d5945855360cab80e299 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Tue, 15 Sep 2026 01:45:51 +0800 Subject: [PATCH] =?UTF-8?q?feat(web):=20TTS=20=E6=83=85=E7=BB=AA=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E4=B8=BA=207=20=E7=A7=8D=20+=20=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E9=9F=B3=E8=89=B2=E8=AF=AD=E8=A8=80=E9=99=90=20zh/en=20+=20?= =?UTF-8?q?=E6=B8=85=E7=90=86=E6=AE=8B=E7=95=99=E4=BB=A3=E7=A0=81=20(#1915?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: xiaoxia Co-committed-by: xiaoxia --- apps/web/src/api/tts/types.ts | 2 +- apps/web/src/pages/ai-avatar/api/aiAvatar.ts | 2 +- .../components/PanelVoiceSelector.tsx | 17 +++++-- .../src/pages/ai-avatar/hooks/useAiAvatar.ts | 4 +- apps/web/src/pages/ai-avatar/types.ts | 39 ++++++++++----- .../web/src/pages/ai-avatar/utils/contract.ts | 49 +++++++++++++++---- apps/web/src/pages/voices/VoiceLibrary.tsx | 4 +- .../src/pages/voices/components/TtsModal.tsx | 16 +++++- .../components/tts-modal/LanguageControl.tsx | 23 +++++++-- .../voices/components/tts-modal/constants.ts | 36 ++++++++++---- .../pages/voices/hooks/useTtsSynthesize.ts | 29 ++++++++++- 11 files changed, 173 insertions(+), 48 deletions(-) diff --git a/apps/web/src/api/tts/types.ts b/apps/web/src/api/tts/types.ts index ab4dda8b8..9bfec5498 100644 --- a/apps/web/src/api/tts/types.ts +++ b/apps/web/src/api/tts/types.ts @@ -105,7 +105,7 @@ export interface TTSPreviewRequest { speed?: number pitch?: number language?: string - emotion?: string // 情绪参数:natural/excited/calm/friendly + emotion?: string // 情绪参数:neutral/happy/sad/angry/surprised/fearful/disgusted(后端 normalize_emotion() 兼容旧 natural/excited/calm/friendly 与中文标签) } /** TTS 试听响应 */ diff --git a/apps/web/src/pages/ai-avatar/api/aiAvatar.ts b/apps/web/src/pages/ai-avatar/api/aiAvatar.ts index ae3a4159d..152c7a193 100644 --- a/apps/web/src/pages/ai-avatar/api/aiAvatar.ts +++ b/apps/web/src/pages/ai-avatar/api/aiAvatar.ts @@ -55,7 +55,7 @@ export const createLipsyncJob = async (data: { script_text?: string /** 语速 0.5~2.0,默认 1.0(TTS 直生模式用) */ speed?: number - /** 情绪英文枚举:natural/excited/calm/friendly(TTS 直生模式用) */ + /** 情绪英文枚举:neutral/happy/sad/angry/surprised/fearful/disgusted(TTS 直生模式用;前端经 normalizeEmotion 归一化) */ emotion?: string enable_video_loop?: boolean project_id?: string diff --git a/apps/web/src/pages/ai-avatar/components/PanelVoiceSelector.tsx b/apps/web/src/pages/ai-avatar/components/PanelVoiceSelector.tsx index 6269e7663..58cd92f33 100644 --- a/apps/web/src/pages/ai-avatar/components/PanelVoiceSelector.tsx +++ b/apps/web/src/pages/ai-avatar/components/PanelVoiceSelector.tsx @@ -13,7 +13,8 @@ import { type VoiceEmotion, type VoiceLanguage, VOICE_EMOTION_OPTIONS, - VOICE_LANGUAGE_OPTIONS, + PRESET_VOICE_LANGUAGE_OPTIONS, + CLONE_VOICE_LANGUAGE_OPTIONS, } from "../types" interface PanelVoiceSelectorProps { @@ -91,6 +92,12 @@ export function PanelVoiceSelector({ const NO_PREVIEW_TIP = "该音色暂无试听音频,请先用此音色生成一段配音后再试听" + // 系统预置音色仅支持 zh/en;克隆音色支持全语言 + const languageOptions = + voiceSource === "clone" ? CLONE_VOICE_LANGUAGE_OPTIONS : PRESET_VOICE_LANGUAGE_OPTIONS + // 当前语言不在可选列表(切回预置时 ja/ko/cantonese/mandarin 失效)→ 自动回退到中文 + const effectiveLanguage = languageOptions.some((o) => o.value === language) ? language : "zh" + /** 用指定 URL 真实播放(抽取公共) */ const playAudioUrl = (voiceId: string, url: string) => { // 临时兼容:后端 /tts/preview 返回 HTTP URL,staging 是 HTTPS,Mixed Content 会阻止加载 @@ -289,10 +296,12 @@ export function PanelVoiceSelector({