fix: 统一AI生成失败提示

This commit is contained in:
hh
2026-07-15 13:12:35 +08:00
parent 38d8c8ad54
commit e81d7170ed
19 changed files with 1220 additions and 88 deletions
+97
View File
@@ -0,0 +1,97 @@
/**
* AI 生成失败的普通用户展示层。
*
* 页面只消费这里的稳定 code,不解析供应商名称、HTTP 状态、URL 或英文异常。
* 本文件不发请求、不依赖 React,后续脚本/图片/视频页面可按需接入。
*/
export type GenerationOperation =
| "script_generate"
| "image_generate"
| "base_asset_generate"
| "triview_generate"
| "storyboard_generate"
| "video_generate"
| "voiceover_generate"
| "entity_extract";
export type GenerationErrorCode =
| "provider_quota_exhausted"
| "provider_rate_limited"
| "provider_unavailable"
| "provider_config_error"
| "model_unavailable"
| "content_rejected"
| "invalid_input"
| "asset_unavailable"
| "user_credit_insufficient"
| "task_timeout"
| "processing_failed"
| "unknown";
export type GenerationErrorAction = "retry" | "retry_later" | "revise_input" | "recharge" | "contact_support" | "none";
export type PublicGenerationError = {
domain: "generation";
code: GenerationErrorCode;
operation: GenerationOperation;
action: GenerationErrorAction;
retryable: boolean;
reference_id?: string;
};
export type GenerationErrorPresentation = {
title: string;
description: string;
action: GenerationErrorAction;
retryable: boolean;
referenceId?: string;
};
const OPERATION_LABEL: Record<GenerationOperation, string> = {
script_generate: "脚本",
image_generate: "图片",
base_asset_generate: "基础素材",
triview_generate: "三视图",
storyboard_generate: "故事板",
video_generate: "视频",
voiceover_generate: "配音",
entity_extract: "脚本信息"
};
type Copy = (operation: string) => Pick<GenerationErrorPresentation, "title" | "description">;
const ERROR_COPY: Record<GenerationErrorCode, Copy> = {
provider_quota_exhausted: (operation) => ({ title: `${operation}暂时不可用`, description: "生成服务正在处理中,请稍后再试。" }),
provider_rate_limited: (operation) => ({ title: `${operation}请求较多`, description: "当前生成请求较多,请稍后再试。" }),
provider_unavailable: (operation) => ({ title: `${operation}暂时不可用`, description: "生成服务暂时不可用,请稍后重试。" }),
provider_config_error: (operation) => ({ title: `${operation}暂时不可用`, description: "平台正在处理该问题,请稍后再试。" }),
model_unavailable: (operation) => ({ title: `${operation}暂时不可用`, description: "当前生成能力暂不可用,请稍后再试。" }),
content_rejected: (operation) => ({ title: `${operation}内容需要调整`, description: "内容未通过生成审核,请调整描述或素材后重试。" }),
invalid_input: (operation) => ({ title: `${operation}内容需检查`, description: "请检查描述、参数或素材格式后重试。" }),
asset_unavailable: () => ({ title: "素材暂不可用", description: "引用的素材不存在或暂不可用,请更换后重试。" }),
user_credit_insufficient: () => ({ title: "可用积分不足", description: "充值后可继续生成。" }),
task_timeout: (operation) => ({ title: `${operation}生成时间过长`, description: "服务响应较慢,未完成生成,请重试。" }),
processing_failed: (operation) => ({ title: `${operation}结果处理失败`, description: "本次未生成可用结果,请重试。" }),
unknown: (operation) => ({ title: `${operation}遇到问题`, description: "请稍后重试;若多次出现,请提供任务编号以便排查。" })
};
export function isPublicGenerationError(value: unknown): value is PublicGenerationError {
if (!value || typeof value !== "object") return false;
const candidate = value as Partial<PublicGenerationError>;
return candidate.domain === "generation"
&& typeof candidate.code === "string" && Object.hasOwn(ERROR_COPY, candidate.code)
&& typeof candidate.operation === "string" && Object.hasOwn(OPERATION_LABEL, candidate.operation)
&& typeof candidate.action === "string"
&& typeof candidate.retryable === "boolean";
}
export function presentGenerationError(error: PublicGenerationError): GenerationErrorPresentation {
const copy = ERROR_COPY[error.code] ?? ERROR_COPY.unknown;
return {
...copy(OPERATION_LABEL[error.operation] ?? "生成"),
action: error.action,
retryable: error.retryable,
referenceId: error.reference_id
};
}