guanghulab/video-ai-system/tools/char004_gen_r3.py
Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

122 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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