diff --git a/scripts/batch_grow_v2.py b/scripts/batch_grow_v2.py index 0d84b0d..75902f6 100644 --- a/scripts/batch_grow_v2.py +++ b/scripts/batch_grow_v2.py @@ -1,7 +1,7 @@ """批量调用接口12(/api/v1/hairline/grow_v2)生成对比素材。 -20 张女生照片 × 5 种发际线发型 × {高清, 非高清} = 200 张输出。 -并发 4,失败的跳过并记录原因。结果图落盘到 static/report_hairline_v2/img/, +20 张女生照片 × 5 种发际线发型(仅非高清)= 100 张输出。 +并发 2,失败的跳过并记录原因。结果图落盘到 static/report_hairline_v2/img/, 元数据落盘 static/report_hairline_v2/results.json,供生成报告用。 用法: python scripts/batch_grow_v2.py @@ -31,7 +31,7 @@ HAIRSTYLES = [ ("chang_xinxing", "心形"), ("chang_huaban", "花瓣"), ] -HR_OPTIONS = [(True, "hr"), (False, "nohr")] +HR_OPTIONS = [(False, "nohr")] # 仅非高清 def list_inputs(): diff --git a/scripts/gen_report_hairline_v2.py b/scripts/gen_report_hairline_v2.py index 5f053d8..c3f7f10 100644 --- a/scripts/gen_report_hairline_v2.py +++ b/scripts/gen_report_hairline_v2.py @@ -78,12 +78,11 @@ def main(): .face-head h2 {{ margin:0; font-size:18px; }} .face-head .orig-thumb {{ width:64px; height:64px; object-fit:cover; border-radius:8px; border:1px solid var(--border); }} - .grid {{ display:grid; grid-template-columns:140px repeat({len(hairstyles)*2}, 1fr); - gap:8px; align-items:start; }} + .grid {{ display:grid; grid-template-columns:repeat({len(hairstyles)+1}, 1fr); + gap:10px; align-items:start; }} .col-hdr {{ font-size:12px; color:var(--muted); text-align:center; padding:6px 4px; border-bottom:1px solid var(--border); }} - .row-lbl {{ font-size:13px; color:var(--accent); padding:8px 4px; - border-right:1px solid var(--border); }} + .col-hdr.orig {{ color:var(--accent); }} .cell {{ position:relative; }} .cell img {{ width:100%; border-radius:6px; display:block; border:1px solid var(--border); }} @@ -117,7 +116,7 @@ def main():

发际线生发对比报告 接口12 · grow_v2

-
固定参数:blend_method=multiband · mb_levels=5 · erode_cm=0.6 · 生成后端=swaphair
+
固定:pushed 遮罩 + multiband 融合 · mb_levels=5 · erode_cm=0.6 · 非高清
生成时间:{html.escape(meta['generated_at'])} · 并发 {meta['concurrency']} · 耗时 {meta['elapsed_sec']}s
{meta['total']}
总调用
@@ -131,45 +130,39 @@ def main(): """) # 图例 - parts.append('
每张脸横向为 5 种发际线发型,每种发型分 ' - '高清 is_hr=true' - '非高清 is_hr=false 两列。
') + parts.append('
每张脸:第一列为原图,其余 5 列为发际线生发结果(非高清)。点击任意图片可放大。
') - # 每张脸一个区块 + # 每张脸一个区块:原图 + 5 发型横向并排 for stem in faces: orig_rel = f"orig/{stem}.jpg" parts.append('
') - parts.append(f'
' - f'原图 {html.escape(stem)}' - f'

{html.escape(stem)}

' - f'
') - # 网格表头 + parts.append(f'

{html.escape(stem)}

') + # 网格:第一列原图,其余 5 列发型结果 parts.append('
') - parts.append('
') + # 表头 + parts.append('
原图
') for h in hairstyles: - parts.append(f'
{html.escape(h["cn"])}
{html.escape(h["id"])}
') - # 行:原图占满左侧第一列的高度由第一行承载;每行 = 一个 hr 选项 - for hro in hr_opts: - hr_tag = hro["tag"] - is_hr = hro["is_hr"] - tag_cls = "" if is_hr else " no" - tag_txt = "高清" if is_hr else "非高清" - parts.append(f'
{tag_txt}{hr_tag}
') - for h in hairstyles: - r = idx.get((stem, h["id"], hr_tag)) - if r and r["ok"]: - ms = r["ms"] - cap = f"{html.escape(h['cn'])} · {tag_txt} · {ms}ms" - parts.append( - f'
' - f'
{ms}ms
') - else: - err = (r or {}).get("error", "未执行") - parts.append( - f'
{html.escape(err)}
') + parts.append(f'
{html.escape(h["cn"])}
{html.escape(h["id"])}
') + # 第一列:原图大图(可点击放大) + parts.append( + f'
原图 {html.escape(stem)}' + f'
原图
') + # 5 发型结果(hr_opts 现在只有 nohr 一档,直接取) + hr_tag = hr_opts[0]["tag"] if hr_opts else "nohr" + for h in hairstyles: + r = idx.get((stem, h["id"], hr_tag)) + if r and r["ok"]: + ms = r["ms"] + parts.append( + f'
' + f'
{ms}ms
') + else: + err = (r or {}).get("error", "未执行") + parts.append( + f'
{html.escape(err)}
') parts.append('
') # grid parts.append('
') # face-block @@ -179,21 +172,19 @@ def main(): parts.append('
') parts.append(f'

失败用例({len(fails)})

') parts.append('' - '' + '' '') for r in fails: parts.append( f'' f'' - f'' f'' f'') parts.append('
人脸发型高清耗时(ms)原因人脸发型耗时(ms)原因
{html.escape(r["stem"])}{html.escape(r["hair_cn"])}{r["hr_tag"]}{r["ms"]}{html.escape(r["error"] or "")}
') parts.append(f"""