import { useRef, useCallback, useEffect } from "react" import { createVoiceClone, toVoiceClone } from "@/api/voice-clone" import { uploadAsset } from "@/api/assets" import type { VoiceClone } from "@/api/voice-clone" interface UseCloneSubmitOptions { voiceName: string voiceDescription: string selectedFile: File | null recordedBlob: Blob | null setPhase: (phase: "input" | "uploading" | "cloning" | "done") => void setErrorMessage: (msg: string) => void validateForm: () => string | null onSuccess?: (clone: VoiceClone) => void onClose: () => void } /** * 克隆提交流程 Hook * 封装上传 + 克隆 + 完成的三阶段流程 */ export function useCloneSubmit({ voiceName, voiceDescription, selectedFile, recordedBlob, setPhase, setErrorMessage, validateForm, onSuccess, onClose, }: UseCloneSubmitOptions) { const timerRef = useRef | null>(null) /** 组件卸载时清理定时器 */ useEffect(() => { return () => { if (timerRef.current) clearTimeout(timerRef.current) } }, []) const handleSubmit = useCallback(async () => { const formError = validateForm() if (formError) { setErrorMessage(formError) return } setErrorMessage("") try { // 阶段 1:上传音频 setPhase("uploading") let fileToUpload: File if (selectedFile) { fileToUpload = selectedFile } else { fileToUpload = new File([recordedBlob!], `recorded-${Date.now()}.webm`, { type: "audio/webm", }) } const formData = new FormData() formData.append("file", fileToUpload) const uploadResult = await uploadAsset(formData) // 阶段 2:克隆 setPhase("cloning") const result = await createVoiceClone({ name: voiceName.trim(), description: voiceDescription.trim() || undefined, audio_url: uploadResult.url, }) // 阶段 3:完成 setPhase("done") // 2秒后自动关闭 timerRef.current = setTimeout(() => { onSuccess?.(toVoiceClone(result)) onClose() }, 2000) } catch (err) { setPhase("input") setErrorMessage(err instanceof Error ? err.message : "克隆失败,请重试") } }, [ validateForm, selectedFile, recordedBlob, voiceName, voiceDescription, setPhase, setErrorMessage, onSuccess, onClose, ]) return { handleSubmit } }