feat: 接口12/接口2 发际线重绘改走 local_test 外部 ComfyUI 服务
后端 generate_hairline_redraw 跳过内置 Flux-2 重绘,改为产出 final(接缝融合基底) + 纯红遮罩 PNG(redraw_band_mask_base64,遮罩区=(255,0,0,255)、其余全透明)。 接口2 female(generate_grow_results_swap) 取 final+遮罩后在后端调 local_test (0716add-hair.json 工作流) 完成重绘,结果作为生发图返回;male 分支不变。 测试页 test_interface12.html / test_interface12_final.html 改为两阶段: 先生成 final+纯红遮罩,再前端调 local_test 重绘并展示;color_match 默认不勾选。 local_test/app.py 加 CORS 头(OPTIONS 预检),支持浏览器跨域直连。
This commit is contained in:
+45
-10
@@ -40,6 +40,27 @@ _REPO = os.path.dirname(os.path.dirname(__file__))
|
||||
_TEXTURE_DIR = os.path.join(_REPO, "hairline_texture")
|
||||
_BLACK_TEXTURE_DIR = os.path.join(_REPO, "hairline_texture_black")
|
||||
|
||||
# 外部重绘服务(local_test,0716add-hair.json 工作流)。接口2 female 用它替代原 Flux-2 重绘。
|
||||
# 可用 HAIR_LOCAL_REDRAW_URL 覆盖(如线上改地址),默认 http://127.0.0.1:8899。
|
||||
_LOCAL_REDRAW_URL = os.getenv("HAIR_LOCAL_REDRAW_URL", "http://127.0.0.1:8899").rstrip("/")
|
||||
|
||||
|
||||
def _call_local_redraw(image_png_bytes, mask_png_bytes, timeout=300.0):
|
||||
"""调外部重绘服务(local_test /api/generate):传 final 图 + 纯红遮罩 PNG,
|
||||
返回重绘后的 PNG bytes。失败抛异常(调用方负责 try/except 跳过)。
|
||||
"""
|
||||
import requests
|
||||
files = {
|
||||
"image": ("final.jpg", image_png_bytes, "image/jpeg"),
|
||||
"mask": ("mask.png", mask_png_bytes, "image/png"),
|
||||
}
|
||||
resp = requests.post(_LOCAL_REDRAW_URL + "/api/generate", files=files, timeout=timeout)
|
||||
resp.raise_for_status()
|
||||
if "image/" not in resp.headers.get("Content-Type", ""):
|
||||
# 服务返回了 JSON 错误
|
||||
raise RuntimeError(f"local_test 返回非图片: {resp.text[:200]}")
|
||||
return resp.content
|
||||
|
||||
# 发际线贴图档位:middle=默认(hairline_texture/),high/low 各自独立文件夹。
|
||||
_TEXTURE_DIRS = {
|
||||
"middle": _TEXTURE_DIR,
|
||||
@@ -215,11 +236,12 @@ def generate_grow_results(image_bgr: np.ndarray, gender: str, use_mask: bool = T
|
||||
|
||||
def generate_grow_results_swap(image_bgr: np.ndarray, hair_styles: list[int] | None,
|
||||
redraw_defaults: dict):
|
||||
"""接口2 女性专用:发际线透明叠图(同 generate_grow_results)+ 换发型+Flux-2 整帧重绘图。
|
||||
"""接口2 女性专用:发际线透明叠图(同 generate_grow_results)+ 换发型重绘图。
|
||||
|
||||
与 generate_grow_results 的差异仅在 grown 图的来源:这里对每个选中发型把 female key 映射到
|
||||
change_hair 的 chang_* hair_id,调 face_analysis.hairline_grow.generate_hairline_redraw
|
||||
(= 接口12 final 管线,参数用 redraw_defaults),取 `redraw_full`(整帧重绘)作为生发图。
|
||||
grown 图来源(新流程):对每个选中发型把 female key 映射到 change_hair 的 chang_* hair_id,
|
||||
调 face_analysis.hairline_grow.generate_hairline_redraw(= 接口12 final 管线,参数用
|
||||
redraw_defaults)拿到 ④ final(接缝融合基底)+ ⑤-② 纯红遮罩 PNG,再**后端调外部重绘服务
|
||||
local_test**(0716add-hair.json 工作流)完成发际线带重绘,重绘结果作为生发图。
|
||||
|
||||
overlay 仍是发际线曲线透明层(与 generate_grow_results 完全一致)。
|
||||
Returns: list[dict] {"hairline_type","order","overlay","grown_png"(jpg bytes 或 None)};
|
||||
@@ -251,12 +273,25 @@ def generate_grow_results_swap(image_bgr: np.ndarray, hair_styles: list[int] | N
|
||||
else:
|
||||
try:
|
||||
data = generate_hairline_redraw(image_bgr, chang_id, **redraw_defaults)
|
||||
b64 = (data.get("steps") or {}).get("redraw_full_base64") or ""
|
||||
if b64.startswith("data:"):
|
||||
b64 = b64.split(",", 1)[1]
|
||||
grown_png = base64.b64decode(b64) if b64 else None
|
||||
if grown_png is None:
|
||||
logger.warning("接口2 换发型:type=%s 整帧重绘为空(可能 ComfyUI 未生效)", key)
|
||||
steps = data.get("steps") or {}
|
||||
# ④ final(接缝融合基底)+ ⑤-② 纯红遮罩 PNG
|
||||
final_b64 = steps.get("final_base64") or ""
|
||||
mask_b64 = steps.get("redraw_band_mask_base64") or ""
|
||||
if not final_b64 or not mask_b64:
|
||||
logger.warning("接口2 换发型:type=%s final/遮罩缺失(final=%d mask=%d)",
|
||||
key, len(final_b64), len(mask_b64))
|
||||
else:
|
||||
# 去掉 data URI 前缀
|
||||
if final_b64.startswith("data:"):
|
||||
final_b64 = final_b64.split(",", 1)[1]
|
||||
if mask_b64.startswith("data:"):
|
||||
mask_b64 = mask_b64.split(",", 1)[1]
|
||||
final_bytes = base64.b64decode(final_b64)
|
||||
mask_bytes = base64.b64decode(mask_b64)
|
||||
# 后端调外部重绘服务(local_test),返回重绘后的 PNG
|
||||
grown_png = _call_local_redraw(final_bytes, mask_bytes)
|
||||
if grown_png is None:
|
||||
logger.warning("接口2 换发型:type=%s 重绘结果为空", key)
|
||||
except NoFaceError:
|
||||
logger.warning("接口2 换发型:type=%s 未检出人脸", key)
|
||||
except Exception as e: # noqa: BLE001 单张失败不拖垮整请求
|
||||
|
||||
Reference in New Issue
Block a user