D158 · 会话收尾 · 进度+脚本+QC报告入库(不含候选图)
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled
铸渊自检 / health-check (push) Has been cancelled

- CURRENT-STATE 更新至D158
- 生成脚本: char004/char004_r3/prop002/prop002_r3/prop003 全量
- QC脚本: qc_char004_r2/r3 + qc_prop_r2
- QC报告: CHAR-004 R2~R5 + PROP全量
- generation-meta: 所有候选批次元数据
- 候选图(JPG)保留本地不入库
This commit is contained in:
冰朔 2026-07-02 01:07:43 +08:00
parent 802435ed7b
commit c81307004d
21 changed files with 1624 additions and 12 deletions

View File

@ -1,7 +1,7 @@
# [VA-04] CURRENT.hdlp · 视频AI系统 · 当前状态快照
> HLDP://video-ai-system/CURRENT
> 铸渊 ICE-GL-ZY001 · D157 · 2026-07-01
> 铸渊 ICE-GL-ZY001 · D158 · 2026-07-02
> 国作登字-2026-A-00037559
---
@ -22,22 +22,44 @@
| 项目 | 状态 |
|------|:----:|
| 剧本完整度 | 75集 ✅ |
| 第1集 | 🟡 CHAR-004已入库·CHAR-003/005+场景道具待处理 |
| 新增正式资产 | 1 · CHAR-004诸葛风V1 ✅ |
| 上一回执 | D157-CHAR-004-INGEST · 2026-07-01 |
| 第1集 | 🟡 3项资产已确认·PROP-002待修正·其余待处理 |
| 新增正式资产 | 3 · CHAR-004+PROP-003+CHAR-004确认待入库 |
| 上一回执 | D158-SESSION · 2026-07-02 |
| 铸渊武器状态 | 全部就绪 ✅ |
| 🔴 已知问题 | Qwen-VL SC-004密钥过期(AccessDenied) |
---
## 做到哪了
```
⊢ CHAR-004诸葛风V1正式入库(剧本锚定版R5候选②·18岁淳朴粗麻白衣)
⊢ 五轮迭代(R1→R5)完成:图生图→灰蓝乞丐→粗麻→制服→剧本锚定
⊢ CHAR-003候选3仅为临时参考·待重做
⊢ CHAR-005、ENV-002/003/004、PROP-002/003 仍为待人工查看候选
⊢ 入库回执: experience/D157-CHAR-004-INGEST.hdlp
⊢ 闸门0规则已封装: 生成前必须先比对剧本原文
⊢ CHAR-004诸葛风V1 ✅ 确认 — R5候选②(18岁淳朴粗麻白衣)
⊢ PROP-003免费招徒广告牌V1 ✅ 确认 — R2候选③(绳系A架·修仙摊位)
⊢ PROP-002天道宗牌匾 🟡 — R3方向对了(破旧木板·摊位招牌)
但牌子全是直立摆放——应是靠在摊位桌上/斜放的临时招牌
明天修正R4:prompt锁定"平放在桌上"或"斜靠在摊位旁"
⊢ CHAR-003苏白 → 待重做(作为风格基准)
⊢ CHAR-005王执事 → 候选待审核
⊢ ENV-002/003/004 → 场景候选待审核
⊢ D158霜砚工单全部处理完成
```
---
## D158 霜砚工单完成(2026-07-02 00:30)
```
⊢ 🔴 Nginx签名验证通道 — 完成
部署 auth-verify-server.py(PM2·port 3906)
Nginx /code/ 路径加 auth_request + 签名验证
测试: 正确token→200 / 无签名→403 / 错误→403
API token: fff703aca852e88f77f5969d93ac43c060abf504
⊢ 🟡 灯塔仓库入口基础设施 — 完成
Forgejo app.ini 启用 Wiki/Issues/PR/Projects
Forgejo重启正常服务
⊢ 🟡 清源QY-GATE v2.0 — 清源自行完成,跳过
```
---
@ -45,7 +67,8 @@
## 铸渊现在能做什么(一句话)
```
⊢ CHAR-004已入库。下一步:处理CHAR-005+场景道具候选或重做CHAR-003。
⊢ 明天优先:PROP-002 R4修正立牌问题 + CHAR-003苏白重做。
其余CHAR-005/ENV-002~004候选等冰朔审核。
```
---
@ -62,7 +85,7 @@
## ⏭️ 下一步
冰朔定优先级:CHAR-003重做 / CHAR-005+场景道具审核 / 继续其他资产。
冰朔定优先级:PROP-002 R4修正 / CHAR-003苏白重做 / 其余资产审核。
---
> ⊢ VA-04(本体)→ VX-05(跳转)→ VA-05(目标)

View File

@ -0,0 +1,35 @@
{
"spec": "PROP-002-R2",
"ts": "20260701-221314",
"ok": 4,
"results": [
{
"c": 1,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R2/20260701-221314/PROP-002-R2-01-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/PROP-002-R2-candidate-01-1080x1920.jpg",
"seed": 10
},
{
"c": 2,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R2/20260701-221314/PROP-002-R2-02-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/PROP-002-R2-candidate-02-1080x1920.jpg",
"seed": 20
},
{
"c": 3,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R2/20260701-221314/PROP-002-R2-03-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/PROP-002-R2-candidate-03-1080x1920.jpg",
"seed": 30
},
{
"c": 4,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R2/20260701-221314/PROP-002-R2-04-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/PROP-002-R2-candidate-04-1080x1920.jpg",
"seed": 40
}
]
}

View File

@ -0,0 +1,35 @@
{
"spec": "PROP-002-R3",
"ts": "20260702-000635",
"ok": 4,
"results": [
{
"c": 1,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R3/20260702-000635/PROP-002-R3-01-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/PROP-002-R3-candidate-01-1080x1920.jpg",
"seed": 11
},
{
"c": 2,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R3/20260702-000635/PROP-002-R3-02-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/PROP-002-R3-candidate-02-1080x1920.jpg",
"seed": 21
},
{
"c": 3,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R3/20260702-000635/PROP-002-R3-03-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/PROP-002-R3-candidate-03-1080x1920.jpg",
"seed": 31
},
{
"c": 4,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-002-R3/20260702-000635/PROP-002-R3-04-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/PROP-002-R3-candidate-04-1080x1920.jpg",
"seed": 41
}
]
}

View File

@ -0,0 +1,35 @@
{
"spec": "PROP-003-R2",
"ts": "20260701-221334",
"ok": 4,
"results": [
{
"c": 1,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-003-R2/20260701-221334/PROP-003-R2-01-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/PROP-003-R2-candidate-01-1080x1920.jpg",
"seed": 50
},
{
"c": 2,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-003-R2/20260701-221334/PROP-003-R2-02-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/PROP-003-R2-candidate-02-1080x1920.jpg",
"seed": 60
},
{
"c": 3,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-003-R2/20260701-221334/PROP-003-R2-03-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/PROP-003-R2-candidate-03-1080x1920.jpg",
"seed": 70
},
{
"c": 4,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/PROP-003-R2/20260701-221334/PROP-003-R2-04-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/PROP-003-R2-candidate-04-1080x1920.jpg",
"seed": 80
}
]
}

View File

@ -0,0 +1,70 @@
{
"PROP-002": [
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-002-R2-candidate-01-1080x1920.jpg"
},
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-002-R2-candidate-02-1080x1920.jpg"
},
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-002-R2-candidate-03-1080x1920.jpg"
},
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-002-R2-candidate-04-1080x1920.jpg"
}
],
"PROP-003": [
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-003-R2-candidate-01-1080x1920.jpg"
},
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-003-R2-candidate-02-1080x1920.jpg"
},
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-003-R2-candidate-03-1080x1920.jpg"
},
{
"score": 0,
"verdict": "FAIL",
"issues": [
"API错误: 'output'"
],
"_file": "PROP-003-R2-candidate-04-1080x1920.jpg"
}
]
}

