From d00d63f14d39004a0993113068fae13f56382adb Mon Sep 17 00:00:00 2001 From: Xiaoxia AI Date: Mon, 22 Jun 2026 22:57:07 +0800 Subject: [PATCH] fix(web): humanize generation failure messages --- .../src/pages/workspace/ProjectGeneration.tsx | 66 +++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/apps/web/src/pages/workspace/ProjectGeneration.tsx b/apps/web/src/pages/workspace/ProjectGeneration.tsx index 382a4650f..ed8f91b44 100644 --- a/apps/web/src/pages/workspace/ProjectGeneration.tsx +++ b/apps/web/src/pages/workspace/ProjectGeneration.tsx @@ -4,8 +4,41 @@ import { Alert, Button, Card, Form, Input, Select, Space, Typography, message } import { useMutation, useQuery } from '@tanstack/react-query'; import { createGenerationTask, getGenerationResults, getGenerationTask } from '@/api/generation'; import { getAssetLibraries } from '@/api/assets'; +import { getProject } from '@/api/projects'; import { useAuthStore } from '@/store/authStore'; +const humanizeGenerationStatus = (status: string) => { + const labels: Record = { + pending: '排队中', + running: '生成中', + completed: '生成完成', + failed: '生成失败', + cancelled: '已取消', + }; + return labels[status] || status; +}; + +const humanizeGenerationError = (errorMessage?: string | null) => { + const raw = (errorMessage || '').trim(); + if (!raw) { + return '生成失败了,但系统没有返回具体原因。请重新发起一次;如果还失败,把项目和素材库发给小虾排查。'; + } + const lower = raw.toLowerCase(); + if (lower.includes('ffmpeg') || lower.includes('ffprobe') || lower.includes('invalid data') || lower.includes('moov atom')) { + return '视频素材格式无法被系统识别。请换一个常见 MP4/H.264 文件,或先用剪映/播放器重新导出后再上传。'; + } + if (lower.includes('oss') || lower.includes('bucket') || lower.includes('accesskey') || lower.includes('storage')) { + return '素材存储服务暂时异常,系统没能读取或保存文件。请稍后重试;如果持续失败,让小虾检查 OSS 配置。'; + } + if (lower.includes('not found') || lower.includes('no such file')) { + return '系统找不到要生成的视频素材。请确认素材已经上传并导入完成,再重新生成。'; + } + if (lower.includes('permission') || lower.includes('forbidden') || lower.includes('unauthorized')) { + return '当前账号没有这个项目或素材库的操作权限。请回到工作空间确认登录账号和权限。'; + } + return `生成失败:${raw}`; +}; + const ProjectGeneration: React.FC = () => { const { id } = useParams<{ id: string }>(); const location = useLocation(); @@ -13,16 +46,33 @@ const ProjectGeneration: React.FC = () => { const projectId = id || ''; const routedWorkspaceId = (location.state as { workspaceId?: string } | null)?.workspaceId || ''; const storedWorkspaceId = projectId ? sessionStorage.getItem(`project-workspace:${projectId}`) || '' : ''; - const workspaceId = routedWorkspaceId || storedWorkspaceId; + const [resolvedWorkspaceId, setResolvedWorkspaceId] = useState(routedWorkspaceId || storedWorkspaceId); + const workspaceId = routedWorkspaceId || storedWorkspaceId || resolvedWorkspaceId; const [taskId, setTaskId] = useState(''); const [form] = Form.useForm(); useEffect(() => { if (projectId && routedWorkspaceId) { sessionStorage.setItem(`project-workspace:${projectId}`, routedWorkspaceId); + setResolvedWorkspaceId(routedWorkspaceId); } }, [projectId, routedWorkspaceId]); + const projectQuery = useQuery({ + queryKey: ['project', projectId], + queryFn: () => getProject(projectId), + enabled: !!projectId && !workspaceId, + retry: false, + }); + + useEffect(() => { + const projectWorkspaceId = projectQuery.data?.workspace_id; + if (projectId && projectWorkspaceId) { + sessionStorage.setItem(`project-workspace:${projectId}`, projectWorkspaceId); + setResolvedWorkspaceId(projectWorkspaceId); + } + }, [projectId, projectQuery.data?.workspace_id]); + const librariesQuery = useQuery({ queryKey: ['generation-libraries', projectId], queryFn: () => getAssetLibraries(projectId), @@ -51,7 +101,7 @@ const ProjectGeneration: React.FC = () => { setTaskId(task.id); message.success('生成任务已创建'); }, - onError: (error: any) => message.error(error.response?.data?.detail || '创建生成任务失败'), + onError: (error: any) => message.error(humanizeGenerationError(error.response?.data?.detail || '创建生成任务失败')), }); useEffect(() => { @@ -70,6 +120,10 @@ const ProjectGeneration: React.FC = () => { [librariesQuery.data] ); + const failedReason = taskQuery.data?.status === 'failed' + ? humanizeGenerationError(taskQuery.data.error_message) + : ''; + return (
@@ -127,8 +181,12 @@ const ProjectGeneration: React.FC = () => { )}