fix(assets): smart-match 响应扁平化修复自动选素材 404/422 全链路断裂 #1565
Reference in New Issue
Block a user
Delete Branch "fix/smart-match-flatten"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
P0:smart-match 返回结构扁平化,修复 AI 自动选素材全链路断裂
线上现象(staging)
GET /api/v1/assets/undefined404 连发 3 次POST /api/v1/templates/{id}/clips/from-assets422根因
POST /assets/smart-match返回SmartMatchItem{asset: AssetResponse, score, breakdown}——素材字段包在item.asset里;前端smartMatchAssets声明Promise<{items: AssetItem[]}>,items.map(a => a.id)取到的全是undefined。修复
SmartMatchItem扁平化(schemas/asset.py):改为继承AssetResponse,id / usable / used_duration / available_duration / used_ratio / duration / mime_type / thumbnail_url等素材字段全部在 item 顶层,前端拿到即可读;score / breakdown评分字段保留。packages.domain.smart_match.smart_select_assets的SmartMatchResult.asset保持原样,generation_tasks.py内部生成链路([r.asset.id for r in results])零影响。ClipsFromAssetsRequest增加 pre-validator 过滤null/空串/空白id(undefined 经 JSON 序列化为 null 直接 422);路由层二次归一化兜底,全非法时 400「素材列表为空」而非 422/500。响应结构(最终,前端以此为准)
items 元素与
GET /assets列表项(AssetResponse)字段完全一致,仅多score/breakdown;无asset包装层。测试
asset包装、余量/usable 字段可读、score/breakdown 保留item["id"]/"asset" not in item)🚀 预览环境已部署
CI全绿,自动审批通过。
CI全绿,自动审批通过。
7546a416feto84252238cfP0 线上事故:前端 smartMatchAssets 按 {items: AssetItem[]} 解析, items.map(a => a.id) 直接取 id;但后端 SmartMatchItem 为 {asset: AssetResponse, score, breakdown} 包装结构,导致 id 全为 undefined → GET /assets/undefined 404 连发、POST /clips/from-assets 携带 null 422,自动模式预览无法生成、标题不显示。 修复: - SmartMatchItem 改为继承 AssetResponse 的扁平结构:id/usable/ used_duration/available_duration/used_ratio 等素材字段全部在 item 顶层,前端拿到即可用;score/breakdown 评分字段保留 - 路由用 model_dump() 解包构造,packages.domain.smart_select_assets 域层 SmartMatchResult.asset 不动,generation_tasks 内部生成链路 ([r.asset.id for r in results])零影响 - ClipsFromAssetsRequest 加 pre validator 过滤 null/空串/空白 id; from-assets 路由层二次归一化兜底,全非法时 400 而非 422/500 测试:扁平结构 3 用例(顶层 id/无 asset 包装/余量字段可读/评分保留)、 端点 TestClient 断言更新、from-assets 容错 4 用例;相关 95 用例全过84252238cfto90e6beea79【阻塞级判定】
📊 审查概览
🔴 阻塞级问题(必须修复)
无
💡 改进建议(不阻塞合并)
[apps/api/app/api/routes/templates_editor/clips.py: 596] 建议拆分长行或提取变量
asset_ids的列表推导式逻辑较长(包含类型判断、去空、strip),且aid.strip()被调用了两次。建议提取为局部函数或拆分写法以提高可读性和微小的性能优化。[apps/api/app/api/routes/templates_editor/clips.py: 405] 建议保持代码可读性
_safe_segment_duration的调用参数较多,压缩为一行可能会影响部分场景下的断点调试和可读性。建议保持多行格式,除非团队有严格的行数限制。✅ 良好实践
schemas.py中增加pre=True的 validator 过滤无效 ID,并在clips.py路由层再次进行防御性检查,有效防止了前端传入null/undefined导致的后续 404 或 500 错误。SmartMatchItem继承AssetResponse并使用model_dump()展开字段,消除了前端访问item.asset.id的嵌套层级,优化了 API 响应结构,符合 RESTful 最佳实践。TestClipsFromAssetsInvalidIds,TestSmartMatchFlatStructure),确保了重构的正确性。✅ 格式检查通过 | ✅ 逻辑审查通过 | ✅ 性能无明显问题
🤖 由 AI 代码审查机器人自动生成 | 2026-08-31 05:18:12 | 模型:
🗑️ 预览环境已清理
PR #1565 已关闭或合并,对应的预览环境已被清理。