88 lines
4.1 KiB
Python
88 lines
4.1 KiB
Python
#!/usr/bin/env python3
|
||
"""CHAR-003 V2 R9 QC · 去麻子 · Qwen-VL"""
|
||
import sys, os, json, base64, subprocess
|
||
from pathlib import Path
|
||
ROOT = Path('D:/WorkBuddy/guanghulab/video-ai-system')
|
||
env = {}
|
||
for line in open(ROOT/".env"):
|
||
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", "")
|
||
FE = "https://dashscope.aliyuncs.com/api/v1/services/aigc/multimodal-generation/generation"
|
||
DIR = ROOT / "assets/candidates/D158-VA-05-001-V2/CHAR-003-SuBai/R9"
|
||
CS = [DIR / f"CHAR-003-V2-R9-candidate-{i:02d}-1080x1920.png" for i in range(1, 5)]
|
||
|
||
PROMPT = """检查CHAR-003苏白立绘。设定:18岁男性,白色长衫,青色腰带,黑色长发半束半披,双手叉腰,自信开朗,俊秀略带痞气,穷但不自卑。
|
||
|
||
判定(JSON,布尔小写):
|
||
1. male: 是否为男性?
|
||
2. young: 是否看起来17-18岁年轻少年?
|
||
3. white_robe: 是否白色长衫?
|
||
4. cyan_sash: 是否有青色/深色腰带?
|
||
5. hair_half_tied: 是否黑色长发半束半披(头顶束发带)?
|
||
6. hands_on_hips: 是否双手叉腰?
|
||
7. intact: 服装是否完整干净无破损?
|
||
8. beggar: 是否有乞丐感/寒酸感?(true=有,一票否决)
|
||
9. handsome_confident: 是否俊秀自信?
|
||
10. like_zhuge: 是否与诸葛风长相相似?(true=相似,一票否决)
|
||
11. face_ok: 五官是否清晰无崩坏?
|
||
12. full_body: 是否全身完整?
|
||
13. freckles: 脸上是否有雀斑/麻子/斑点?(true=有,一票否决)
|
||
14. sleeves_ok: 袖子是否完整(非无袖背心)?
|
||
|
||
pass = 男性且年轻且白衫且腰带且半束发且叉腰且完整且俊秀且五官清晰且全身完整且无麻子且无袖正常,且 beggar=false 且 like_zhuge=false。
|
||
|
||
输出格式:{{"candidate": N, "pass": bool, "score": 0-100, "male": bool, "young": bool, ...}} 以及 "summary": "一句话"""
|
||
|
||
def enc(p):
|
||
with open(p, "rb") as f:
|
||
return f"data:image/png;base64,{base64.b64encode(f.read()).decode()}"
|
||
|
||
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)
|
||
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.replace("```", "").strip()
|
||
return json.loads(c)
|
||
except Exception as e:
|
||
print(e)
|
||
continue
|
||
return None
|
||
|
||
rs = []
|
||
for i, p in enumerate(CS):
|
||
print(f"[{i+1}/4]", end=" ", flush=True)
|
||
qc = q(enc(p))
|
||
if qc:
|
||
qc["candidate"] = i + 1
|
||
print(f"pass={qc.get('pass')} s={qc.get('score')}")
|
||
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 = [k for k, v in r.items() if isinstance(v, bool) and v and k in ["beggar", "like_zhuge", "freckles"]]
|
||
iss += [k for k, v in r.items() if isinstance(v, bool) and not v and k in ["male", "young", "white_robe", "cyan_sash", "hair_half_tied", "hands_on_hips", "intact", "handsome_confident", "face_ok", "full_body", "sleeves_ok"]]
|
||
print(f" 候{r['candidate']} ✗: {','.join(iss) if iss else '其他'} s={r.get('score')}")
|
||
|
||
with open(DIR / "QC-R9-BATCH.json", "w", encoding="utf-8") as f:
|
||
json.dump({"spec": "VA-05-001-V2-R9", "method": "qwen-vl-auto", "results": rs, "summary": {"passed": ok, "total": 4}}, f, ensure_ascii=False, indent=2)
|
||
print("报告: QC-R9-BATCH.json")
|