fix: 优化生成接口错误信息,将技术状态机术语改为用户友好提示
CI/CD Pipeline / Frontend Lint (push) Failing after 28h9m33s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 28h9m34s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1686h44m54s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1686h44m56s
CI/CD Pipeline / Build Production Runtime Images (push) Failing after 1686h44m58s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (push) Failing after 1686h44m58s
CI/CD Pipeline / Deploy Production (push) Failing after 1687h16m24s
CI/CD Pipeline / Frontend Lint (push) Failing after 28h9m33s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 28h9m34s
CI/CD Pipeline / Production Browser E2E (push) Failing after 1686h44m54s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 1686h44m56s
CI/CD Pipeline / Build Production Runtime Images (push) Failing after 1686h44m58s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (push) Failing after 1686h44m58s
CI/CD Pipeline / Deploy Production (push) Failing after 1687h16m24s
- edit_plan_service.py: can_generate() 错误信息改为'请先编辑并保存模板后再生成视频' - edit_plans.py: 7处错误信息改为用户友好中文提示,不再暴露内部状态名和异常类型 - test_edit_plan_generation_api.py: 更新3个测试用例以匹配新的用户友好错误信息 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -200,9 +200,9 @@ def _check_project_access(project_id: str, user_id: str, project_repository: Any
|
||||
return
|
||||
project = project_repository.find_by_id(project_id)
|
||||
if project is None:
|
||||
raise HTTPException(status_code=404, detail=f"Project {project_id} not found")
|
||||
raise HTTPException(status_code=404, detail="项目不存在")
|
||||
if not project.can_access(user_id):
|
||||
raise HTTPException(status_code=403, detail="Access denied to project")
|
||||
raise HTTPException(status_code=403, detail="无权访问该项目")
|
||||
|
||||
|
||||
def _to_response(p: EditPlan) -> EditPlanResponse:
|
||||
@@ -253,7 +253,7 @@ def list_plans(
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=(f"无效的状态值: {status_filter}," f"可选值: draft, editing, rendering, completed, failed"),
|
||||
detail="无效的筛选条件,请选择正确的状态",
|
||||
)
|
||||
|
||||
# 项目鉴权:如果指定了 project_id,校验用户是否有权访问
|
||||
@@ -379,7 +379,7 @@ def update_plan(
|
||||
except ValueError:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=(f"无效的状态值: {body.status}," f"可选值: draft, editing, rendering, completed, failed"),
|
||||
detail="无效的状态值,请选择正确的状态",
|
||||
)
|
||||
svc.transition_status(plan_id, target_status)
|
||||
except ValueError as exc:
|
||||
@@ -524,7 +524,7 @@ def generate_plan(
|
||||
logger.warning("标记计划失败状态时异常: plan_id=%s", plan_id)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"触发生成失败: {type(exc).__name__}: {exc}",
|
||||
detail="生成失败,请稍后重试",
|
||||
)
|
||||
|
||||
|
||||
@@ -672,7 +672,7 @@ def ai_recommend_clips(
|
||||
if plan_status not in ("draft", "editing"):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"AI 推荐仅支持 draft/editing 状态的计划,当前状态: {plan_status}",
|
||||
detail="当前计划状态不支持AI推荐,请先创建或编辑计划后再试",
|
||||
)
|
||||
|
||||
# 调用 AI 推荐服务(同步调用 stub,后续改为 Celery 异步)
|
||||
@@ -723,7 +723,7 @@ def ai_recommend_clips(
|
||||
pass
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"AI 推荐结果写入失败: {exc}",
|
||||
detail="AI推荐结果保存失败,请稍后重试",
|
||||
)
|
||||
|
||||
logger.info(
|
||||
|
||||
@@ -447,7 +447,7 @@ class EditPlanService:
|
||||
|
||||
# 检查状态
|
||||
if plan.status != EditPlanStatus.EDITING:
|
||||
return False, f"只有 editing 状态的计划可以触发渲染,当前状态: {plan.status}"
|
||||
return False, "请先编辑并保存模板后再生成视频"
|
||||
|
||||
# 检查是否有片段
|
||||
clips = self._clip_repo.list_by_plan(plan_id)
|
||||
|
||||
@@ -337,12 +337,12 @@ class TestGeneratePlan:
|
||||
client: TestClient,
|
||||
plan_repo: StubEditPlanRepository,
|
||||
) -> None:
|
||||
"""draft 状态 → 400"""
|
||||
"""draft 状态 → 400 + 用户友好的错误信息"""
|
||||
plan = _make_plan(status=EditPlanStatus.DRAFT)
|
||||
plan_repo.create(plan)
|
||||
resp = client.post(f"/api/v1/edit-plans/{plan.id}/generate")
|
||||
assert resp.status_code == 400
|
||||
assert "editing" in resp.json()["detail"]
|
||||
assert "请先编辑并保存模板后再生成视频" in resp.json()["detail"]
|
||||
|
||||
def test_generate_wrong_status_rendering(
|
||||
self,
|
||||
@@ -601,7 +601,7 @@ class TestGeneratePlanErrorHandling:
|
||||
plan_repo: StubEditPlanRepository,
|
||||
clip_repo: StubEditPlanClipRepository,
|
||||
) -> None:
|
||||
"""核心流程抛异常 → 500 + 明确错误信息(非裸 500)"""
|
||||
"""核心流程抛异常 → 500 + 用户友好的错误信息(不暴露技术细节)"""
|
||||
plan = _make_plan(status=EditPlanStatus.EDITING)
|
||||
plan_repo.create(plan)
|
||||
clip = _make_clip(plan.id, order=1)
|
||||
@@ -614,10 +614,10 @@ class TestGeneratePlanErrorHandling:
|
||||
|
||||
assert resp.status_code == 500
|
||||
data = resp.json()
|
||||
# 验证返回了明确的错误信息,包含异常类型和描述
|
||||
assert "触发生成失败" in data["detail"]
|
||||
assert "RuntimeError" in data["detail"]
|
||||
assert "Redis 连接超时" in data["detail"]
|
||||
# 验证返回了用户友好的错误信息,不暴露技术细节
|
||||
assert "生成失败" in data["detail"]
|
||||
assert "RuntimeError" not in data["detail"]
|
||||
assert "Redis" not in data["detail"]
|
||||
|
||||
def test_generate_error_rolls_back_plan_status(
|
||||
self,
|
||||
@@ -640,13 +640,13 @@ class TestGeneratePlanErrorHandling:
|
||||
updated = plan_repo.get(plan.id)
|
||||
assert updated.status == EditPlanStatus.FAILED
|
||||
|
||||
def test_generate_error_detail_includes_exception_type(
|
||||
def test_generate_error_detail_is_user_friendly(
|
||||
self,
|
||||
client: TestClient,
|
||||
plan_repo: StubEditPlanRepository,
|
||||
clip_repo: StubEditPlanClipRepository,
|
||||
) -> None:
|
||||
"""错误信息包含异常类型名,方便前端/运维定位"""
|
||||
"""错误信息对用户友好,不暴露技术细节(异常类型、内部错误信息)"""
|
||||
plan = _make_plan(status=EditPlanStatus.EDITING)
|
||||
plan_repo.create(plan)
|
||||
clip = _make_clip(plan.id, order=1)
|
||||
@@ -658,5 +658,8 @@ class TestGeneratePlanErrorHandling:
|
||||
|
||||
assert resp.status_code == 500
|
||||
detail = resp.json()["detail"]
|
||||
assert "ConnectionError" in detail
|
||||
assert "Broker 不可达" in detail
|
||||
# 验证不暴露技术细节
|
||||
assert "ConnectionError" not in detail
|
||||
assert "Broker 不可达" not in detail
|
||||
# 验证返回了用户友好的提示
|
||||
assert "生成失败" in detail
|
||||
|
||||
Reference in New Issue
Block a user