View File

@ -0,0 +1,108 @@
{
"spec": "VA-05-001-R2",
"asset_id": "CHAR-004-ZhugeFeng",
"qc_tool": "Qwen-VL (qwen-vl-max)",
"results": [
{
"candidate": 4,
"pass": true,
"score": 95,
"hole_in_pants": true,
"frayed_hem": true,
"dirty_shoes": true,
"stains": true,
"patches": true,
"beggar_look": false,
"correct_top": true,
"correct_belt": true,
"correct_pants": true,
"correct_shoes": true,
"has_bag": true,
"extra_accessories": false,
"face_intact": true,
"cold_temperament": true,
"similar_to_su_bai": false,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"summary": "符合清贫少年设定,服装细节完整且合理,无多余配饰,面部冷硬气质突出,整体质量优秀"
},
{
"candidate": 4,
"pass": true,
"score": 95,
"hole_in_pants": true,
"frayed_hem": true,
"dirty_shoes": true,
"stains": true,
"patches": false,
"beggar_look": false,
"correct_top": true,
"correct_belt": true,
"correct_pants": true,
"correct_shoes": true,
"has_bag": true,
"extra_accessories": false,
"face_intact": true,
"cold_temperament": true,
"similar_to_su_bai": false,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"summary": "角色整体符合清贫少年设定,服装细节准确,无明显缺陷,仅膝盖破洞与污渍为合理设计,非乞丐化"
},
{
"candidate": 4,
"pass": true,
"score": 95,
"hole_in_pants": true,
"frayed_hem": true,
"dirty_shoes": true,
"stains": true,
"patches": true,
"beggar_look": false,
"correct_top": true,
"correct_belt": true,
"correct_pants": true,
"correct_shoes": true,
"has_bag": true,
"extra_accessories": false,
"face_intact": true,
"cold_temperament": true,
"similar_to_su_bai": false,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"summary": "符合清贫少年设定,服装细节完整且有生活感,无明显缺陷"
},
{
"candidate": 4,
"pass": true,
"score": 95,
"hole_in_pants": true,
"frayed_hem": true,
"dirty_shoes": true,
"stains": true,
"patches": false,
"beggar_look": false,
"correct_top": true,
"correct_belt": true,
"correct_pants": true,
"correct_shoes": true,
"has_bag": true,
"extra_accessories": false,
"face_intact": true,
"cold_temperament": true,
"similar_to_su_bai": false,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"summary": "整体符合清贫少年设定,服装细节真实,无多余配饰,面部气质冷硬,仅膝盖破洞和轻微污渍属合理磨损,非乞丐化"
}
],
"summary": {
"passed": 4,
"total": 4,
"verdict": "APPROVED"
}
}

View File

@ -0,0 +1,39 @@
{
"spec": "VA-05-001-R2",
"asset_id": "CHAR-004-ZhugeFeng",
"timestamp": "20260701-140007",
"model": "doubao-seedream-4-0-250828",
"resolution_raw": "1440x2560",
"resolution_final": "1080x1920",
"strategy": "pure_text_prompt_no_image_reference",
"results": [
{
"candidate": 1,
"status": "generated",
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R2/20260701-140007/CHAR-004-R2-candidate-01-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/CHAR-004-R2-candidate-01-1080x1920.jpg",
"seed": 42
},
{
"candidate": 2,
"status": "generated",
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R2/20260701-140007/CHAR-004-R2-candidate-02-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/CHAR-004-R2-candidate-02-1080x1920.jpg",
"seed": 137
},
{
"candidate": 3,
"status": "generated",
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R2/20260701-140007/CHAR-004-R2-candidate-03-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/CHAR-004-R2-candidate-03-1080x1920.jpg",
"seed": 256
},
{
"candidate": 4,
"status": "generated",
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R2/20260701-140007/CHAR-004-R2-candidate-04-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/CHAR-004-R2-candidate-04-1080x1920.jpg",
"seed": 399
}
]
}

View File

@ -0,0 +1,79 @@
{
"spec": "VA-05-001-R3",
"asset": "CHAR-004",
"tool": "qwen-vl-max",
"results": [
{
"candidate": 4,
"pass": false,
"score": 60,
"hole_in_pants": true,
"frayed_hem": true,
"dirty_shoes": false,
"stains": false,
"patches": false,
"beggar_look": true,
"face_intact": true,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"similar_to_sb": false,
"summary": "裤子膝盖有破洞且衣摆毛边明显,整体气质偏流浪感,不符合清贫但整洁的要求"
},
{
"candidate": "CHAR-004",
"pass": true,
"score": 98,
"hole_in_pants": false,
"frayed_hem": false,
"dirty_shoes": false,
"stains": false,
"patches": false,
"beggar_look": false,
"face_intact": true,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"similar_to_sb": false,
"summary": "角色造型清贫但整洁,气质有骨气,符合规范要求"
},
{
"candidate": "CHAR-004",
"pass": true,
"score": 95,
"hole_in_pants": false,
"frayed_hem": false,
"dirty_shoes": false,
"stains": false,
"patches": false,
"beggar_look": false,
"face_intact": true,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"similar_to_sb": false,
"summary": "角色整体干净整洁,符合清贫但有骨气的设定,无破洞污渍补丁,气质端正,形象完整清晰。"
},
{
"candidate": "CHAR-004",
"pass": true,
"score": 95,
"hole_in_pants": false,
"frayed_hem": false,
"dirty_shoes": false,
"stains": false,
"patches": false,
"beggar_look": false,
"face_intact": true,
"anatomy_ok": true,
"clear_image": true,
"full_body": true,
"similar_to_sb": false,
"summary": "角色形象清贫但整洁,气质有骨气,符合规范要求。"
}
],
"summary": {
"passed": 3,
"total": 4
}
}

View File

@ -0,0 +1,37 @@
{
"spec": "VA-05-001-R3",
"asset": "CHAR-004",
"ts": "20260701-142752",
"ok": 4,
"total": 4,
"results": [
{
"c": 1,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R3/20260701-142752/CHAR-004-R3-01-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/CHAR-004-R3-candidate-01-1080x1920.jpg",
"seed": 42
},
{
"c": 2,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R3/20260701-142752/CHAR-004-R3-02-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/CHAR-004-R3-candidate-02-1080x1920.jpg",
"seed": 137
},
{
"c": 3,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R3/20260701-142752/CHAR-004-R3-03-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/CHAR-004-R3-candidate-03-1080x1920.jpg",
"seed": 256
},
{
"c": 4,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R3/20260701-142752/CHAR-004-R3-04-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/CHAR-004-R3-candidate-04-1080x1920.jpg",
"seed": 399
}
]
}

View File

@ -0,0 +1,73 @@
{
"spec": "VA-05-001-R4",
"results": [
{
"candidate": "CHAR-004",
"pass": true,
"score": 98,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"neat": true,
"beggar": false,
"like_sb": false,
"face": true,
"full": true,
"summary": "整体造型朴素整洁,符合修仙学徒设定,无破损、污渍或乞丐感,布料平整干净,五官正常,全身完整。仅面部与苏白CHAR-003略有差异,不影响通过。"
},
{
"candidate": "CHAR-004",
"pass": true,
"score": 98,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"neat": true,
"beggar": false,
"like_sb": false,
"face": true,
"full": true,
"summary": "制服整洁无破损,布料平整干净,无污渍或破洞,整体呈现朴素修仙学徒风貌,无乞丐感。五官正常,全身完整,符合R4核心标准。"
},
{
"candidate": "CHAR-004",
"pass": true,
"score": 98,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"neat": true,
"beggar": false,
"like_sb": false,
"face": true,
"full": true,
"summary": "制服整洁无破损,布料平整干净,无污渍或毛边,整体呈现朴素修仙学徒风貌,无乞丐感。五官正常,全身完整。与苏白CHAR-003脸型不同。"
},
{
"candidate": "CHAR-004",
"pass": true,
"score": 98,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"neat": true,
"beggar": false,
"like_sb": false,
"face": true,
"full": true,
"summary": "制服整洁无破损,布料平整干净,无污渍或毛边,无乞丐感,符合修仙学徒朴素整洁要求。面部五官正常,全身完整。与苏白CHAR-003脸型不同。"
}
],
"summary": {
"passed": 4,
"total": 4
}
}

