From 950dced40be79f2aecffec63f082f6b1f8e986a4 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 30 Jul 2026 14:05:02 +0800 Subject: [PATCH] =?UTF-8?q?fix(#1195):=20useStep5Voice=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=85=8B=E9=9A=86=E9=9F=B3=E8=89=B2=E8=AF=95=E5=90=AC=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E9=80=BB=E8=BE=91=EF=BC=8C=E9=A2=84=E7=95=99=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E6=8E=A5=E5=8F=A3=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pages/generate/hooks/useStep5Voice.tsx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/apps/web/src/pages/generate/hooks/useStep5Voice.tsx b/apps/web/src/pages/generate/hooks/useStep5Voice.tsx index ca630c3a3..6256826b4 100755 --- a/apps/web/src/pages/generate/hooks/useStep5Voice.tsx +++ b/apps/web/src/pages/generate/hooks/useStep5Voice.tsx @@ -2,6 +2,7 @@ * Step 5 配音选择 Hook * 封装 AI 推荐、预设音色试听、TTS 自定义合成、存为素材等逻辑 */ +import { useState, useRef, useCallback } from "react" import { message } from "antd" import type { VoiceClone } from "@/api/voice-clone" import { VOICE_GENDER_ICON, CLONE_STATUS_CONFIG } from "../constants" @@ -100,6 +101,40 @@ export function useStep5Voice({ onCloneModalOpenChange, }) + /* ── 克隆音色试听播放 ── */ + const [playingCloneVoice, setPlayingCloneVoice] = useState(null) + const cloneAudioRef = useRef(null) + + const handlePlayCloneSample = useCallback( + (voice: VoiceClone) => { + if (playingCloneVoice === voice.id) { + cloneAudioRef.current?.pause() + cloneAudioRef.current = null + setPlayingCloneVoice(null) + return + } + cloneAudioRef.current?.pause() + // TODO: 后端克隆音色试听接口出来后,改为调用接口获取试听音频 + // 目前使用 sample_url 字段,如果没有则提示 + const audioUrl = voice.sample_url + if (!audioUrl) { + message.warning("该克隆音色暂无试听音频") + return + } + const audio = new Audio(audioUrl) + cloneAudioRef.current = audio + audio.play().catch(() => { + message.error("播放失败,请检查网络") + }) + audio.onended = () => { + setPlayingCloneVoice(null) + cloneAudioRef.current = null + } + setPlayingCloneVoice(voice.id) + }, + [playingCloneVoice], + ) + const handleCloneSuccess = (voice: VoiceClone) => { rawCloneSuccess(voice) message.success("音色克隆成功!") @@ -124,6 +159,9 @@ export function useStep5Voice({ // 音频播放 playingVoice, toggleVoicePlay, + // 克隆音色试听播放 + playingCloneVoice, + handlePlayCloneSample, // 预设音色操作 handleSelectPresetVoice, handleSelectCloneVoice, @@ -163,3 +201,4 @@ export function useStep5Voice({ } export default useStep5Voice +