From c81307004d7bd38abf7f589ebd6d2f0f047f766f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Thu, 2 Jul 2026 01:07:43 +0800 Subject: [PATCH] =?UTF-8?q?D158=20=C2=B7=20=E4=BC=9A=E8=AF=9D=E6=94=B6?= =?UTF-8?q?=E5=B0=BE=20=C2=B7=20=E8=BF=9B=E5=BA=A6+=E8=84=9A=E6=9C=AC+QC?= =?UTF-8?q?=E6=8A=A5=E5=91=8A=E5=85=A5=E5=BA=93=EF=BC=88=E4=B8=8D=E5=90=AB?= =?UTF-8?q?=E5=80=99=E9=80=89=E5=9B=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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)保留本地不入库 --- video-ai-system/CURRENT.hdlp | 47 +++- .../generation-meta.json | 35 +++ .../generation-meta.json | 35 +++ .../generation-meta.json | 35 +++ .../candidates/D157-PROP-QC-report.json | 70 ++++++ .../CHAR-004-ZhugeFeng/QC-R2-BATCH.json | 108 +++++++++ .../CHAR-004-ZhugeFeng/generation-meta.json | 39 +++ .../CHAR-004-ZhugeFeng/QC-R3-BATCH.json | 79 +++++++ .../CHAR-004-ZhugeFeng/generation-meta.json | 37 +++ .../CHAR-004-ZhugeFeng/QC-R4-BATCH.json | 73 ++++++ .../CHAR-004-ZhugeFeng/generation-meta.json | 37 +++ .../CHAR-004-ZhugeFeng/QC-R5-BATCH.json | 77 ++++++ .../CHAR-004-ZhugeFeng/generation-meta.json | 35 +++ video-ai-system/tools/char004_gen.py | 222 ++++++++++++++++++ video-ai-system/tools/char004_gen_r3.py | 121 ++++++++++ video-ai-system/tools/prop002_gen.py | 53 +++++ video-ai-system/tools/prop002_gen_r3.py | 58 +++++ video-ai-system/tools/prop003_gen.py | 52 ++++ video-ai-system/tools/qc_char004_r2.py | 184 +++++++++++++++ video-ai-system/tools/qc_char004_r3.py | 99 ++++++++ video-ai-system/tools/qc_prop_r2.py | 140 +++++++++++ 21 files changed, 1624 insertions(+), 12 deletions(-) create mode 100644 video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/generation-meta.json create mode 100644 video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/generation-meta.json create mode 100644 video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/generation-meta.json create mode 100644 video-ai-system/assets/candidates/D157-PROP-QC-report.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/QC-R2-BATCH.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/generation-meta.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/QC-R3-BATCH.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/generation-meta.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/QC-R4-BATCH.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/generation-meta.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/QC-R5-BATCH.json create mode 100644 video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/generation-meta.json create mode 100644 video-ai-system/tools/char004_gen.py create mode 100644 video-ai-system/tools/char004_gen_r3.py create mode 100644 video-ai-system/tools/prop002_gen.py create mode 100644 video-ai-system/tools/prop002_gen_r3.py create mode 100644 video-ai-system/tools/prop003_gen.py create mode 100644 video-ai-system/tools/qc_char004_r2.py create mode 100644 video-ai-system/tools/qc_char004_r3.py create mode 100644 video-ai-system/tools/qc_prop_r2.py diff --git a/video-ai-system/CURRENT.hdlp b/video-ai-system/CURRENT.hdlp index 1bffd41..d83bfb1 100644 --- a/video-ai-system/CURRENT.hdlp +++ b/video-ai-system/CURRENT.hdlp @@ -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(目标) diff --git a/video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/generation-meta.json b/video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/generation-meta.json new file mode 100644 index 0000000..da812e8 --- /dev/null +++ b/video-ai-system/assets/candidates/D157-PROP-002-R2/PROP-002-Tiandao-Plaque/generation-meta.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/generation-meta.json b/video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/generation-meta.json new file mode 100644 index 0000000..b906d5b --- /dev/null +++ b/video-ai-system/assets/candidates/D157-PROP-002-R3/PROP-002-Tiandao-Stall-Sign/generation-meta.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/generation-meta.json b/video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/generation-meta.json new file mode 100644 index 0000000..d399caa --- /dev/null +++ b/video-ai-system/assets/candidates/D157-PROP-003-R2/PROP-003-Recruit-Board/generation-meta.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-PROP-QC-report.json b/video-ai-system/assets/candidates/D157-PROP-QC-report.json new file mode 100644 index 0000000..8271a6e --- /dev/null +++ b/video-ai-system/assets/candidates/D157-PROP-QC-report.json @@ -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" + } + ] +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/QC-R2-BATCH.json b/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/QC-R2-BATCH.json new file mode 100644 index 0000000..4cad5c4 --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/QC-R2-BATCH.json @@ -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" + } +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/generation-meta.json b/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/generation-meta.json new file mode 100644 index 0000000..7eaa0eb --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R2/CHAR-004-ZhugeFeng/generation-meta.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/QC-R3-BATCH.json b/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/QC-R3-BATCH.json new file mode 100644 index 0000000..9e5a9f6 --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/QC-R3-BATCH.json @@ -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 + } +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/generation-meta.json b/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/generation-meta.json new file mode 100644 index 0000000..f5d2316 --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R3/CHAR-004-ZhugeFeng/generation-meta.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/QC-R4-BATCH.json b/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/QC-R4-BATCH.json new file mode 100644 index 0000000..6a4a581 --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/QC-R4-BATCH.json @@ -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 + } +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/generation-meta.json b/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/generation-meta.json new file mode 100644 index 0000000..7cf8a30 --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R4/CHAR-004-ZhugeFeng/generation-meta.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/QC-R5-BATCH.json b/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/QC-R5-BATCH.json new file mode 100644 index 0000000..e238738 --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/QC-R5-BATCH.json @@ -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 + } +} \ No newline at end of file diff --git a/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/generation-meta.json b/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/generation-meta.json new file mode 100644 index 0000000..c07b77c --- /dev/null +++ b/video-ai-system/assets/candidates/D157-VA-05-001-R5/CHAR-004-ZhugeFeng/generation-meta.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/video-ai-system/tools/char004_gen.py b/video-ai-system/tools/char004_gen.py new file mode 100644 index 0000000..1ce5a61 --- /dev/null +++ b/video-ai-system/tools/char004_gen.py @@ -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()) diff --git a/video-ai-system/tools/char004_gen_r3.py b/video-ai-system/tools/char004_gen_r3.py new file mode 100644 index 0000000..fb6a73c --- /dev/null +++ b/video-ai-system/tools/char004_gen_r3.py @@ -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()) diff --git a/video-ai-system/tools/prop002_gen.py b/video-ai-system/tools/prop002_gen.py new file mode 100644 index 0000000..a14608d --- /dev/null +++ b/video-ai-system/tools/prop002_gen.py @@ -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()) diff --git a/video-ai-system/tools/prop002_gen_r3.py b/video-ai-system/tools/prop002_gen_r3.py new file mode 100644 index 0000000..9f775e0 --- /dev/null +++ b/video-ai-system/tools/prop002_gen_r3.py @@ -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()) diff --git a/video-ai-system/tools/prop003_gen.py b/video-ai-system/tools/prop003_gen.py new file mode 100644 index 0000000..d996293 --- /dev/null +++ b/video-ai-system/tools/prop003_gen.py @@ -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()) diff --git a/video-ai-system/tools/qc_char004_r2.py b/video-ai-system/tools/qc_char004_r2.py new file mode 100644 index 0000000..6af2e08 --- /dev/null +++ b/video-ai-system/tools/qc_char004_r2.py @@ -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()) diff --git a/video-ai-system/tools/qc_char004_r3.py b/video-ai-system/tools/qc_char004_r3.py new file mode 100644 index 0000000..26e4fba --- /dev/null +++ b/video-ai-system/tools/qc_char004_r3.py @@ -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()) diff --git a/video-ai-system/tools/qc_prop_r2.py b/video-ai-system/tools/qc_prop_r2.py new file mode 100644 index 0000000..916391f --- /dev/null +++ b/video-ai-system/tools/qc_prop_r2.py @@ -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": , "content_ok": , "has_text": , "is_photorealistic": , "is_easel": , "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())