View File

@ -0,0 +1,37 @@
{
"spec": "VA-05-001-R4",
"asset": "CHAR-004",
"ts": "20260701-144533",
"ok": 4,
"total": 4,
"results": [
{
"c": 1,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R4/20260701-144533/CHAR-004-R4-01-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/CHAR-004-R4-candidate-01-1080x1920.jpg",
"seed": 42
},
{
"c": 2,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R4/20260701-144533/CHAR-004-R4-02-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/CHAR-004-R4-candidate-02-1080x1920.jpg",
"seed": 137
},
{
"c": 3,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R4/20260701-144533/CHAR-004-R4-03-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/CHAR-004-R4-candidate-03-1080x1920.jpg",
"seed": 256
},
{
"c": 4,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R4/20260701-144533/CHAR-004-R4-04-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/CHAR-004-R4-candidate-04-1080x1920.jpg",
"seed": 399
}
]
}

View File

@ -0,0 +1,77 @@
{
"spec": "VA-05-001-R5",
"results": [
{
"candidate": "CHAR-004诸葛风",
"pass": true,
"score": 95,
"white_clothes": true,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"beggar": false,
"honest": true,
"like_sb": false,
"face_ok": true,
"full_body": true,
"summary": "角色符合淳朴少年设定,衣着素净整洁,无破损污渍,气质端正,整体表现优秀。"
},
{
"candidate": "CHAR-004诸葛风",
"pass": true,
"score": 95,
"white_clothes": false,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"beggar": false,
"honest": true,
"like_sb": false,
"face_ok": true,
"full_body": true,
"summary": "角色形象符合淳朴少年设定,服装整洁素雅,无破损污渍,气质端正,整体表现优秀。"
},
{
"candidate": "CHAR-004诸葛风",
"pass": true,
"score": 95,
"white_clothes": false,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"beggar": false,
"honest": true,
"like_sb": false,
"face_ok": true,
"full_body": true,
"summary": "角色整体干净整洁,气质淳朴端正,符合18岁少年设定,无破损或污渍,仅衣色非白系,但不影响整体表现。"
},
{
"candidate": "CHAR-004诸葛风",
"pass": true,
"score": 95,
"white_clothes": true,
"damaged": false,
"frayed": false,
"hole_knee": false,
"dirty_shoes": false,
"stains": false,
"beggar": false,
"honest": true,
"like_sb": false,
"face_ok": true,
"full_body": true,
"summary": "角色形象符合淳朴少年设定,衣着素净整洁,无破损污渍,气质端正,整体表现优秀。"
}
],
"summary": {
"passed": 4,
"total": 4
}
}

View File

@ -0,0 +1,35 @@
{
"spec": "VA-05-001-R5",
"ts": "20260701-151158",
"ok": 4,
"results": [
{
"c": 1,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R5/20260701-151158/CHAR-004-R5-01-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/CHAR-004-R5-candidate-01-1080x1920.jpg",
"seed": 42
},
{
"c": 2,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R5/20260701-151158/CHAR-004-R5-02-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/CHAR-004-R5-candidate-02-1080x1920.jpg",
"seed": 137
},
{
"c": 3,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R5/20260701-151158/CHAR-004-R5-03-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/CHAR-004-R5-candidate-03-1080x1920.jpg",
"seed": 256
},
{
"c": 4,
"ok": true,
"raw": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01/D157-R5/20260701-151158/CHAR-004-R5-04-1440x2560.jpg",
"scaled": "/Users/bingshuolingdianyuanhe/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/CHAR-004-R5-candidate-04-1080x1920.jpg",
"seed": 399
}
]
}

View File

