/** * Translate API error messages to user-friendly Chinese. * * Classifies errors into categories and provides user-friendly messages * with suggested recovery actions. */ export type TaskErrorCategory = | "content_policy" | "auth_failure" | "insufficient_balance" | "unsupported_model" | "concurrency_busy" | "invalid_asset" | "network_failure" | "timeout" | "cancelled" | "unknown"; export interface TaskErrorInfo { category: TaskErrorCategory; message: string; action: string; } const ERROR_RULES: Array<{ pattern: RegExp; category: TaskErrorCategory; message: string; action: string; }> = [ // Content policy { pattern: /violated? our (?:relevant )?policies|content policies|violated? content policy|content.*filter|safety.*filter|moderation|blocked by.*filter|nsfw|inappropriate|explicit.*content|adult.*content/i, category: "content_policy", message: "输入词汇包含违规信息,已停止生成", action: "修改提示词后重试", }, // Auth failure { pattern: /unauthorized|authentication.*fail|invalid.*token|token.*expired|session.*expired|401|login.*required/i, category: "auth_failure", message: "登录已过期,请重新登录", action: "重新登录", }, // Insufficient balance { pattern: /insufficient.*balance|余额不足|积分不足|INSUFFICIENT_BALANCE|balance.*not.*enough|402/i, category: "insufficient_balance", message: "余额不足,请充值后重试", action: "去充值", }, // Concurrency busy { pattern: /concurrency pool.*full|pool is full|concurrency.*limit|too many.*concurrent|排队繁忙/i, category: "concurrency_busy", message: "当前模型排队繁忙,请稍后重试或切换其他模型", action: "稍后重试或切换模型", }, // Rate limit { pattern: /rate limit|too many requests|429/i, category: "concurrency_busy", message: "请求过于频繁,请稍后再试", action: "稍后重试", }, // Unsupported model { pattern: /unsupported.*model|model.*not.*support|model.*not.*found|ENTERPRISE_VIDEO_MODEL_NOT_ALLOWED|not.*available/i, category: "unsupported_model", message: "当前模型暂不可用,请切换其他模型重试", action: "切换模型", }, // Invalid asset / upload { pattern: /upload.*fail|asset.*fail|素材|invalid.*image|invalid.*video|file.*too.*large/i, category: "invalid_asset", message: "素材上传失败,请重新上传后重试", action: "重新上传素材", }, // Network failure { pattern: /network|connection|fetch failed|ECONNREFUSED|ENOTFOUND|socket.*hang/i, category: "network_failure", message: "网络错误,请检查网络后重试", action: "检查网络后重试", }, // Timeout { pattern: /timeout|timed? out|ETIMEDOUT/i, category: "timeout", message: "任务超时,请稍后在任务历史中查看结果", action: "稍后重试", }, // Quota exceeded { pattern: /quota exceeded|quota.*limit/i, category: "insufficient_balance", message: "配额已用完,请联系管理员", action: "联系管理员", }, // Cancelled { pattern: /cancelled|已取消/i, category: "cancelled", message: "已取消", action: "重新开始", }, // All providers failed { pattern: /all.*providers.*failed|provider.*fail/i, category: "concurrency_busy", message: "所有可用模型均暂时不可用,请稍后重试", action: "稍后重试", }, // Upstream / service error { pattern: /upstream.*error|文本服务返回|服务返回.*HTTP|openai_error|internal.*server.*error|500|502|503/i, category: "network_failure", message: "AI 服务暂时不可用,请稍后重试", action: "稍后重试", }, // Access denied / forbidden { pattern: /access.*denied|forbidden|403|permission.*denied|权限/i, category: "auth_failure", message: "模型权限未开通,请联系管理员", action: "联系管理员", }, // Image format / size issues { pattern: /image.*too.*large|image.*format|图片.*大小|图片.*格式|invalid.*file.*type/i, category: "invalid_asset", message: "图片格式或大小不符合要求,请调整后重试", action: "调整图片后重试", }, // Aborted (user or timeout abort) { pattern: /aborted|abort/i, category: "timeout", message: "请求已中断,请重试", action: "重试", }, ]; /** * Classify an API error into a structured result with category, message, and action. */ export function classifyTaskError(error: string | undefined | null): TaskErrorInfo { if (!error) { return { category: "unknown", message: "任务失败,请重试", action: "重试" }; } for (const rule of ERROR_RULES) { if (rule.pattern.test(error)) { return { category: rule.category, message: rule.message, action: rule.action }; } } const hasChinese = /[一-鿿]/.test(error); if (hasChinese) { const truncated = error.length > 80 ? `${error.slice(0, 80)}...` : error; return { category: "unknown", message: truncated, action: "重试" }; } return { category: "unknown", message: "服务异常,请稍后重试", action: "重试" }; } /** * Translate an API error message to a user-friendly Chinese message. * Convenience wrapper around classifyTaskError. */ export function translateTaskError(error: string | undefined | null): string { return classifyTaskError(error).message; }