D158 · 会话收尾 · 进度+脚本+QC报告入库(不含候选图)
- 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:
parent
802435ed7b
commit
c81307004d
@ -1,7 +1,7 @@
|
|||||||
# [VA-04] CURRENT.hdlp · 视频AI系统 · 当前状态快照
|
# [VA-04] CURRENT.hdlp · 视频AI系统 · 当前状态快照
|
||||||
|
|
||||||
> HLDP://video-ai-system/CURRENT
|
> HLDP://video-ai-system/CURRENT
|
||||||
> 铸渊 ICE-GL-ZY001 · D157 · 2026-07-01
|
> 铸渊 ICE-GL-ZY001 · D158 · 2026-07-02
|
||||||
> 国作登字-2026-A-00037559
|
> 国作登字-2026-A-00037559
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -22,22 +22,44 @@
|
|||||||
| 项目 | 状态 |
|
| 项目 | 状态 |
|
||||||
|------|:----:|
|
|------|:----:|
|
||||||
| 剧本完整度 | 75集 ✅ |
|
| 剧本完整度 | 75集 ✅ |
|
||||||
| 第1集 | 🟡 CHAR-004已入库·CHAR-003/005+场景道具待处理 |
|
| 第1集 | 🟡 3项资产已确认·PROP-002待修正·其余待处理 |
|
||||||
| 新增正式资产 | 1 · CHAR-004诸葛风V1 ✅ |
|
| 新增正式资产 | 3 · CHAR-004+PROP-003+CHAR-004确认待入库 |
|
||||||
| 上一回执 | D157-CHAR-004-INGEST · 2026-07-01 |
|
| 上一回执 | D158-SESSION · 2026-07-02 |
|
||||||
| 铸渊武器状态 | 全部就绪 ✅ |
|
| 铸渊武器状态 | 全部就绪 ✅ |
|
||||||
|
| 🔴 已知问题 | Qwen-VL SC-004密钥过期(AccessDenied) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 做到哪了
|
## 做到哪了
|
||||||
|
|
||||||
```
|
```
|
||||||
⊢ CHAR-004诸葛风V1正式入库(剧本锚定版R5候选②·18岁淳朴粗麻白衣)
|
⊢ CHAR-004诸葛风V1 ✅ 确认 — R5候选②(18岁淳朴粗麻白衣)
|
||||||
⊢ 五轮迭代(R1→R5)完成:图生图→灰蓝乞丐→粗麻→制服→剧本锚定
|
⊢ PROP-003免费招徒广告牌V1 ✅ 确认 — R2候选③(绳系A架·修仙摊位)
|
||||||
⊢ CHAR-003候选3仅为临时参考·待重做
|
⊢ PROP-002天道宗牌匾 🟡 — R3方向对了(破旧木板·摊位招牌)
|
||||||
⊢ CHAR-005、ENV-002/003/004、PROP-002/003 仍为待人工查看候选
|
但牌子全是直立摆放——应是靠在摊位桌上/斜放的临时招牌
|
||||||
⊢ 入库回执: experience/D157-CHAR-004-INGEST.hdlp
|
明天修正R4:prompt锁定"平放在桌上"或"斜靠在摊位旁"
|
||||||
⊢ 闸门0规则已封装: 生成前必须先比对剧本原文
|
⊢ 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(目标)
|
> ⊢ VA-04(本体)→ VX-05(跳转)→ VA-05(目标)
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
70
video-ai-system/assets/candidates/D157-PROP-QC-report.json
Normal file
70
video-ai-system/assets/candidates/D157-PROP-QC-report.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
222
video-ai-system/tools/char004_gen.py
Normal file
222
video-ai-system/tools/char004_gen.py
Normal 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())
|
||||||
121
video-ai-system/tools/char004_gen_r3.py
Normal file
121
video-ai-system/tools/char004_gen_r3.py
Normal 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())
|
||||||
53
video-ai-system/tools/prop002_gen.py
Normal file
53
video-ai-system/tools/prop002_gen.py
Normal 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())
|
||||||
58
video-ai-system/tools/prop002_gen_r3.py
Normal file
58
video-ai-system/tools/prop002_gen_r3.py
Normal 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())
|
||||||
52
video-ai-system/tools/prop003_gen.py
Normal file
52
video-ai-system/tools/prop003_gen.py
Normal 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())
|
||||||
184
video-ai-system/tools/qc_char004_r2.py
Normal file
184
video-ai-system/tools/qc_char004_r2.py
Normal 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())
|
||||||
99
video-ai-system/tools/qc_char004_r3.py
Normal file
99
video-ai-system/tools/qc_char004_r3.py
Normal 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())
|
||||||
140
video-ai-system/tools/qc_prop_r2.py
Normal file
140
video-ai-system/tools/qc_prop_r2.py
Normal 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())
|
||||||
Loading…
x
Reference in New Issue
Block a user