@ -0,0 +1,222 @@
#!/usr/bin/env python3
"""
CHAR-004 诸葛风 · VA-05-001-R2 · 纯文生图执行脚本
分两步:先锁服装 → 再调面部
禁用任何图像参考,全程纯文字prompt
"""
import os, sys, json, time, base64, subprocess
from pathlib import Path
sys.path.insert(0, os.path.dirname(__file__))
from secrets_loader import secret, endpoint
# ── API 配置 ──
API_KEY = secret("SC-001")
BASE_URL = endpoint("EPT-001")
IMAGE_MODEL = "doubao-seedream-4-0-250828" # 已验证通过
# ── 路径配置 ──
REPO_ROOT = Path(__file__).resolve().parents[1]
JZAO_BASE = Path("/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01")
CANDIDATES_DIR = REPO_ROOT / "assets/candidates/D157-VA-05-001-R2" / "CHAR-004-ZhugeFeng"
# ── R2规范 · 全文字prompt ──
CHAR004_PROMPT = """
3D动漫卡通渲染,国风玄幻动态漫风格,画面质感与光影水平统一。
男性,16岁,清瘦挺拔,全身立绘,正面站立姿势。身高约175cm,肩宽偏窄,身形单薄但有力量感,无佝偻萎靡感。
面部:小麦色肤色,面部轮廓棱角分明,剑眉星目,眼神锐利有韧劲,鼻梁挺直,嘴唇偏薄,下颌线清晰。气质偏冷硬,少年气强,与温润型角色明确区分。
发型:纯黑色短发,高束半马尾,发尾有零散碎发。用一根普通深棕色木簪固定,无华丽发饰。额前散落几缕碎发,整体整洁不凌乱。
上衣:灰蓝色粗布交领短打,右衽,袖口收窄贴合手腕。衣服洗得微微褪色,领口、袖口边缘有轻微磨毛痕迹。无破洞、无污渍、无补丁,干净整洁。腰间系一根深棕色粗麻绳腰带,系法简单。
下装:深灰蓝色同色系粗布长裤,裤脚收紧塞进靴筒,膝盖位置有轻微磨白痕迹。无破损、无污渍。
鞋子:黑色粗布短靴,厚鞋底,鞋头有轻微磨损痕迹,干净无泥污。
配饰:无玉佩、香囊、首饰。仅腰间麻绳上挂一个拳头大的深灰色旧布包,布包平整无破损。
整体:清贫但不落魄,整洁有骨气。纯白背景,全身从头到鞋完整展示,画面干净。
负面:不要破洞,不要污渍,不要补丁,不要乞丐,不要乞丐服,不要麻绳缠身,不要短袖,不要破损衣服,不要无鞋,不要半身。
""".strip().replace("\n", " ")
def call_seedream(prompt_text, seed=None):
"""调用Seedream文生图API"""
url = f"{BASE_URL}/images/generations"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": IMAGE_MODEL,
"prompt": prompt_text,
"size": "1440x2560",
"n": 1,
}
if seed:
payload["seed"] = seed
print(f" → POST {url}")
print(f" → model: {IMAGE_MODEL}")
# 使用curl调用(避免requests SSL问题)
payload_json = json.dumps(payload)
cmd = [
"curl", "-s", "-m", "120", "--noproxy", "*",
"-X", "POST", url,
"-H", f"Authorization: Bearer {API_KEY}",
"-H", "Content-Type: application/json",
"-d", payload_json
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=130)
if result.returncode != 0:
print(f" ✗ curl error: {result.stderr}")
return None
try:
data = json.loads(result.stdout)
except json.JSONDecodeError:
print(f" ✗ JSON parse error: {result.stdout[:200]}")
return None
if "error" in data:
print(f" ✗ API error: {data['error']}")
return None
# Seedream4 响应结构:data[0].url
if "data" in data and len(data["data"]) > 0:
img_url = data["data"][0].get("url", "")
print(f" ✓ 生成成功: {img_url[:80]}...")
return img_url
print(f" ✗ 未找到图片URL. 响应: {json.dumps(data)[:300]}")
return None
def download_image(url, filepath):
"""下载图片到指定路径"""
Path(filepath).parent.mkdir(parents=True, exist_ok=True)
print(f" ↓ 下载到 {filepath}")
cmd = ["curl", "-s", "-m", "60", "-L", "--noproxy", "*", "-o", filepath, url]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=65)
if result.returncode != 0:
print(f" ✗ 下载失败: {result.stderr}")
return False
size = os.path.getsize(filepath) if os.path.exists(filepath) else 0
print(f" ✓ 已保存 {size/1024:.0f}KB")
return size > 1024 # 至少1KB
def scale_to_1080(src_path, dst_path):
"""1440x2560 → 1080x1920 等比缩放"""
print(f" ⇄ 缩放 {src_path} → {dst_path}")
cmd = [
"sips", "-z", "1920", "1080",
str(src_path),
"--out", str(dst_path)
]
result = subprocess.run(cmd, capture_output=True, text=True)
return result.returncode == 0
def main():
print("=" * 60)
print("CHAR-004 诸葛风 · VA-05-001-R2 · 纯文生图")
print(f"模型: {IMAGE_MODEL}")
print(f"分辨率: 1440x2560 → 1080x1920")
print(f"备选数: 4")
print(f"策略: 全程纯文字 · 禁用图像参考")
print("=" * 60)
if not API_KEY:
print("✗ 未找到JIMENG_API_KEY,退出")
sys.exit(1)
# ── 第一步:生成4张(锁服装身形) ──
print("\n── 第一步:生成4张候选 ──")
timestamp = time.strftime("%Y%m%d-%H%M%S")
run_dir = JZAO_BASE / "D157-R2" / timestamp
run_dir.mkdir(parents=True, exist_ok=True)
candidates_dir = CANDIDATES_DIR
candidates_dir.mkdir(parents=True, exist_ok=True)
results = []
seeds = [42, 137, 256, 399] # 不同seed产生不同变体
for i, seed in enumerate(seeds):
print(f"\n[{i+1}/4] 生成候选 {i+1} (seed={seed})")
# 微调prompt增加面部变化
variations = [
"面部角度:正脸直视镜头",
"面部角度:微微侧头,目光坚毅",
"面部角度:略微仰视,眼神向上",
"面部角度:3/4侧脸,侧视左前方",
]
full_prompt = f"{CHAR004_PROMPT} {variations[i]}"
img_url = call_seedream(full_prompt, seed=seed)
if not img_url:
print(f" ✗ 候选 {i+1} 生成失败")
results.append({"candidate": i+1, "status": "failed", "error": "API call failed"})
continue
# 保存原始1440×2560
raw_name = f"CHAR-004-R2-candidate-{i+1:02d}-1440x2560.jpg"
raw_path = run_dir / raw_name
if not download_image(img_url, raw_path):
results.append({"candidate": i+1, "status": "failed", "error": "download failed"})
continue
# 缩放至1080×1920
scaled_name = f"CHAR-004-R2-candidate-{i+1:02d}-1080x1920.jpg"
scaled_path = candidates_dir / scaled_name
if not scale_to_1080(raw_path, scaled_path):
results.append({"candidate": i+1, "status": "failed", "error": "scale failed"})
continue
results.append({
"candidate": i+1,
"status": "generated",
"raw": str(raw_path),
"scaled": str(scaled_path),
"seed": seed
})
print(f" ✓ 候选 {i+1} 完成")
time.sleep(2) # 避免请求过快
# ── 汇总 ──
print("\n── 生成汇总 ──")
success = sum(1 for r in results if r["status"] == "generated")
failed = len(results) - success
print(f"成功: {success}/4")
print(f"失败: {failed}/4")
if failed > 0:
for r in results:
if r["status"] != "generated":
print(f" ✗ 候选{r['candidate']}: {r.get('error', 'unknown')}")
# 写入元数据
meta = {
"spec": "VA-05-001-R2",
"asset_id": "CHAR-004-ZhugeFeng",
"timestamp": timestamp,
"model": IMAGE_MODEL,
"resolution_raw": "1440x2560",
"resolution_final": "1080x1920",
"strategy": "pure_text_prompt_no_image_reference",
"results": results
}
meta_path = candidates_dir / "generation-meta.json"
with open(meta_path, "w") as f:
json.dump(meta, f, ensure_ascii=False, indent=2)
print(f"\n元数据已保存: {meta_path}")
return 0 if success >= 4 else 1
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,121 @@
#!/usr/bin/env python3
"""CHAR-004 R3 · 反乞丐滑坡版 · 纯文生图"""
import sys, os, json, time, subprocess
from pathlib import Path
sys.path.insert(0, os.path.dirname(__file__))
from secrets_loader import secret, endpoint
API_KEY = secret("SC-001")
BASE_URL = endpoint("EPT-001")
IMAGE_MODEL = "doubao-seedream-4-0-250828"
REPO_ROOT = Path(__file__).resolve().parents[1]
JZAO_BASE = Path("/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01")
CANDIDATES_DIR = REPO_ROOT / "assets/candidates/D157-VA-05-001-R3" / "CHAR-004-ZhugeFeng"
POSITIVE = """3D动漫卡通渲染,国风玄幻动态漫质感,单人男性角色全身立绘,纯白背景。
角色为16岁少年,清瘦挺拔,身高约175cm,肩宽略窄,身形单薄但精神利落,不佝偻,不颓废。小麦色肤色,面部轮廓棱角分明,剑眉星目,眼神锐利有韧劲,鼻梁挺直,嘴唇偏薄,下颌线清晰,少年气强,气质冷硬。黑色短发,高束半马尾,发尾有少量碎发,用普通深棕色木簪固定,额前散落几缕碎发,整体整洁。
服装为朴素修仙学徒服,灰蓝色棉麻粗布交领上衣,右衽,袖口收窄,内搭浅色中衣;衣服整体干净整洁,只在领口、袖口边缘有非常轻微的磨毛质感,没有破洞,没有补丁,没有污渍。腰间系深棕色粗麻绳腰带,系法简单。下装为深灰蓝色同色系棉麻长裤,裤脚收进黑色短靴,膝盖和裤脚仅有轻微磨白,没有破损,没有泥污。黑色粗布短靴,厚鞋底,干净整洁。
腰间麻绳上挂一个拳头大小的深灰色旧布包,布包完整平整,布料略有年代感,但没有破口,没有补丁,没有脏污。
整体气质是清贫但整洁、有骨气、一心求仙的少年,不是乞丐,不是流民,不是流浪汉。
人物完整居中露出,比例协调,线条清晰,色彩柔和,卡通渲染,3D动漫角色质感。"""
NEGATIVE = """乞丐,流民,流浪汉,破损服装,破洞,补丁,污渍,泥污,脏鞋,破裤腿,烂袖口,脏布包,佝偻,颓废,萎靡,肮脏,凌乱,衣衫褴褛,夸张破旧,CHAR-003同款脸,CHAR-003同款五官,CHAR-003同款发型,与苏白长相相似,真人照片,写实,畸形肢体,五官崩坏,模糊,水印。"""
VARIATIONS = [
"正面直视镜头,表情沉稳有韧劲",
"微微侧头,目光坚毅看向前方",
"略微仰视,下颌抬起,眼神向上有向往",
"3/4侧脸,侧视左前方,少年英气",
]
def call_api(prompt_text, neg_text, seed):
url = f"{BASE_URL}/images/generations"
payload = json.dumps({
"model": IMAGE_MODEL,
"prompt": prompt_text,
"negative_prompt": neg_text,
"size": "1440x2560",
"n": 1,
"seed": seed,
})
proc = subprocess.run([
"curl", "-s", "-m", "120", "--noproxy", "*",
"-X", "POST", url,
"-H", f"Authorization: Bearer {API_KEY}",
"-H", "Content-Type: application/json",
"-d", payload
], capture_output=True, text=True, timeout=130)
try:
data = json.loads(proc.stdout)
if "data" in data and len(data["data"]) > 0:
return data["data"][0].get("url")
except:
pass
return None
def download(url, dst):
Path(dst).parent.mkdir(parents=True, exist_ok=True)
subprocess.run(["curl", "-s", "-m", "60", "-L", "--noproxy", "*", "-o", dst, url],
capture_output=True, timeout=65)
return os.path.exists(dst) and os.path.getsize(dst) > 1024
def scale(src, dst):
subprocess.run(["sips", "-z", "1920", "1080", str(src), "--out", str(dst)],
capture_output=True)
return os.path.exists(dst)
def main():
print("CHAR-004 R3 · 反乞丐滑坡")
print(f"策略: 整洁优先+负面词锁死+{len(VARIATIONS)}角度变体")
if not API_KEY:
print("✗ 无API Key"); sys.exit(1)
ts = time.strftime("%Y%m%d-%H%M%S")
run_dir = JZAO_BASE / "D157-R3" / ts
run_dir.mkdir(parents=True, exist_ok=True)
CANDIDATES_DIR.mkdir(parents=True, exist_ok=True)
results = []
seeds = [42, 137, 256, 399]
for i, (seed, var) in enumerate(zip(seeds, VARIATIONS)):
full = f"{POSITIVE} {var}"
print(f"\n[{i+1}/4] seed={seed} 角度={var[:10]}...")
url = call_api(full, NEGATIVE, seed)
if not url:
print(" ✗ API失败"); results.append({"c": i+1, "ok": False, "err": "api"})
continue
raw = run_dir / f"CHAR-004-R3-{i+1:02d}-1440x2560.jpg"
if not download(url, raw):
print(" ✗ 下载失败"); results.append({"c": i+1, "ok": False, "err": "download"})
continue
print(f" ✓ raw {os.path.getsize(raw)/1024:.0f}KB")
scaled = CANDIDATES_DIR / f"CHAR-004-R3-candidate-{i+1:02d}-1080x1920.jpg"
if not scale(raw, scaled):
print(" ✗ 缩放失败"); results.append({"c": i+1, "ok": False, "err": "scale"})
continue
print(f" ✓ scaled {os.path.getsize(scaled)/1024:.0f}KB")
results.append({"c": i+1, "ok": True, "raw": str(raw), "scaled": str(scaled), "seed": seed})
time.sleep(2)
ok = sum(1 for r in results if r["ok"])
print(f"\n{'='*40}\n完成: {ok}/4")
meta = {"spec": "VA-05-001-R3", "asset": "CHAR-004", "ts": ts, "ok": ok, "total": 4, "results": results}
with open(CANDIDATES_DIR / "generation-meta.json", "w") as f:
json.dump(meta, f, ensure_ascii=False, indent=2)
return 0 if ok >= 4 else 1
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""PROP-002 天道宗无字牌匾 · 3D动漫卡通渲染风格 · 重做"""
import sys,os,json,time,subprocess
from pathlib import Path
sys.path.insert(0,os.path.dirname(__file__))
from secrets_loader import secret,endpoint
AK=secret("SC-001");URL=endpoint("EPT-001");M="doubao-seedream-4-0-250828"
ROOT=Path(__file__).resolve().parents[1];J=Path("/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01")
CD=ROOT/"assets/candidates/D157-PROP-002-R2"/"PROP-002-Tiandao-Plaque"
P="""3D动漫卡通渲染,国风玄幻动态漫质感,一件游戏道具牌匾,纯白背景。
深棕色木质无字牌匾底板,牌匾为长方形横版,边缘有简单的古朴雕花装饰。
木质纹理清晰但为卡通渲染风格,不是写实摄影。牌匾正面朝上平视角度。
木板表面平整,略有年代磨损痕迹但整体干净,没有写字,没有文字。
比例协调,线条清晰,光影柔和,适合作为动态漫中的道具使用。"""
N="""写实,照片感,真实木纹,家具摄影,产品图,3D渲染,PBR材质,高精度写实,文字,字母,汉字,书法,破损,裂缝,腐烂。"""
V=["正面平视,标准构图","轻微斜角,展示厚度感","俯视角度,展示完整板面","略侧角度,展示边缘雕花"]
S=[10,20,30,40]
def g(prompt,neg,seed):
url=f"{URL}/images/generations"
r=subprocess.run(["curl","-s","-m","120","--noproxy","*","-X","POST",url,
"-H",f"Authorization: Bearer {AK}","-H","Content-Type: application/json",
"-d",json.dumps({"model":M,"prompt":prompt,"negative_prompt":neg,"size":"1440x2560","n":1,"seed":seed})],
capture_output=True,text=True,timeout=130)
try:d=json.loads(r.stdout);return d["data"][0].get("url")
except:return None
def dl(url,dst):
Path(dst).parent.mkdir(parents=True,exist_ok=True)
subprocess.run(["curl","-s","-m","60","-L","--noproxy","*","-o",dst,url],capture_output=True,timeout=65)
return os.path.exists(dst) and os.path.getsize(dst)>1024
def main():
print("PROP-002 R2 · 3D动漫卡通风格牌匾")
if not AK: sys.exit("✗ no key")
ts=time.strftime("%Y%m%d-%H%M%S");rd=J/"PROP-002-R2"/ts;rd.mkdir(parents=True,exist_ok=True)
CD.mkdir(parents=True,exist_ok=True);rs=[]
for i,(seed,var) in enumerate(zip(S,V)):
full=f"{P} {var}";print(f"[{i+1}/4] seed={seed}",flush=True)
url=g(full,N,seed)
if not url:rs.append({"c":i+1,"ok":False,"err":"api"});continue
raw=rd/f"PROP-002-R2-{i+1:02d}-1440x2560.jpg"
if not dl(url,raw):rs.append({"c":i+1,"ok":False,"err":"dl"});continue
sc=CD/f"PROP-002-R2-candidate-{i+1:02d}-1080x1920.jpg"
subprocess.run(["sips","-z","1920","1080",str(raw),"--out",str(sc)],capture_output=True)
rs.append({"c":i+1,"ok":True,"raw":str(raw),"scaled":str(sc),"seed":seed});time.sleep(2)
ok=sum(1 for r in rs if r["ok"]);print(f"完成:{ok}/4")
with open(CD/"generation-meta.json","w") as f:json.dump({"spec":"PROP-002-R2","ts":ts,"ok":ok,"results":rs},f,ensure_ascii=False,indent=2)
return 0 if ok>=4 else 1
if __name__=="__main__":sys.exit(main())

View File

@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""PROP-002 天道宗摊位木板招牌 · R3 · 摊位简陋木牌 · 3D动漫卡通渲染"""
import sys,os,json,time,subprocess
from pathlib import Path
sys.path.insert(0,os.path.dirname(__file__))
from secrets_loader import secret,endpoint
AK=secret("SC-001");URL=endpoint("EPT-001");M="doubao-seedream-4-0-250828"
ROOT=Path(__file__).resolve().parents[1];J=Path("/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01")
CD=ROOT/"assets/candidates/D157-PROP-002-R3"/"PROP-002-Tiandao-Stall-Sign"
# 关键词变化:
# R2: 深棕色木质无字牌匾,边缘古朴雕花装饰 → 庄重大匾,错了
# R3: 百宗会广场角落的摊位招牌,一块破旧的长方形木板,简单朴素
# 剧本依据:△特写:角落里写着【天道宗】的破旧牌匾。
P="""3D动漫卡通渲染,国风玄幻动态漫质感,百宗会广场角落里的摊位招牌,纯白背景。
一块简单的长方形木板招牌,原木色,没有雕花装饰,没有边框装饰,就是一块切割平整的普通木板。
木板表面有明显的使用痕迹和轻微磨损,边缘有磕碰痕迹,整体破旧但结构完整。
木板朴素简陋,像街边摊位的临时招牌,不是庙宇大门匾额。
木板正面朝上平视角度,比例自然,适合后期在上面添加【天道宗】文字。"""
N="""写实,照片,真实木纹,摄影,产品图,雕刻,雕花,鎏金,红漆,豪华,气派,庙宇,匾额,装裱,边框装饰,金属包边,书法,文字,汉字,字母,PBR,高精度写实,3D渲染。"""
V=["正面平视,木板占画面主体","轻微斜角,展示木板厚度和简朴质感","侧面视角,木板倚靠在简单支架上","正面略俯,展示木板放在摊位桌上的感觉"]
S=[11,21,31,41]
def g(prompt,neg,seed):
url=f"{URL}/images/generations"
r=subprocess.run(["curl","-s","-m","120","--noproxy","*","-X","POST",url,
"-H",f"Authorization: Bearer {AK}","-H","Content-Type: application/json",
"-d",json.dumps({"model":M,"prompt":prompt,"negative_prompt":neg,"size":"1440x2560","n":1,"seed":seed})],
capture_output=True,text=True,timeout=130)
try:d=json.loads(r.stdout);return d["data"][0].get("url")
except:return None
def dl(url,dst):
Path(dst).parent.mkdir(parents=True,exist_ok=True)
subprocess.run(["curl","-s","-m","60","-L","--noproxy","*","-o",dst,url],capture_output=True,timeout=65)
return os.path.exists(dst) and os.path.getsize(dst)>1024
def main():
print("PROP-002 R3 · 摊位木板招牌(破旧简朴)")
if not AK: sys.exit("✗ no key")
ts=time.strftime("%Y%m%d-%H%M%S");rd=J/"PROP-002-R3"/ts;rd.mkdir(parents=True,exist_ok=True)
CD.mkdir(parents=True,exist_ok=True);rs=[]
for i,(seed,var) in enumerate(zip(S,V)):
full=f"{P} {var}";print(f"[{i+1}/4] seed={seed}",flush=True)
url=g(full,N,seed)
if not url:rs.append({"c":i+1,"ok":False,"err":"api"});continue
raw=rd/f"PROP-002-R3-{i+1:02d}-1440x2560.jpg"
if not dl(url,raw):rs.append({"c":i+1,"ok":False,"err":"dl"});continue
sc=CD/f"PROP-002-R3-candidate-{i+1:02d}-1080x1920.jpg"
subprocess.run(["sips","-z","1920","1080",str(raw),"--out",str(sc)],capture_output=True)
rs.append({"c":i+1,"ok":True,"raw":str(raw),"scaled":str(sc),"seed":seed});time.sleep(2)
ok=sum(1 for r in rs if r["ok"]);print(f"完成:{ok}/4")
with open(CD/"generation-meta.json","w") as f:json.dump({"spec":"PROP-002-R3","ts":ts,"ok":ok,"results":rs},f,ensure_ascii=False,indent=2)
return 0 if ok>=4 else 1
if __name__=="__main__":sys.exit(main())

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
"""PROP-003 免费招徒广告牌 · 3D动漫卡通渲染风格 · 重做"""
import sys,os,json,time,subprocess
from pathlib import Path
sys.path.insert(0,os.path.dirname(__file__))
from secrets_loader import secret,endpoint
AK=secret("SC-001");URL=endpoint("EPT-001");M="doubao-seedream-4-0-250828"
ROOT=Path(__file__).resolve().parents[1];J=Path("/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/zai-fu-fei-xiu-xian/ep01")
CD=ROOT/"assets/candidates/D157-PROP-003-R2"/"PROP-003-Recruit-Board"
P="""3D动漫卡通渲染,国风玄幻动态漫质感,一件游戏道具无字广告牌,纯白背景。
木制立式支架+米黄色空白宣纸底板,正面平视角度。
木质支架为原木色,简单不华丽,结构稳固但朴素。宣纸平整贴在木板上,纸张略带质感,干净没有任何文字和墨迹。
典型的修仙世界摊位宣传木板,适合动态漫场景道具使用。
线条清晰,卡通渲染质感,非写实摄影。"""
N="""写实,照片,真实木纹,家具摄影,产品图,PBR,高精度,文字,字母,汉字,书法,墨迹,笔划,破损,裂缝,污渍,旧报纸。"""
V=["正面平视,标准构图","略斜角度,展示支架结构","特写宣纸面板","完整支架+面板构图"]
S=[50,60,70,80]
def g(prompt,neg,seed):
url=f"{URL}/images/generations"
r=subprocess.run(["curl","-s","-m","120","--noproxy","*","-X","POST",url,
"-H",f"Authorization: Bearer {AK}","-H","Content-Type: application/json",
"-d",json.dumps({"model":M,"prompt":prompt,"negative_prompt":neg,"size":"1440x2560","n":1,"seed":seed})],
capture_output=True,text=True,timeout=130)
try:d=json.loads(r.stdout);return d["data"][0].get("url")
except:return None
def dl(url,dst):
Path(dst).parent.mkdir(parents=True,exist_ok=True)
subprocess.run(["curl","-s","-m","60","-L","--noproxy","*","-o",dst,url],capture_output=True,timeout=65)
return os.path.exists(dst) and os.path.getsize(dst)>1024
def main():
print("PROP-003 R2 · 3D动漫卡通风格广告牌")
if not AK: sys.exit("✗ no key")
ts=time.strftime("%Y%m%d-%H%M%S");rd=J/"PROP-003-R2"/ts;rd.mkdir(parents=True,exist_ok=True)
CD.mkdir(parents=True,exist_ok=True);rs=[]
for i,(seed,var) in enumerate(zip(S,V)):
full=f"{P} {var}";print(f"[{i+1}/4] seed={seed}",flush=True)
url=g(full,N,seed)
if not url:rs.append({"c":i+1,"ok":False,"err":"api"});continue
raw=rd/f"PROP-003-R2-{i+1:02d}-1440x2560.jpg"
if not dl(url,raw):rs.append({"c":i+1,"ok":False,"err":"dl"});continue
sc=CD/f"PROP-003-R2-candidate-{i+1:02d}-1080x1920.jpg"
subprocess.run(["sips","-z","1920","1080",str(raw),"--out",str(sc)],capture_output=True)
rs.append({"c":i+1,"ok":True,"raw":str(raw),"scaled":str(sc),"seed":seed});time.sleep(2)
ok=sum(1 for r in rs if r["ok"]);print(f"完成:{ok}/4")
with open(CD/"generation-meta.json","w") as f:json.dump({"spec":"PROP-003-R2","ts":ts,"ok":ok,"results":rs},f,ensure_ascii=False,indent=2)
return 0 if ok>=4 else 1
if __name__=="__main__":sys.exit(main())

