测试结论: 纯生发提示词(不做皮肤处理)效果最佳。 - 替换所有位置的提示词默认值(原"填充遮罩区域的头发,皮肤加一点磨皮,再加一点美颜"等) - 涉及25个文件: app.py/hairline/service.py/hairline/redraw.py/工作流json/测试页/benchmark脚本/local_test - _REDRAW_PROMPT / _DEFAULT_PROMPT / 各接口Form默认值 / 测试页输入框默认值 全部统一
130 lines
4.5 KiB
Python
130 lines
4.5 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""接口2女性 花瓣形 单发型 4模型×3分辨率×3图×3次 矩阵测试。
|
||
|
||
调用本机 hair-worker (:8187) 的 /api/v1/hair/grow,gender=female, hair_style=2(花瓣形)。
|
||
每次记录:生发图、耗时、显存峰值。结果图存到 benchmark_out/matrix/,最后生成 HTML 报告。
|
||
"""
|
||
import base64
|
||
import json
|
||
import os
|
||
import subprocess
|
||
import sys
|
||
import time
|
||
from pathlib import Path
|
||
|
||
import requests
|
||
|
||
API = "http://127.0.0.1:8187/api/v1/hair/grow"
|
||
TOKEN = "dev-shared-secret-2026"
|
||
OUT = Path("/home/ubuntu/hair/benchmark_out/matrix")
|
||
OUT.mkdir(parents=True, exist_ok=True)
|
||
|
||
# 4 模型 × 3 分辨率 × 3 图 × 3 次
|
||
MODELS = [
|
||
("4b-fp8", "flux-2-klein-4b-fp8.safetensors"),
|
||
("9b-fp8", "flux2.0/flux-2-klein-9b-fp8.safetensors"),
|
||
("9b-Q5", "flux-2-klein-9b-Q5_K_M.gguf"),
|
||
("9b-Q4", "flux-2-klein-9b-Q4_K_M.gguf"),
|
||
]
|
||
RES = [("orig", "0"), ("640", "640"), ("896", "896")]
|
||
IMGS = [
|
||
("asdf", "/home/ubuntu/hair/image/asdf.jpg"),
|
||
("qwer", "/home/ubuntu/hair/image/qwer.jpg"),
|
||
("girl5", "/home/ubuntu/hair/image/girl_img/girl5.jpg"),
|
||
]
|
||
REPEAT = 3
|
||
|
||
|
||
def gpu_used():
|
||
"""返回当前显存已用 MiB。"""
|
||
try:
|
||
out = subprocess.check_output(
|
||
["nvidia-smi", "--query-gpu=memory.used", "--format=csv,noheader,nounits"],
|
||
timeout=10,
|
||
)
|
||
return int(out.decode().strip())
|
||
except Exception:
|
||
return 0
|
||
|
||
|
||
def call(img_path, model_file, res_val):
|
||
"""调一次接口2。返回 dict: ok/elapsed/grown_path/gpu_peak/error。"""
|
||
fd = {
|
||
"gender": "female",
|
||
"hair_style": "2", # 花瓣形
|
||
"use_mask": "true",
|
||
"prompt": "填充遮罩区域的头发",
|
||
}
|
||
if model_file:
|
||
fd["flux_model"] = model_file
|
||
if res_val != "":
|
||
fd["redraw_max_side"] = res_val
|
||
t0 = time.perf_counter()
|
||
peak = gpu_used()
|
||
err = None
|
||
grown_path = None
|
||
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=fd, timeout=300,
|
||
)
|
||
elapsed = time.perf_counter() - t0
|
||
# 采样峰值(推理刚结束)
|
||
peak = max(peak, gpu_used())
|
||
j = r.json()
|
||
if j.get("code") != 0:
|
||
err = f"code={j.get('code')} {j.get('message','')}"
|
||
else:
|
||
res = j.get("data", {}).get("results", [])
|
||
if res and res[0].get("grown_image_base64"):
|
||
grown_path = OUT / f"tmp_grown.jpg"
|
||
with open(grown_path, "wb") as gf:
|
||
gf.write(base64.b64decode(res[0]["grown_image_base64"]))
|
||
elif res:
|
||
err = "grown_image_base64 为空"
|
||
else:
|
||
err = "无 results"
|
||
except Exception as e:
|
||
elapsed = time.perf_counter() - t0
|
||
err = str(e)[:200]
|
||
return {"elapsed": elapsed, "gpu_peak": peak, "grown_path": str(grown_path) if grown_path else None, "error": err}
|
||
|
||
|
||
def main():
|
||
results = [] # 每元素一个组合
|
||
total = len(MODELS) * len(RES) * len(IMGS) * REPEAT
|
||
idx = 0
|
||
for mlabel, mfile in MODELS:
|
||
for rlabel, rval in RES:
|
||
for ilabel, ipath in IMGS:
|
||
# 一个组合:3 次
|
||
runs = []
|
||
for rep in range(REPEAT):
|
||
idx += 1
|
||
print(f"[{idx}/{total}] {mlabel} | res={rlabel} | {ilabel} | rep{rep+1}", flush=True)
|
||
r = call(ipath, mfile, rval)
|
||
print(f" -> {r['elapsed']:.1f}s peak={r['gpu_peak']}MiB err={r['error']}", flush=True)
|
||
# 存每次的生发图
|
||
if r["grown_path"]:
|
||
save_to = OUT / f"{mlabel}_{rlabel}_{ilabel}_r{rep+1}.jpg"
|
||
os.replace(r["grown_path"], save_to)
|
||
r["grown_path"] = str(save_to)
|
||
runs.append(r)
|
||
results.append({
|
||
"model": mlabel, "model_file": mfile,
|
||
"res": rlabel, "res_val": rval,
|
||
"img": ilabel, "img_path": ipath,
|
||
"runs": runs,
|
||
})
|
||
# 存原始数据
|
||
with open(OUT / "results.json", "w", encoding="utf-8") as f:
|
||
json.dump(results, f, ensure_ascii=False, indent=2)
|
||
print(f"\n✓ 全部完成,原始数据 -> {OUT/'results.json'}", flush=True)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|