#!/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")