View File

@ -0,0 +1,184 @@
#!/usr/bin/env python3
"""CHAR-004 R2 候选质检 · Qwen-VL · VA-05-001-R2标准"""
import sys, os, json, base64, subprocess
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from secrets_loader import secret, endpoint
API_KEY = secret("SC-004")
EP = endpoint("EPT-002")
FALLBACK_EP = "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"
CANDIDATES_DIR = os.path.expanduser("~/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng")
CANDIDATES = [f"{CANDIDATES_DIR}/CHAR-004-R2-candidate-{i:02d}-1080x1920.jpg" for i in range(1, 5)]
QC_PROMPT = """你是动画资产质量检查员。检查这张CHAR-004诸葛风立绘候选图,按以下标准逐项打分。
## R2规范必查项
1. 服装完整性(一票否决):
- 裤子膝盖是否有破洞/破损?是/否
- 衣服下摆是否有毛边/破损/撕裂?是/否
- 鞋子是否有泥污/脏污?是/否
- 服装是否有污渍?是/否
- 是否有补丁?是/否
- 整体是否"乞丐化"(像乞丐而不是清贫少年)?
2. 服装部件准确性:
- 上衣是否为灰蓝色交领短打、右衽?是/否
- 是否系深棕色粗麻绳腰带?是/否
- 裤子是否深灰蓝色、裤脚塞进靴子?是/否
- 鞋子是否黑色粗布短靴?是/否
- 腰间是否有旧布包?是/否
- 有无不该有的配饰(玉佩、香囊等)?是/否
3. 面部质量:
- 五官是否清晰无崩坏?是/否
- 是否少年感强、气质偏冷硬?是/否
- 有没有和苏白(温润仙气型)相似?是/否
4. 整体:
- 人物肢体比例是否正常?是/否
- 画面是否清晰无噪点?是/否
- 是否全身从头到鞋完整展示?是/否
输出严格JSON,不要额外文字:
{
"candidate": N,
"pass": true/false,
"score": 0-100,
"hole_in_pants": true/false,
"frayed_hem": true/false,
"dirty_shoes": true/false,
"stains": true/false,
"patches": true/false,
"beggar_look": true/false,
"correct_top": true/false,
"correct_belt": true/false,
"correct_pants": true/false,
"correct_shoes": true/false,
"has_bag": true/false,
"extra_accessories": true/false,
"face_intact": true/false,
"cold_temperament": true/false,
"similar_to_su_bai": true/false,
"anatomy_ok": true/false,
"clear_image": true/false,
"full_body": true/false,
"summary": "一句话总结"
}"""
def encode_image(path):
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
ext = path.rsplit(".", 1)[-1].lower()
mime = {"jpg": "jpeg", "jpeg": "jpeg", "png": "png"}.get(ext, "jpeg")
return f"data:image/{mime};base64,{b64}"
def call_qwen(image_b64):
body = json.dumps({
"model": "qwen-vl-max",
"input": {
"messages": [{
"role": "user",
"content": [
{"image": image_b64},
{"text": QC_PROMPT}
]
}]
}
})
endpoints = [EP, FALLBACK_EP]
for ep in endpoints:
try:
proc = subprocess.run(
["curl", "-s", "-m", "60", "--noproxy", "*",
"-X", "POST", ep,
"-H", f"Authorization: Bearer {API_KEY}",
"-H", "Content-Type: application/json",
"--data-binary", "@-"],
input=body, capture_output=True, text=True, timeout=65
)
if proc.returncode != 0 or not proc.stdout.strip():
continue
resp = json.loads(proc.stdout)
if "output" in resp:
content = resp["output"]["choices"][0]["message"]["content"][0]["text"]
# Clean markdown wrappers
if "```" in content:
content = content.split("```")[1]
if content.startswith("json"):
content = content[4:]
content = content.split("```")[0]
return json.loads(content.strip())
elif "error" in resp:
print(f" [Qwen error] {resp['error']}", file=sys.stderr)
continue
except Exception as e:
print(f" [fail {ep}] {e}", file=sys.stderr)
continue
return None
def main():
print("=" * 60)
print("CHAR-004 R2 候选质检 · Qwen-VL · VA-05-001-R2标准")
print("=" * 60)
results = []
for i, path in enumerate(CANDIDATES):
print(f"\n[{i+1}/4] 质检候选 {i+1}...")
img = encode_image(path)
qc = call_qwen(img)
if qc:
print(f" score={qc.get('score')} pass={qc.get('pass')}")
print(f" 破洞={qc.get('hole_in_pants')} 毛边={qc.get('frayed_hem')} 脏鞋={qc.get('dirty_shoes')}")
print(f" 乞丐化={qc.get('beggar_look')} 和苏白像={qc.get('similar_to_su_bai')}")
print(f" {qc.get('summary')}")
results.append(qc)
else:
print(f" ✗ Qwen-VL调用失败")
results.append({"candidate": i+1, "pass": False, "error": "Qwen-VL call failed"})
# 汇总
print("\n" + "=" * 60)
print("质检汇总")
print("=" * 60)
passed = sum(1 for r in results if r.get("pass"))
print(f"通过: {passed}/4")
for r in results:
if not r.get("pass"):
issues = []
if r.get("hole_in_pants"): issues.append("裤子破洞")
if r.get("frayed_hem"): issues.append("下摆毛边")
if r.get("dirty_shoes"): issues.append("鞋子脏污")
if r.get("stains"): issues.append("污渍")
if r.get("patches"): issues.append("补丁")
if r.get("beggar_look"): issues.append("乞丐化")
if r.get("extra_accessories"): issues.append("多余配饰")
print(f" 候选{r.get('candidate')} ✗: {', '.join(issues) if issues else 'other'}")
# 写入JSON
out_path = os.path.join(CANDIDATES_DIR, "QC-R2-BATCH.json")
report = {
"spec": "VA-05-001-R2",
"asset_id": "CHAR-004-ZhugeFeng",
"qc_tool": "Qwen-VL (qwen-vl-max)",
"results": results,
"summary": {
"passed": passed,
"total": 4,
"verdict": "APPROVED" if passed >= 4 else "REJECTED"
}
}
with open(out_path, "w") as f:
json.dump(report, f, ensure_ascii=False, indent=2)
print(f"\nQC报告已保存: {out_path}")
return 0 if passed >= 4 else 1
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,99 @@
#!/usr/bin/env python3
"""CHAR-004 R3 候选质检 · Qwen-VL · 反乞丐滑坡版标准"""
import sys, os, json, base64, subprocess
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from secrets_loader import secret, endpoint
API_KEY = secret("SC-004")
EP = endpoint("EPT-002")
FALLBACK_EP = "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"
CANDIDATES_DIR = os.path.expanduser("~/guanghulab/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng")
CANDIDATES = [f"{CANDIDATES_DIR}/CHAR-004-R3-candidate-{i:02d}-1080x1920.jpg" for i in range(1, 5)]
QC_PROMPT = """你是动画资产质量检查员。检查这张CHAR-004诸葛风立绘候选图。规范要求:清贫但整洁、有骨气、不是乞丐不是流民。服装干净,无破洞无补丁无污渍。
逐项检查并输出严格JSON:
1. 裤子膝盖有没有破洞/破损?(hole_in_pants: true/false)
2. 衣服下摆有没有毛边/撕裂?(frayed_hem: true/false)
3. 鞋子干不干净?有泥污没?(dirty_shoes: true/false)
4. 衣服有没有污渍?(stains: true/false)
5. 有没有补丁?(patches: true/false)
6. 整体气质像不像乞丐/流浪汉?(beggar_look: true/false)
7. 五官清晰无崩坏吗?(face_intact: true/false)
8. 肢体比例正常吗?(anatomy_ok: true/false)
9. 画面清晰吗?(clear_image: true/false)
10. 全身从头到鞋完整吗?(full_body: true/false)
11. 和苏白CHAR-003的脸像不像?(similar_to_sb: true/false)
注意:
- "磨白"不等于"破洞"——裤子膝盖只有颜色变浅、没有破损开口,hole_in_pants就是false
- 鞋子没有明显泥污就是dirty_shoes=false
- 衣领轻微磨毛不等于毛边撕裂——frayed_hem特指明显破损/散开/撕裂
输出严格JSON,不要额外文字:
{"candidate":N,"pass":true/false,"score":0-100,"hole_in_pants":bool,"frayed_hem":bool,"dirty_shoes":bool,"stains":bool,"patches":bool,"beggar_look":bool,"face_intact":bool,"anatomy_ok":bool,"clear_image":bool,"full_body":bool,"similar_to_sb":bool,"summary":"一句话"}"""
def encode_image(path):
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode()
ext = path.rsplit(".", 1)[-1].lower()
mime = {"jpg": "jpeg", "jpeg": "jpeg", "png": "png"}.get(ext, "jpeg")
return f"data:image/{mime};base64,{b64}"
def call_qwen(img):
body = json.dumps({"model":"qwen-vl-max","input":{"messages":[{"role":"user","content":[{"image":img},{"text":QC_PROMPT}]}]}})
for ep in [EP, FALLBACK_EP]:
try:
proc = subprocess.run(["curl","-s","-m","60","--noproxy","*","-X","POST",ep,"-H",f"Authorization: Bearer {API_KEY}","-H","Content-Type: application/json","--data-binary","@-"],input=body,capture_output=True,text=True,timeout=65)
if not proc.stdout.strip(): continue
resp = json.loads(proc.stdout)
if "output" in resp:
content = resp["output"]["choices"][0]["message"]["content"][0]["text"]
if "```" in content:
content = content.split("```")[1]
if content.startswith("json"): content = content[4:]
content = content.split("```")[0]
return json.loads(content.strip())
except: continue
return None
def main():
print("CHAR-004 R3 QC · Qwen-VL")
results = []
for i, p in enumerate(CANDIDATES):
print(f"[{i+1}/4]", end=" ", flush=True)
qc = call_qwen(encode_image(p))
if qc:
s = qc.get("score","?")
ok = qc.get("pass","?")
h = qc.get("hole_in_pants","?")
print(f"score={s} pass={ok} 破洞={h}")
results.append(qc)
else:
print("✗")
results.append({"candidate":i+1,"pass":False,"error":"api"})
ok = sum(1 for r in results if r.get("pass"))
print(f"\n通过: {ok}/4")
for r in results:
if not r.get("pass"):
issues = []
if r.get("hole_in_pants"): issues.append("破洞")
if r.get("frayed_hem"): issues.append("毛边")
if r.get("dirty_shoes"): issues.append("脏鞋")
if r.get("stains"): issues.append("污渍")
if r.get("beggar_look"): issues.append("乞丐化")
print(f" 候选{r.get('candidate')} ✗: {', '.join(issues) if issues else '评分不足'} (score={r.get('score')})")
report = {"spec":"VA-05-001-R3","asset":"CHAR-004","tool":"qwen-vl-max","results":results,"summary":{"passed":ok,"total":4}}
with open(os.path.join(CANDIDATES_DIR,"QC-R3-BATCH.json"),"w") as f:
json.dump(report,f,ensure_ascii=False,indent=2)
print(f"\n报告: QC-R3-BATCH.json")
return 0
if __name__=="__main__":
sys.exit(main())

