import EmptyData from "@/components/empty-data"; import CardListItem from "@/components/list/card-list-item/index"; import CardList from "@/components/list/card-list/index"; import { IVoicePlayerBar } from "@/components/voice-player-bar/index"; import WemetaRadio from "@/components/wemeta-radio/index"; import { CloneVoiceStatus } from "@/consts/enum"; import IconWave from "@/images/icon-wave-20.png"; import { voiceCloneConfirm } from "@/service/character"; import { useAppStore } from "@/store/appStore"; import { useCharacterStore } from "@/store/characterStore"; import { ICharacter, TEntityVoiceCloneRecord } from "@/types"; import { formatDateFull, getCloneVoiceIdentifier } from "@/utils/index"; import { Image, View } from "@tarojs/components"; import { useEffect, useRef, useState } from "react"; import PopupContainer from "./components/popup-container"; import PopupRecorder, { ECloneStatus } from "./components/popup-recorder/index"; import PopupTryout from "./components/popup-tryout/index"; import style from "./index.module.less"; interface Props { value?: ICharacter; setValue?: (value: ICharacter) => void; profileId: string; onPlay?: (voice: any) => void; } export default ({ profileId, onPlay }: Props) => { const playerRef = useRef(null); const intervalRef = useRef(null); const [show, setShow] = useState(false); const [popupType, setPopupType] = useState<"clone" | "try" | "reclone">( "clone", ); const [voiceName, setVoiceName] = useState(""); const [voiceIndex, setVoiceIndex] = useState(-1); const { saveCharacter, fetchCharacter, fetchVoiceCloneHistory } = useCharacterStore(); const character = useCharacterStore((state) => state.character); const voiceList = useCharacterStore((state) => state.voiceList); const appConfig = useAppStore((state) => state.appConfig); const createVoiceNameText = (voiceName: string) => { const i = voiceList.findIndex((item) => item.voiceName === voiceName); console.log(voiceName, i); if (i === -1) return ""; return `克隆声音 0${i + 1}`; }; // 克隆列表操作 const renderRightColumn = (item?: TEntityVoiceCloneRecord) => { if (item?.status == CloneVoiceStatus.CloneVoiceStatusExpired) { return ; } if (item?.status == CloneVoiceStatus.CloneVoiceStatusSuccess) { const notSystemVoice = (character?.voice !== character?.defaultSystemVoice) const isSameVoice = (item.voiceName === character?.voice) return ( ); } if (item?.status == CloneVoiceStatus.CloneVoiceStatusUnconfirmed) { return ( 试听 ); } return <>; }; // 克隆状态 const renderCloneStatus = (item: TEntityVoiceCloneRecord) => { if (item.status === CloneVoiceStatus.CloneVoiceStatusSuccess) { return ( {item.createdAt && formatDateFull(new Date(item.createdAt))} ); } if (item.status === CloneVoiceStatus.CloneVoiceStatusUnconfirmed) { return 试听确认; } if (item.status == CloneVoiceStatus.CloneVoiceStatusExpired) { return 已过期; } return 当前时间; }; const renderCloneList = () => { if (!voiceList.length) { return ; } return ( {voiceList.map((item, _index) => { return ( { return renderRightColumn(item); }} onClick={() => handleSelect(item, _index)} > {/* deprecated getCloneVoiceIdentifier */} {item.voiceAlias ?? getCloneVoiceIdentifier(_index + 1)} {renderCloneStatus(item)} ); })} ); }; const handleSelect = (item: TEntityVoiceCloneRecord, index: number) => { setVoiceIndex(index); if (item.status == CloneVoiceStatus.CloneVoiceStatusSuccess) { if (item.voiceName) { setVoiceName(item.voiceName); onPlay && onPlay({ voiceName: item.voiceName, voiceAlias: item.voiceAlias, voiceIndex: index, }); } saveCharacter({ profileId: profileId, voice: item.voiceName, }); } if (item.status == CloneVoiceStatus.CloneVoiceStatusUnconfirmed) { // 未确认,弹出试听框 setPopupType("try"); setShow(true); } }; // 克隆按钮状态 const handleCloneStatus = (status: ECloneStatus) => { console.log(status); }; const fetchVoiceList = async () => { if (profileId) { const r = await fetchVoiceCloneHistory(profileId); const result = r.find((item) => item.status === "pending"); if (result) { intervalRef.current = setTimeout(() => fetchVoiceList(), 3000); } else { stopTimer(); } } }; const handleSureAction = async () => { setShow(false); await voiceCloneConfirm(voiceList[voiceIndex].voiceName!); fetchVoiceList(); }; const handleRecloneAction = () => { setPopupType("reclone"); setShow(true); }; // 声音录制完成 const onRecordEnd = (r: string) => { console.log("onRecordEnd:", r); fetchVoiceList(); }; const stopTimer = () => { if (intervalRef.current !== null) { clearTimeout(intervalRef.current); intervalRef.current = null; } }; const calcRemainCloneNum = () => { if (appConfig?.maxCloneNum) { const clonedNum = voiceList.filter( (item) => item.status === CloneVoiceStatus.CloneVoiceStatusSuccess || item.status === CloneVoiceStatus.CloneVoiceStatusUnconfirmed, ).length; const remainNum = appConfig.maxCloneNum - clonedNum; return remainNum < 0 ? 0 : remainNum; } return voiceList.length; }; const initPage = async (profileId: string) => { await fetchCharacter(profileId); fetchVoiceCloneHistory(profileId); character?.voice && setVoiceName(character.voice); }; useEffect(() => { profileId && initPage(profileId); }, [profileId]); // 清除定时器 useEffect(() => { return () => { stopTimer(); }; }, []); return ( {/* */} {renderCloneList()} {(popupType == "clone" || popupType == "reclone") && ( handleCloneStatus(status)} voiceName={ popupType == "reclone" ? voiceList[voiceIndex].voiceName! : "" } > )} {popupType == "try" && ( )} { setPopupType("clone"); setShow(true); }} > 添加克隆声音 (剩{calcRemainCloneNum()}次) ); };