#!/usr/bin/env python3 """生成 v2 分辨率对比报告:每行=原图+5档,按图×发型组织15行。""" import json, os, html OUT = "/home/ubuntu/hair/image/res_test/out" REPORT = os.path.join(OUT, "report.html") results = json.load(open(os.path.join(OUT, "report.json"))) IMAGES = ["girl2", "girl5", "qwer", "asdf", "girl7"] STYLES = [("flower", "花瓣"), ("heart", "心形"), ("wave", "波浪")] SIDES = [("origin", "原图直送", 0), ("s1024", "1024", 1024), ("s896", "896", 896), ("s768", "768", 768), ("s640", "640", 640)] LONGSIDE = {"girl2": 1082, "girl5": 767, "qwer": 1678, "asdf": 1666, "girl7": 925} def get(img, style, side): for r in results: if r["img"] == img and r["style"] == style and r["side"] == side: return r return None # 统计 total = len(results) ok = sum(1 for r in results if r["ok"]) # 每档平均耗时(排除冷启动异常值:girl2_flower_origin=135s 明显是冷启动) def avg(side, exclude_first_cold=False): ts = [] for r in results: if r["side"] == side and r["ok"]: if exclude_first_cold and r["key"] == "girl2_flower_origin": continue # 跳过冷启动 ts.append(r["elapsed"]) return sum(ts) / len(ts) if ts else 0 avg_origin = avg("origin", exclude_first_cold=True) avg_1024 = avg("s1024") avg_896 = avg("s896") avg_768 = avg("s768") avg_640 = avg("s640") avgs = [("origin", "原图直送", avg_origin, 0), ("s1024", "1024", avg_1024, 1024), ("s896", "896", avg_896, 896), ("s768", "768", avg_768, 768), ("s640", "640", avg_640, 640)] # 速度色阶:以全部耗时的 min-max 映射颜色(绿→黄→红) all_t = sorted([r["elapsed"] for r in results if r["ok"] and r["key"] != "girl2_flower_origin"]) tmin, tmax = all_t[0], all_t[-1] def speed_color(t): if tmax == tmin: return "#16a34a" ratio = (t - tmin) / (tmax - tmin) # 0=最快(绿) 1=最慢(红) if ratio < 0.33: return "#16a34a" # 绿 elif ratio < 0.66: return "#f59e0b" # 橙 else: return "#dc2626" # 红 # 表格行 rows_html = [] for img in IMAGES: for style_key, style_cn in STYLES: # 原图格 orig_cell = (f'' f'
原图
' f'
📷 原图
') # 5档格 side_cells = [] for side_name, side_lbl, side_val in SIDES: r = get(img, style_key, side_name) if r and r["ok"]: col = speed_color(r["elapsed"]) cell = (f'' f'
{html.escape(r[
' f'
{r["elapsed"]}s · ' f'{r["out_w"]}×{r["out_h"]}
') elif r: cell = (f'
' f'
{html.escape(r["err"][:30])}
') else: cell = '
' side_cells.append(cell) row_label = (f'' f'
{html.escape(img)}
' f'
{html.escape(style_cn)}
' f'
长边 {LONGSIDE[img]}
') rows_html.append("" + row_label + orig_cell + "".join(side_cells) + "") # 顶部平均耗时卡 def stat_card(lbl, val, col, sub=""): return (f'
' f'
{val:.1f}s
' f'
{lbl}{sub}
') stat_cards = "".join([ stat_card("原图直送", avg_origin, "#dc2626", "
排除冷启动"), stat_card("1024", avg_1024, "#f59e0b"), stat_card("896 (默认)", avg_896, "#2563eb"), stat_card("768", avg_768, "#16a34a"), stat_card("640", avg_640, "#0d9488"), ]) html_doc = f""" 接口2 分辨率对比测试 v2

💄 接口2 生发 · 5档分辨率对比报告

POST /api/v1/hair/grow · female · 5 图 × 3 发型(花瓣/心形/波浪) × 5 档分辨率 = 75 次 · 串行 · 4090 (24G)

{ok}/{total}
成功 / 总数
{stat_cards}
📊 结论:耗时随送图分辨率单调下降。大图(qwer/asdf 长边~1670) 原图直送需 ~27-30s,是 896 档(10s) 的近 3 倍; 中小图(girl2/girl5/girl7 长边 767-1082)各档差异较小(6-15s)。 4090 24G 全程无 OOM,75/75 成功。画质对比见下表(横向滑动),点击任意图可放大。 快(<{tmin+ (tmax-tmin)*0.33:.0f}s) 中等 慢(>{tmin+ (tmax-tmin)*0.66:.0f}s)
{"".join(rows_html)}
图 · 发型 📷 原图 原图直送 (0)
不缩放
1024 896
默认
768 640
""" with open(REPORT, "w") as f: f.write(html_doc) print(f"已生成: {REPORT}")