View File

@ -0,0 +1,140 @@
#!/usr/bin/env python3
"""QC: PROP-002牌匾 + PROP-003广告牌 R2候选图 · 闸门1"""
import sys, os, json, base64, time, subprocess
from pathlib import Path
sys.path.insert(0, os.path.dirname(__file__))
from secrets_loader import secret, endpoint
AK = secret("SC-004")
URL = endpoint("EPT-002")
ROOT = Path(__file__).resolve().parents[1]
# 候选图路径
CANDIDATES = {
"PROP-002": {
"name": "天道宗无字牌匾",
"spec": "深棕色木质无字牌匾,长方形横版,边缘古朴雕花装饰,3D动漫卡通渲染风格,纯白背景,无文字",
"reject": ["写实", "照片感", "真实木纹", "产品摄影", "文字", "汉字", "字母"],
"dir": ROOT / "assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque",
"files": [f"PROP-002-R2-candidate-{i:02d}-1080x1920.jpg" for i in range(1, 5)]
},
"PROP-003": {
"name": "免费招徒广告牌",
"spec": "木制立式支架+米黄色空白宣纸底板,原木色支架朴素稳固,宣纸干净无字墨迹,修仙世界摊位宣传木板,3D动漫卡通渲染,纯白背景",
"reject": ["写实", "照片感", "画架", "easel", "美术画架", "真实木纹", "产品图", "文字", "墨迹"],
"dir": ROOT / "assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board",
"files": [f"PROP-003-R2-candidate-{i:02d}-1080x1920.jpg" for i in range(1, 5)]
}
}
def encode_image(path):
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode()
def qwen_vl_qc(img_b64, asset_name, spec, reject_words):
"""调用Qwen-VL质检单张图"""
prompt = f"""你是一个动态漫资产生成质检员。请严格检查这张图片。
资产名称:{asset_name}
规范要求:{spec}
请逐项检查并打分(0-100):
1. 风格匹配度(是否为3D动漫卡通渲染风格,非写实/照片感)
2. 内容准确性(是否包含规范要求的所有元素)
3. 一票否决项检查(以下任意一项出现直接判不合格):
- 是否有文字/汉字/字母?
- 是否是写实/照片感风格?
- 是否像产品摄影图?
- 对于PROP-003:是否是画架(easel)样式而不是摊位木板?
输出格式(严格JSON):
{{"score": <0-100>, "style_ok": <bool>, "content_ok": <bool>, "has_text": <bool>, "is_photorealistic": <bool>, "is_easel": <bool>, "issues": ["问题列表"], "verdict": "PASS/FAIL"}}"""
payload = {
"model": "qwen-vl-max-latest",
"input": {
"messages": [
{"role": "user", "content": [
{"image": f"data:image/jpeg;base64,{img_b64}"},
{"text": prompt}
]}
]
},
"parameters": {"enable_thinking": False}
}
r = subprocess.run(
["curl", "-s", "-m", "60", "--noproxy", "*", "-X", "POST", URL,
"-H", f"Authorization: Bearer {AK}",
"-H", "Content-Type: application/json",
"-d", json.dumps(payload)],
capture_output=True, text=True, timeout=65
)
try:
d = json.loads(r.stdout)
content = d["output"]["choices"][0]["message"]["content"]
# 提取JSON
import re
m = re.search(r'\{[^{}]*\}', content)
if m:
return json.loads(m.group())
return {"score": 0, "verdict": "FAIL", "issues": ["无法解析VL响应"], "raw": content[:200]}
except Exception as e:
return {"score": 0, "verdict": "FAIL", "issues": [f"API错误: {e}"]}
def main():
if not AK:
print("✗ SC-004密钥未找到"); return 1
results = {}
for aid, cfg in CANDIDATES.items():
print(f"\n{'='*50}")
print(f"QC: {aid} · {cfg['name']}")
print(f"{'='*50}")
results[aid] = []
for fname in cfg["files"]:
fpath = cfg["dir"] / fname
if not fpath.exists():
print(f" ✗ 文件不存在: {fname}")
continue
print(f"\n 检查: {fname} ...", end=" ", flush=True)
img_b64 = encode_image(str(fpath))
qc = qwen_vl_qc(img_b64, cfg["name"], cfg["spec"], cfg["reject"])
v = qc.get("verdict", "?")
s = qc.get("score", "?")
issues = qc.get("issues", [])
print(f"[{v}] score={s}")
for iss in issues:
print(f" ⚠️ {iss}")
qc["_file"] = fname
results[aid].append(qc)
time.sleep(1)
# 输出汇总
print(f"\n\n{'='*60}")
print("QC 汇总报告")
print(f"{'='*60}")
for aid, qlist in results.items():
print(f"\n【{aid}】")
for q in qlist:
fn = q.get("_file", "?")
v = q.get("verdict", "?")
s = q.get("score", "?")
ph = q.get("is_photorealistic", False)
easel = q.get("is_easel", False)
has_txt = q.get("has_text", False)
flag = ""
if ph: flag += " 写实"
if easel: flag += " 画架"
if has_txt: flag += " 有字"
print(f" {fn}: {v} (score={s}){flag}")
# 写入QC报告
report_path = ROOT / "assets/candidates/D157-PROP-QC-report.json"
with open(report_path, "w") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"\n📋 QC报告已写入: {report_path}")
return 0
if __name__ == "__main__":
sys.exit(main())