+ {showLabel && (
+
+ 配音风格
+
+ )}
+
+ {TTS_STYLE_OPTIONS.map((opt) => {
+ const selected = current === opt.value
+ return (
+
+ )
+ })}
+
+
+ )
+ }
+
+ return (
+
+ {showLabel && (
+
+ 配音风格
+
+ )}
+
+ {TTS_STYLE_OPTIONS.map((opt) => {
+ const selected = current === opt.value
+ return (
+
+ )
+ })}
+
+
+ )
+}
+
+export default TtsStyleSelector
diff --git a/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx b/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx
index a9a10e723..5698549fa 100644
--- a/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx
+++ b/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx
@@ -94,7 +94,7 @@ const AiAvatarPage: React.FC = () => {
state.resetTtsPreview()
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [state.scriptText, state.selectedVoice?.voice_id, state.speed, state.emotion])
+ }, [state.scriptText, state.selectedVoice?.voice_id, state.speed, state.emotion, state.style])
const _clearTtsProgressTimer = useCallback(() => {
if (ttsProgressTimerRef.current) {
@@ -175,7 +175,14 @@ const AiAvatarPage: React.FC = () => {
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [state.selectedVideo, state.selectedVoice, state.scriptText, state.speed, state.emotion])
+ }, [
+ state.selectedVideo,
+ state.selectedVoice,
+ state.scriptText,
+ state.speed,
+ state.emotion,
+ state.style,
+ ])
const handleRetryTts = useCallback(() => {
handleGenerateTts()
@@ -255,6 +262,7 @@ const AiAvatarPage: React.FC = () => {
video_url: videoUrl,
speed: state.speed,
emotion: normalizeEmotion(state.emotion),
+ style: state.style,
}
}
const job = await createLipsyncJob(payload)
@@ -299,6 +307,7 @@ const AiAvatarPage: React.FC = () => {
state.scriptText,
state.speed,
state.emotion,
+ state.style,
state.ttsPreview,
])
@@ -600,6 +609,8 @@ const AiAvatarPage: React.FC = () => {
onSelectVoice={state.setSelectedVoice}
emotion={state.emotion}
onEmotionChange={state.setEmotion}
+ style={state.style}
+ onStyleChange={state.setStyle}
speed={state.speed}
onSpeedChange={state.setSpeed}
language={state.language}
diff --git a/apps/web/src/pages/ai-avatar/api/aiAvatar.ts b/apps/web/src/pages/ai-avatar/api/aiAvatar.ts
index cdbcf6a50..83412bace 100644
--- a/apps/web/src/pages/ai-avatar/api/aiAvatar.ts
+++ b/apps/web/src/pages/ai-avatar/api/aiAvatar.ts
@@ -41,6 +41,8 @@ export const createLipsyncJob = async (data: {
speed?: number
/** 情绪英文枚举:neutral/happy/sad/angry/surprised/fearful/disgusted(TTS 直生模式用;前端经 normalizeEmotion 归一化) */
emotion?: string
+ /** 配音风格预设(natural/excited/professional/sweet/news/livestream) */
+ style?: string
enable_video_loop?: boolean
project_id?: string
}): Promise