docs: 重绘分辨率对比(无美颜提示词) + 调试接口支持自定义提示词
- app.py/hairline/service.py: 调试接口新增 redraw_prompt 参数,_call_local_redraw 支持自定义提示词 - benchmark_res_prompt.py: 提示词改为"填充遮罩区域的头发,皮肤加一点磨皮"(去掉美颜) - static/bench4_report.html: 20行×4分辨率对比报告,80/80成功,0 OOM 可对照 bench3(含美颜) vs bench4(无美颜) 看画质差异
@@ -829,6 +829,7 @@ async def debug_grow_timing(
|
||||
hair_style: str = Form(default="2", description="发型序号(花瓣=2),逗号分隔多选"),
|
||||
webui_steps: Optional[int] = Form(default=None, description="swapHair webui img2img 采样步数,None=服务端默认(15),可填10/15/20/25对比"),
|
||||
redraw_max_side: Optional[int] = Form(default=None, description="ComfyUI重绘分辨率(长边像素)。None=默认896;0=原图不缩;其他如640/768/1024"),
|
||||
redraw_prompt: Optional[str] = Form(default=None, description="ComfyUI重绘提示词,None=默认'填充遮罩区域的头发,皮肤加一点磨皮,再加一点美颜'"),
|
||||
):
|
||||
"""单图跑接口2女性生发,返回每个步骤的耗时 + 结果图,用于定位性能瓶颈。
|
||||
|
||||
@@ -927,9 +928,12 @@ async def debug_grow_timing(
|
||||
|
||||
# 3: ComfyUI 重绘
|
||||
t0 = _time.perf_counter()
|
||||
# max_side: 0 或 None 都让 _call_local_redraw 用默认逻辑(外层已控制分辨率)
|
||||
_ms = redraw_max_side if redraw_max_side is not None and redraw_max_side > 0 else None
|
||||
grown_png = await run_in_threadpool(
|
||||
_call_local_redraw,
|
||||
base64.b64decode(final_b64), base64.b64decode(mask_b64))
|
||||
base64.b64decode(final_b64), base64.b64decode(mask_b64),
|
||||
max_side=_ms, prompt=redraw_prompt)
|
||||
entry["comfyui_redraw_ms"] = int((_time.perf_counter() - t0) * 1000)
|
||||
if grown_png:
|
||||
entry["grown_b64"] = "data:image/jpeg;base64," + _png_to_jpg_b64(grown_png)
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""分辨率对比测试(新提示词版):4图×5发型=20行,每行4种分辨率,steps=15。
|
||||
提示词固定为 "填充遮罩区域的头发,皮肤加一点磨皮"(去掉了"再加一点美颜")。
|
||||
热数据:预热1次+正式1次。
|
||||
"""
|
||||
import base64
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import requests
|
||||
|
||||
API = "http://127.0.0.1:8187/api/v1/debug/grow-timing"
|
||||
TOKEN = "dev-shared-secret-2026"
|
||||
PROMPT = "填充遮罩区域的头发,皮肤加一点磨皮"
|
||||
OUT = Path("/home/ubuntu/hair/benchmark_out/bench4")
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
IMGS = [
|
||||
("asdf", "/home/ubuntu/hair/image/asdf.jpg"),
|
||||
("qwer", "/home/ubuntu/hair/image/qwer.jpg"),
|
||||
("girl2", "/home/ubuntu/hair/image/girl_img/girl2.jpg"),
|
||||
("girl5", "/home/ubuntu/hair/image/girl_img/girl5.jpg"),
|
||||
]
|
||||
HAIRSTYLES = [
|
||||
(1, "ellipse", "椭圆"), (2, "flower", "花瓣"), (3, "heart", "心形"),
|
||||
(4, "straight", "直线"), (5, "wave", "波浪"),
|
||||
]
|
||||
RES_LIST = [("orig", "0"), ("896", "896"), ("768", "768"), ("640", "640")]
|
||||
RES_TITLES = ["原图(不缩放)", "896", "768", "640"]
|
||||
STEPS = 15
|
||||
|
||||
|
||||
def call(img_path, hair_num, redraw_max_side, save_grown=None, timeout=300):
|
||||
data = {"hair_style": str(hair_num), "webui_steps": str(STEPS),
|
||||
"redraw_max_side": str(redraw_max_side), "redraw_prompt": PROMPT}
|
||||
t0 = time.perf_counter()
|
||||
try:
|
||||
with open(img_path, "rb") as f:
|
||||
r = requests.post(API, headers={"X-Internal-Token": TOKEN},
|
||||
files={"image_file": (os.path.basename(img_path), f, "image/jpeg")},
|
||||
data=data, timeout=timeout)
|
||||
wall = time.perf_counter() - t0
|
||||
j = r.json()
|
||||
if j.get("code") != 0:
|
||||
return {"ok": False, "error": j.get("message", "")[:80], "wall": wall}
|
||||
d = j["data"]
|
||||
hs = d["per_hairstyle"][0]
|
||||
if save_grown and hs.get("grown_b64"):
|
||||
b = hs["grown_b64"].split(",")[1] if "," in hs["grown_b64"] else hs["grown_b64"]
|
||||
with open(save_grown, "wb") as gf:
|
||||
gf.write(base64.b64decode(b))
|
||||
return {
|
||||
"ok": hs.get("ok", False), "wall": wall,
|
||||
"total_ms": d["total_ms"], "swap_ms": hs.get("swap_ms"),
|
||||
"comfy_ms": hs.get("comfyui_redraw_ms"),
|
||||
"error": hs.get("error"),
|
||||
}
|
||||
except Exception as e:
|
||||
return {"ok": False, "error": str(e)[:80], "wall": time.perf_counter() - t0}
|
||||
|
||||
|
||||
def main():
|
||||
rows = []
|
||||
total = len(IMGS) * len(HAIRSTYLES) * len(RES_LIST) * 2
|
||||
idx = 0
|
||||
for ilabel, ipath in IMGS:
|
||||
for hnum, hkey, hname in HAIRSTYLES:
|
||||
cells = []
|
||||
for (rlabel, rval), rtitle in zip(RES_LIST, RES_TITLES):
|
||||
idx += 1
|
||||
print(f"[{idx}/{total}] 预热 {ilabel}|{hname}|{rtitle}", flush=True)
|
||||
try:
|
||||
call(ipath, hnum, rval, timeout=120)
|
||||
except Exception:
|
||||
pass
|
||||
idx += 1
|
||||
save = OUT / f"{ilabel}_{hkey}_{rlabel}.jpg"
|
||||
print(f"[{idx}/{total}] 正式 {ilabel}|{hname}|{rtitle}", flush=True)
|
||||
r = call(ipath, hnum, rval, save_grown=save, timeout=300)
|
||||
r["res_label"] = rlabel; r["res_title"] = rtitle
|
||||
r["grown_path"] = str(save) if r.get("ok") else None
|
||||
status = f"{r.get('total_ms')}ms" if r.get("ok") else f"FAIL:{r.get('error','')[:30]}"
|
||||
print(f" -> {status}", flush=True)
|
||||
cells.append(r)
|
||||
rows.append({"img": ilabel, "img_path": ipath,
|
||||
"hair_num": hnum, "hair_key": hkey, "hair_name": hname,
|
||||
"cells": cells})
|
||||
with open(OUT / "results.json", "w", encoding="utf-8") as f:
|
||||
json.dump({"res_titles": RES_TITLES, "prompt": PROMPT, "rows": rows}, f, ensure_ascii=False, indent=2)
|
||||
ok = sum(1 for row in rows for c in row["cells"] if c.get("ok"))
|
||||
print(f"\n✓ 完成: {ok}/{len(rows)*len(RES_LIST)} 成功 -> {OUT/'results.json'}", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -55,7 +55,7 @@ _REDRAW_PROMPT = os.getenv("REDRAW_PROMPT", "填充遮罩区域的头发,皮
|
||||
_REDRAW_MAX_SIDE = int(os.getenv("REDRAW_MAX_SIDE", "896"))
|
||||
|
||||
def _call_local_redraw(image_png_bytes, mask_png_bytes, timeout=300.0,
|
||||
max_side=None, unet_name=None):
|
||||
max_side=None, unet_name=None, prompt=None):
|
||||
"""直接调 ComfyUI 重绘(替代原 local_test HTTP 服务)。
|
||||
|
||||
传 final 图 + 纯红遮罩 PNG,返回重绘后的 PNG bytes。
|
||||
@@ -63,6 +63,7 @@ def _call_local_redraw(image_png_bytes, mask_png_bytes, timeout=300.0,
|
||||
|
||||
max_side:送 ComfyUI 前长边压到多少像素,None 用全局默认 _REDRAW_MAX_SIDE。
|
||||
unet_name:非 None 时切换 Flux 模型,None 用工作流内置默认。
|
||||
prompt:None 用默认 _REDRAW_PROMPT,否则用传入的提示词。
|
||||
"""
|
||||
from .redraw import run_redraw
|
||||
eff_side = _REDRAW_MAX_SIDE if max_side is None else max_side
|
||||
@@ -84,7 +85,8 @@ def _call_local_redraw(image_png_bytes, mask_png_bytes, timeout=300.0,
|
||||
orig_w, orig_h, nw, nh, eff_side)
|
||||
# front=True:接口2 时延敏感,插到 ComfyUI 队列最前,避免排在接口3/5 的批量任务后面
|
||||
out = run_redraw(image_png_bytes, mask_png_bytes, timeout=timeout,
|
||||
prompt=_REDRAW_PROMPT, front=True, unet_name=unet_name)
|
||||
prompt=prompt if prompt is not None else _REDRAW_PROMPT,
|
||||
front=True, unet_name=unet_name)
|
||||
if scale < 1.0 and out:
|
||||
out = _upscale_png_to(out, orig_w, orig_h)
|
||||
return out
|
||||
|
||||
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 294 KiB |
|
After Width: | Height: | Size: 58 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 247 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 57 KiB |
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 239 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 244 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 120 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 200 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 122 KiB |
|
After Width: | Height: | Size: 170 KiB |
|
After Width: | Height: | Size: 190 KiB |
|
After Width: | Height: | Size: 88 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 185 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 74 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 99 KiB |
|
After Width: | Height: | Size: 71 KiB |
|
After Width: | Height: | Size: 102 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 251 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 87 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 260 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 256 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
After Width: | Height: | Size: 83 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 257 KiB |