完善视频提炼和视频复刻完善提交测试

This commit is contained in:
Azmat@qq.com
2026-08-28 10:15:15 +08:00
parent 52c5cdae1d
commit 849b14a0f6
33 changed files with 1475 additions and 208 deletions
+13 -4
View File
@@ -127,11 +127,14 @@ export function setRemember(username: string | null, remember: boolean) {
export class ApiError extends Error {
status: number;
/** 解析成功的响应体。409 这类「冲突」要把在跑的任务带回给调用方接上,只有 message 不够用。 */
payload?: Record<string, unknown>;
constructor(status: number, message: string) {
constructor(status: number, message: string, payload?: Record<string, unknown>) {
super(message);
this.name = "ApiError";
this.status = status;
this.payload = payload;
}
}
@@ -169,8 +172,10 @@ async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
const text = await response.text();
// DRF 错误体是 JSON({"detail": "..."} 或 {field: ["..."]}),提取人话给 toast,别把原始 JSON 怼到用户脸上
let message = text || `${response.status} ${response.statusText}`;
let payload: Record<string, unknown> | undefined;
try {
const data = JSON.parse(text) as Record<string, unknown>;
payload = data;
const first = data.detail ?? data.error ?? data.message ?? Object.values(data)[0];
if (typeof first === "string") message = first;
else if (Array.isArray(first) && typeof first[0] === "string") message = first[0];
@@ -191,7 +196,7 @@ async function request<T>(path: string, options: RequestInit = {}): Promise<T> {
if (response.status === 413) {
message = "文件太大,服务器没接收。视频请压到 200MB 以内再传";
}
throw new ApiError(response.status, message);
throw new ApiError(response.status, message, payload);
}
if (response.status === 204) return undefined as T;
return response.json() as Promise<T>;
@@ -379,7 +384,10 @@ export const api = {
return request<QuickCreateJob>(`/api/projects/quick-create-retry/${jobId}/`, { method: "POST" });
},
quickCreateHistory() {
return request<{ count: number; results: QuickCreateJob[] }>("/api/projects/quick-create-history/");
// inflight = 正在跑的那条:刷新/重进页面据此恢复进度,不再显示成空表单
return request<{ count: number; results: QuickCreateJob[]; inflight?: QuickCreateJob | null }>(
"/api/projects/quick-create-history/"
);
},
// 整体替换 metadata —— 调用方务必先展开现有 project.metadata 再合并,别把别的 key 冲掉
updateProject(id: string, payload: { name?: string; metadata?: Record<string, unknown> }) {
@@ -932,7 +940,8 @@ export const api = {
return request<{ task: FreeVideoTask }>("/api/ai/video-replace/", { method: "POST", body: JSON.stringify(payload) });
},
videoReplaceTasks(offset = 0, pageSize = 20) {
return request<{ results: FreeVideoTask[]; total: number; has_more: boolean }>(
// inflight 只在首页返回:刷新/重进页面据此恢复「进行中」,不用自己在列表里翻状态
return request<{ results: FreeVideoTask[]; total: number; has_more: boolean; inflight?: FreeVideoTask | null }>(
`/api/ai/video-replace/?offset=${offset}&page_size=${pageSize}`
);
},