104 lines
4.9 KiB
Python
104 lines
4.9 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""CHAR-003 V2 R6 QC · Seedream · R3-02风格 + 17-18岁"""
|
|||
|
|
import sys, os, json, base64, subprocess
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# 读 .env
|
|||
|
|
ROOT = Path('D:/WorkBuddy/guanghulab/video-ai-system')
|
|||
|
|
ENV_FILE = ROOT / ".env"
|
|||
|
|
env = {}
|
|||
|
|
if ENV_FILE.exists():
|
|||
|
|
for line in open(ENV_FILE):
|
|||
|
|
line = line.strip()
|
|||
|
|
if line and not line.startswith("#") and "=" in line:
|
|||
|
|
k, v = line.split("=", 1)
|
|||
|
|
env[k.strip()] = v.strip()
|
|||
|
|
|
|||
|
|
AK = env.get("ALIYUN_QWEN_VL_KEY", "")
|
|||
|
|
EP = env.get("ALIYUN_QWEN_VL_ENDPOINT", "https://ws-umd6xwlovzmshuat.cn-beijing.maas.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation")
|
|||
|
|
FE = "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"
|
|||
|
|
|
|||
|
|
DIR = ROOT / "assets/candidates/D158-VA-05-001-V2/CHAR-003-SuBai/R6"
|
|||
|
|
CS = [DIR / f"CHAR-003-V2-R6-candidate-{i:02d}-1080x1920.png" for i in range(1, 5)]
|
|||
|
|
|
|||
|
|
PROMPT = """检查CHAR-003苏白立绘。剧本设定:18岁男性,白色长衫,青色腰带,黑色长发半束半披,双手叉腰,自信开朗,气质俊秀略带痞气,穷但不自卑。
|
|||
|
|
|
|||
|
|
逐项判定:
|
|||
|
|
1. 是否为男性?(male: bool)
|
|||
|
|
2. 是否白色长衫?(white_robe: bool)
|
|||
|
|
3. 是否有青色/深色腰带?(cyan_sash: bool)
|
|||
|
|
4. 是否为黑色长发半束半披?(hair_half_tied: bool)
|
|||
|
|
5. 是否双手叉腰?(hands_on_hips: bool)
|
|||
|
|
6. 服装是否完整无破损?(intact: bool)
|
|||
|
|
7. 是否有乞丐感/寒酸感?(beggar: bool)
|
|||
|
|
8. 是否十七八岁年轻少年?(young: bool)
|
|||
|
|
9. 是否俊秀自信?(handsome_confident: bool)
|
|||
|
|
10. 是否与诸葛风长相相似?(like_zhuge: bool)
|
|||
|
|
11. 五官是否清晰无崩坏?(face_ok: bool)
|
|||
|
|
12. 全身是否完整?(full_body: bool)
|
|||
|
|
13. 袖子是否完整(非无袖/背心)?(sleeves_ok: bool)
|
|||
|
|
|
|||
|
|
评分规则:
|
|||
|
|
- 若 male/white_robe/cyan_sash/hair_half_tied/hands_on_hips/intact/young/handsome_confident/face_ok/full_body/sleeves_ok 任一不满足 → pass=false
|
|||
|
|
- 若 beggar=true 或 like_zhuge=true → pass=false
|
|||
|
|
|
|||
|
|
输出JSON: {"candidate": N, "pass": bool, "score": 0-100, "male": bool, "white_robe": bool, "cyan_sash": bool, "hair_half_tied": bool, "hands_on_hips": bool, "intact": bool, "beggar": bool, "young": bool, "handsome_confident": bool, "like_zhuge": bool, "face_ok": bool, "full_body": bool, "sleeves_ok": bool, "summary": "一句话"}"""
|
|||
|
|
|
|||
|
|
def encode(p):
|
|||
|
|
with open(p, "rb") as f:
|
|||
|
|
b64 = base64.b64encode(f.read()).decode()
|
|||
|
|
return f"data:image/png;base64,{b64}"
|
|||
|
|
|
|||
|
|
def q(img):
|
|||
|
|
b = json.dumps({"model": "qwen-vl-max", "input": {"messages": [{"role": "user", "content": [{"image": img}, {"text": PROMPT}]}]}})
|
|||
|
|
for ep in [EP, FE]:
|
|||
|
|
try:
|
|||
|
|
r = subprocess.run(["curl", "-s", "-m", "90", "--noproxy", "*", "-X", "POST", ep,
|
|||
|
|
"-H", f"Authorization: Bearer {AK}", "-H", "Content-Type: application/json", "--data-binary", "@-"],
|
|||
|
|
input=b, capture_output=True, text=True, timeout=95)
|
|||
|
|
if not r.stdout.strip():
|
|||
|
|
continue
|
|||
|
|
d = json.loads(r.stdout)
|
|||
|
|
if "output" in d:
|
|||
|
|
c = d["output"]["choices"][0]["message"]["content"][0]["text"]
|
|||
|
|
if "```" in c:
|
|||
|
|
c = c.split("```")[1]
|
|||
|
|
c = c[4:] if c.startswith("json") else c
|
|||
|
|
c = c.split("```")[0]
|
|||
|
|
return json.loads(c.strip())
|
|||
|
|
except Exception as e:
|
|||
|
|
continue
|
|||
|
|
return None
|
|||
|
|
|
|||
|
|
rs = []
|
|||
|
|
for i, p in enumerate(CS):
|
|||
|
|
print(f"[{i+1}/4]", end=" ", flush=True)
|
|||
|
|
qc = q(encode(p))
|
|||
|
|
if qc:
|
|||
|
|
print(f"s={qc.get('score', '?')} pass={qc.get('pass', '?')}")
|
|||
|
|
rs.append(qc)
|
|||
|
|
else:
|
|||
|
|
print("✗")
|
|||
|
|
rs.append({"candidate": i+1, "pass": False, "error": "api"})
|
|||
|
|
|
|||
|
|
ok = sum(1 for r in rs if r.get("pass"))
|
|||
|
|
print(f"\n通过: {ok}/4")
|
|||
|
|
for r in rs:
|
|||
|
|
if not r.get("pass") and "error" not in r:
|
|||
|
|
iss = []
|
|||
|
|
for k, v in r.items():
|
|||
|
|
if isinstance(v, bool) and v:
|
|||
|
|
if k in ["male", "white_robe", "cyan_sash", "hair_half_tied", "hands_on_hips", "intact", "young", "handsome_confident", "face_ok", "full_body", "sleeves_ok"]:
|
|||
|
|
pass
|
|||
|
|
elif k == "beggar": iss.append("乞丐感")
|
|||
|
|
elif k == "like_zhuge": iss.append("像诸葛风")
|
|||
|
|
else: iss.append(k)
|
|||
|
|
elif isinstance(v, bool) and not v and k in ["male", "white_robe", "cyan_sash", "hair_half_tied", "hands_on_hips", "intact", "young", "handsome_confident", "face_ok", "full_body", "sleeves_ok"]:
|
|||
|
|
iss.append(f"缺{k}")
|
|||
|
|
print(f" 候{r.get('candidate')} ✗: {','.join(iss) if iss else '其他'} s={r.get('score')}")
|
|||
|
|
|
|||
|
|
rep = {"spec": "VA-05-001-V2-R6", "method": "qwen-vl-auto", "results": rs, "summary": {"passed": ok, "total": 4}}
|
|||
|
|
with open(DIR / "QC-R6-BATCH.json", "w", encoding="utf-8") as f:
|
|||
|
|
json.dump(rep, f, ensure_ascii=False, indent=2)
|
|||
|
|
print(f"\n报告: QC-R6-BATCH.json")
|