type LongTaskResponse = { success?: boolean; processing?: boolean; status?: string; taskId?: string; pollAfterMs?: number; error?: string; detail?: string; [key: string]: any; }; function isProcessingPayload(payload: LongTaskResponse | null | undefined) { if (!payload) return false; if (payload.processing === true) return true; const status = String(payload.status || "").toLowerCase(); return status === "queued" || status === "running" || status === "pending"; } function buildTaskError(payload: LongTaskResponse | null | undefined, fallback: string) { const message = payload?.error || payload?.detail || fallback; return new Error(String(message || fallback)); } async function safeParseJson(response: Response) { try { return (await response.json()) as LongTaskResponse; } catch { return null; } } export async function requestLongTaskResult(params: { endpoint: string; payload: Record; pollingParams?: Record; timeoutMs?: number; }) { const response = await fetch(params.endpoint, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(params.payload), }); const result = await safeParseJson(response); if (!response.ok) { throw buildTaskError(result, "请求失败"); } if (!isProcessingPayload(result)) { return result as LongTaskResponse; } const taskId = String(result?.taskId || "").trim(); if (!taskId) { throw buildTaskError(result, "任务正在处理中,但缺少 taskId"); } const pollingParams = new URLSearchParams(); pollingParams.set("taskId", taskId); for (const [key, value] of Object.entries(params.pollingParams || {})) { if (value === null || value === undefined || value === "") continue; pollingParams.set(key, String(value)); } const timeoutMs = Math.max(10_000, params.timeoutMs ?? 8 * 60 * 1000); const startedAt = Date.now(); let pollAfterMs = Math.max(800, Number(result?.pollAfterMs || 1500)); while (Date.now() - startedAt < timeoutMs) { await new Promise((resolve) => setTimeout(resolve, pollAfterMs)); const statusResponse = await fetch(`${params.endpoint}?${pollingParams.toString()}`, { method: "GET", cache: "no-store", }); const statusPayload = await safeParseJson(statusResponse); if (!statusResponse.ok) { throw buildTaskError(statusPayload, "查询任务状态失败"); } if (!isProcessingPayload(statusPayload)) { return statusPayload as LongTaskResponse; } pollAfterMs = Math.max(800, Number(statusPayload?.pollAfterMs || pollAfterMs)); } throw new Error("任务处理超时,请稍后再试"); }