feat(ai-art): 路径C窗户字汇表(含阳台标准件修正)及首图验证

- 修正阳台标准件prompt:两扇→三对6扇+物理依据(正投影/轴测两件)
- 重生成阳台2件并核验;4标准件(卧室窗/厨卫窄窗/阳台正投影/阳台轴测)全合格
- 新增窗户字汇表(_build_parts_sheet.py 拼接3正投影件+中英标签)
- 路径C组装prompt + codex完整prompt + codex Mac指南
- 工具:_gen_standard_parts.py / _run_pathc_fuse.py
- 路径C首图(apiyi三图融合,阳台6扇一次对,风格统一无割裂)
This commit is contained in:
2026-06-23 17:46:14 +08:00
parent 996ddf3c67
commit e8b9da5bc3
15 changed files with 458 additions and 4 deletions
@@ -0,0 +1,91 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
拼「窗户标准件合集图」(windows spec sheet) = 路径C组装prompt的【图3:窗户字汇表】。
纵向排列 3 个正投影标准件,每件下方加中英标签 + 尺度注释。
轴测件不进合集(它表达立体关系,最小闭环靠文字描述)。
需要 Pillow: pip install Pillow
"""
import sys
import io
from pathlib import Path
# Windows 控制台 UTF-8(避免 print emoji/中文时 GBK 崩溃)
if sys.platform == "win32":
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
from PIL import Image, ImageDraw, ImageFont
RESEARCH = Path(__file__).resolve().parent.parent
PARTS_DIR = RESEARCH / "生成结果" / "窗户标准件"
OUT = PARTS_DIR / "标准件合集图.png"
# (文件名, 中文, 英文, 尺度注释)
ITEMS = [
("标准件-普通窗-卧室.png", "卧室普通窗", "Bedroom window — 2-panel sliding", "约1.4m宽 · 两扇推拉 · 每扇宽高比1:2 · 把手在两端"),
("标准件-窄窗-厨卫-新版.png", "厨卫窄窗", "Kitchen/bath narrow window", "约0.7m宽 · 单扇外开 · 宽高比1:2"),
("260623-160342_gpt-image-2_gen.png", "阳台正面", "Balcony front — 6-panel sliding", "约4.2m宽 · 三对推拉共6扇 · 每扇宽高比1:2"),
]
def font(size):
for f in ["C:/Windows/Fonts/msyh.ttc", "C:/Windows/Fonts/simhei.ttf",
"C:/Windows/Fonts/arial.ttf"]:
if Path(f).exists():
try:
return ImageFont.truetype(f, size)
except Exception:
pass
return ImageFont.load_default()
ROW_H = 820
LABEL_H = 170
PAD = 50
CANVAS_W = 1700
rows = []
for fn, zh, en, note in ITEMS:
p = PARTS_DIR / fn
if not p.exists():
print(f"⚠️ 缺文件,跳过: {fn}")
continue
img = Image.open(p).convert("RGB")
w, h = img.size
scale = ROW_H / h
nw, nh = int(w * scale), ROW_H
maxw = CANVAS_W - 2 * PAD
if nw > maxw:
s2 = maxw / nw
nw, nh = int(nw * s2), int(nh * s2)
rows.append((img.resize((nw, nh), Image.LANCZOS), zh, en, note, nw))
n = len(rows)
unit = ROW_H + LABEL_H
canvas_h = unit * n + PAD * 2 + 30 * (n - 1) + 70 # +70 给顶部标题
canvas = Image.new("RGB", (CANVAS_W, canvas_h), "white")
draw = ImageDraw.Draw(canvas)
# 顶部标题:强调"尺寸仅供识别窗型,非真实比例"
draw.text((PAD, 18),
"窗户标准件字汇表 Windows Spec Sheet",
fill="black", font=font(34))
draw.text((PAD, 58),
"正投影·平涂结构图。图中窗的视觉大小仅供识别窗型,不代表真实比例;真实面宽见组装prompt的文字布局。",
fill="#666", font=font(24))
y = 100
for img2, zh, en, note, nw in rows:
x = (CANVAS_W - nw) // 2
canvas.paste(img2, (x, y))
ly = y + ROW_H + 6
draw.text((PAD, ly), zh, fill="black", font=font(46))
draw.text((PAD, ly + 58), en, fill="#555", font=font(28))
draw.text((PAD, ly + 96), note, fill="#555", font=font(26))
y += unit + 30
canvas.save(OUT)
print(f"✅ 合集图已生成: {OUT}")
print(f" 尺寸: {canvas.size}")
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
标准件生图辅助(apiyi 通道,无风格前缀)。
从 prompts/标准件/<名>.txt 读 UTF-8 prompt,生成纯结构示意图到 生成结果/窗户标准件/。
为什么需要它:
- 避开 Windows shell 传中文 prompt 给 Python argv 的 GBK/UTF-8 乱码坑;
- 标准件是工程结构图(平涂色块、无光照),【不加】STYLE_SEED_EN(那是 cel-shaded 游戏风格,会冲突)。
Usage(用英文 key,避免中文 argv):
python _gen_standard_parts.py # 默认:front + axo(阳台两件)
python _gen_standard_parts.py front # 仅阳台正投影
python _gen_standard_parts.py axo # 仅阳台轴测
python _gen_standard_parts.py bedroom narrow # 卧室窗 + 厨卫窄窗
"""
import sys
from pathlib import Path
HERE = Path(__file__).resolve().parent # ai-art-research/tools/
RESEARCH = HERE.parent # ai-art-research/
sys.path.insert(0, str(HERE))
from image_gen import get_client, cmd_generate
# 英文 key → (prompt 文件名, 尺寸)
# 横向构图(宽立面/阳台)用 1536x1024;单个竖窗用 1024x1024
PARTS = {
"front": ("阳台窗-正投影", "1536x1024"),
"axo": ("阳台窗-轴测", "1536x1024"),
"bedroom": ("普通窗-卧室", "1024x1024"),
"narrow": ("窄窗-厨卫", "1024x1024"),
}
keys = sys.argv[1:] or ["front", "axo"]
client = get_client()
for k in keys:
if k not in PARTS:
print(f"❌ 未知标准件 key: {k} (可用: {' '.join(PARTS)})")
continue
name, size = PARTS[k]
pf = RESEARCH / "prompts" / "标准件" / f"{name}.txt"
if not pf.exists():
print(f"❌ prompt 文件不存在: {pf}")
continue
prompt = pf.read_text(encoding="utf-8")
print(f"\n{'='*60}\n=== 标准件 [{k}] {name} 尺寸 {size} ===\n{'='*60}")
cmd_generate(client, prompt, use_style=False, size=size,
quality="medium", model=None, subdir="窗户标准件")
print("\n✅ 全部完成")
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
路径C组装:apiyi 三图融合(风格 + 外立面 + 窗户字汇表)→ 单元南立面。
在 Python 内部用绝对路径调 cmd_fuse,避开 Windows shell 传中文路径给 Python argv 的 GBK 乱码坑。
注意:image_gen.py 的 cmd_fuse 当前硬编码 size=1024x1024(方图)。
路径C首图先用方图验证「三图融合能否成功 + 窗户准确度」;
若窗户对、只是横向比例挤,再改 cmd_fuse 支持 size 出 1536x1024 横图。
"""
import sys
from pathlib import Path
# 注意:不在这里重定向 stdout/stderr —— image_gen.py 开头已做 TextIOWrapper(UTF-8) 重定向,
# 重复包装同一个 buffer 会导致底层文件被提前关闭("I/O operation on closed file")。
HERE = Path(__file__).resolve().parent # tools/
RESEARCH = HERE.parent # ai-art-research/
sys.path.insert(0, str(HERE))
from image_gen import get_client, cmd_fuse
STYLE = RESEARCH / "参考图" / "游戏截图" / "深夏时光" / "深夏时光-下午-街景.png"
CONTENT = [
RESEARCH / "参考图" / "真实场景" / "东井村" / "QQ20260616-174350.png",
RESEARCH / "生成结果" / "窗户标准件" / "标准件合集图.png",
]
PROMPT_FILE = RESEARCH / "prompts" / "居民楼-单元南立面-路径C-窗户字汇表-v1.txt"
for p in [STYLE] + CONTENT + [PROMPT_FILE]:
if not p.exists():
print(f"❌ 缺失: {p}")
sys.exit(1)
prompt = PROMPT_FILE.read_text(encoding="utf-8")
client = get_client()
# cmd_fuse 上传顺序 = [style, *content],与 prompt 里 图1=风格/图2=外立面/图3=窗户表 的编号一致
cmd_fuse(
client,
style_path=str(STYLE),
content_paths=[str(c) for c in CONTENT],
prompt=prompt,
model=None,
subdir="路径C组装",
)