Files
ViGent2/frontend/src/features/home/model/useRefAudios.ts
Kevin Wong 96a298e51c 更新
2026-02-11 13:48:45 +08:00

117 lines
3.8 KiB
TypeScript

import { useCallback, useState } from "react";
import api from "@/shared/api/axios";
import { ApiResponse, unwrap } from "@/shared/api/types";
import { toast } from "sonner";
interface RefAudio {
id: string;
name: string;
path: string;
ref_text: string;
duration_sec: number;
created_at: number;
}
interface UseRefAudiosOptions {
selectedRefAudio: RefAudio | null;
setSelectedRefAudio: React.Dispatch<React.SetStateAction<RefAudio | null>>;
setRefText: React.Dispatch<React.SetStateAction<string>>;
}
export const useRefAudios = ({
selectedRefAudio,
setSelectedRefAudio,
setRefText,
}: UseRefAudiosOptions) => {
const [refAudios, setRefAudios] = useState<RefAudio[]>([]);
const [isUploadingRef, setIsUploadingRef] = useState(false);
const [uploadRefError, setUploadRefError] = useState<string | null>(null);
const [retranscribingId, setRetranscribingId] = useState<string | null>(null);
const fetchRefAudios = useCallback(async () => {
try {
const { data: res } = await api.get<ApiResponse<{ items: RefAudio[] }>>('/api/ref-audios');
const payload = unwrap(res);
const items: RefAudio[] = payload.items || [];
items.sort((a, b) => b.created_at - a.created_at);
setRefAudios(items);
} catch (error) {
console.error("获取参考音频失败:", error);
}
}, []);
const uploadRefAudio = useCallback(async (file: File) => {
setIsUploadingRef(true);
setUploadRefError(null);
try {
const formData = new FormData();
formData.append('file', file);
const { data: res } = await api.post<ApiResponse<RefAudio>>('/api/ref-audios', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
const payload = unwrap(res);
await fetchRefAudios();
setSelectedRefAudio(payload);
setRefText(payload.ref_text);
setIsUploadingRef(false);
} catch (err: unknown) {
console.error("Upload ref audio failed:", err);
setIsUploadingRef(false);
const axiosErr = err as { response?: { data?: { message?: string } }; message?: string };
const errorMsg = axiosErr.response?.data?.message || axiosErr.message || String(err);
setUploadRefError(`上传失败: ${errorMsg}`);
}
}, [fetchRefAudios, setRefText, setSelectedRefAudio]);
const deleteRefAudio = useCallback(async (audioId: string) => {
if (!confirm("确定要删除这个参考音频吗?")) return;
try {
await api.delete(`/api/ref-audios/${encodeURIComponent(audioId)}`);
fetchRefAudios();
if (selectedRefAudio?.id === audioId) {
setSelectedRefAudio(null);
setRefText('');
}
} catch (error) {
toast.error("删除失败: " + error);
}
}, [fetchRefAudios, selectedRefAudio, setRefText, setSelectedRefAudio]);
const retranscribeRefAudio = useCallback(async (audioId: string) => {
setRetranscribingId(audioId);
try {
const { data: res } = await api.post<ApiResponse<{ ref_text: string }>>(
`/api/ref-audios/${encodeURIComponent(audioId)}/retranscribe`
);
const payload = unwrap(res);
toast.success("识别完成");
// 更新列表和当前选中
await fetchRefAudios();
if (selectedRefAudio?.id === audioId) {
setRefText(payload.ref_text);
}
} catch (err: unknown) {
const axiosErr = err as { response?: { data?: { message?: string } }; message?: string };
const errorMsg = axiosErr.response?.data?.message || axiosErr.message || String(err);
toast.error(`识别失败: ${errorMsg}`);
} finally {
setRetranscribingId(null);
}
}, [fetchRefAudios, selectedRefAudio, setRefText]);
return {
refAudios,
isUploadingRef,
uploadRefError,
setUploadRefError,
fetchRefAudios,
uploadRefAudio,
deleteRefAudio,
retranscribeRefAudio,
retranscribingId,
};
};