fix(media): 创作结果恢复与等待上限 - 长视频不再误判失败 (#665)
* fix(media): 创作结果恢复 - 结果定位符缺失时回退到任务结果 首页创作生成的图片/视频在本地素材索引尚未同步时(物化结果幂等命中、换标签页、 素材同步延迟)会被收敛成“任务已结束,但生成结果暂时无法读取”:结果定位符只查 本地素材 store,查不到就返回空,于是结果既不挂载也不显示,而服务端其实已经成功。 - generationTaskMaterializedStorageKeys 在本地查不到素材时回退到结果自带的 providerArtifactRef(resource:<id>),展示地址仍由渲染层按需续签; - 携带过期签名的历史地址不再直接交给 <img>/<video>,避免首帧 403 空白。 * fix(media): 前端等待上限对齐后端超时 - 长视频不再被前端误判失败 视频任务的前端等待上限写死 32 分钟,而后端视频超时默认 60 分钟(现网配到 120 分钟)、 上游 30 秒档常态 35-45 分钟。结果:任务在后端正常跑并最终成功,前端先报 “任务执行超时,请稍后重试”,消息被标成失败;而失败态消息不会被恢复流程接管 (isRecoverableCreationMessage 只认 pending),用户看到的就是“失败”且视频永远不显示。 - taskWaitTimeoutMs:视频 32 → 125 分钟、分镜 13 → 25 分钟,都不小于后端同类超时; - isRecoverableCreationMessage:媒体消息的失败态也纳入恢复,任务确实失败时收敛结果不变, 任务其实成功时把结果补回消息。 --------- Co-authored-by: xiaomuclaw <282836183+xiaomuclaw@users.noreply.github.com>
This commit is contained in:
@@ -537,8 +537,10 @@ async function taskTextStreamHTTPError(response: Response) {
|
||||
|
||||
function taskWaitTimeoutMs(task?: GenerationTask) {
|
||||
const type = task?.type || "";
|
||||
if (type.includes("storyboard")) return 13 * 60 * 1000;
|
||||
if (type.includes("video")) return 32 * 60 * 1000;
|
||||
// 等待上限必须不小于后端同类任务的执行超时(分镜 20 分钟、视频 120 分钟,见后台
|
||||
// 资源与策略),否则长任务会在前端被判超时、消息显示失败,而后端其实还在跑并最终成功。
|
||||
if (type.includes("storyboard")) return 25 * 60 * 1000;
|
||||
if (type.includes("video")) return 125 * 60 * 1000;
|
||||
if (type.includes("image")) return 10 * 60 * 1000;
|
||||
if (type.includes("text") || type.includes("audio")) return 12 * 60 * 1000;
|
||||
return 10 * 60 * 1000;
|
||||
|
||||
@@ -30,7 +30,10 @@ export function removeCreationConversationSnapshot<T extends { id: string }>(con
|
||||
|
||||
function isRecoverableCreationMessage(message: PendingCreationMessage) {
|
||||
if (message.role !== "assistant" || !message.taskIds?.length) return false;
|
||||
return message.mode === "text" ? message.status === "streaming" || message.status === "pending" : message.status === "pending";
|
||||
if (message.mode === "text") return message.status === "streaming" || message.status === "pending";
|
||||
// 媒体消息的前端等待可能先于后端结束(例如长视频),消息被判失败但任务其实已经成功。
|
||||
// 失败态一并纳入恢复:任务确实失败时收敛结果不变,任务成功时把结果补回消息。
|
||||
return message.status === "pending" || message.status === "error";
|
||||
}
|
||||
|
||||
export function pendingCreationTaskKey(conversations: StoredCreationConversation[]) {
|
||||
|
||||
@@ -571,7 +571,11 @@ export function generationTaskMaterializedStorageKeys(task: GenerationTask): str
|
||||
const assets = useAssetStore.getState().assets;
|
||||
return (task.outputs || []).flatMap((output) => {
|
||||
const asset = output.materializedAssetId ? assets.find((candidate) => candidate.id === output.materializedAssetId) : undefined;
|
||||
if (!asset || (asset.kind !== "image" && asset.kind !== "video" && asset.kind !== "audio")) return [];
|
||||
return asset.data.storageKey ? [asset.data.storageKey] : [];
|
||||
const storageKey = asset && (asset.kind === "image" || asset.kind === "video" || asset.kind === "audio") ? asset.data.storageKey : "";
|
||||
if (storageKey) return [storageKey];
|
||||
// 物化结果复用时(幂等命中、换标签页、素材尚未同步)本地索引里可能没有这条素材,
|
||||
// 结果自己带着稳定的 resource:<id>;丢掉它会把已经生成成功的结果判成无法读取,
|
||||
// 展示地址随后仍由渲染层按需续签。
|
||||
return output.providerArtifactRef ? [output.providerArtifactRef] : [];
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user