perf(图片): 接口2/3/5 返回 JPG(体积~9×↓),接口1 标注图仍 PNG(透明)

- app.py: 接口2(预览+生发)/3(生发)/5(发际线叠图) 编码改 JPG(质量90,env JPG_QUALITY);
  接口1 annotated_image 含透明仍 PNG。_png_to_jpg_b64 把 ComfyUI 的 PNG 重编码为 JPG(无法解码则透传)
- gateway/forward.py: 落盘按内容嗅探扩展名(PNG头→.png 否则.jpg),原先硬编码 .png
- 测试/文档同步;实测接口5 一张 59KB(JPG) vs 548KB(PNG)。pytest 44 全绿

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
xsl
2026-06-15 23:35:24 +08:00
co-authored by Claude Opus 4.8
parent e3c67fc8cf
commit 4c7681b338
4 changed files with 36 additions and 17 deletions
+23 -8
View File
@@ -226,6 +226,24 @@ async def resolve_image_bytes(image_file, image_url, image_base64):
return None, err(1008, "base64 解码失败")
# 接口2/3/5 返回不透明照片,用 JPG 显著减小体积(接口1 标注图含透明,仍用 PNG)
_JPG_QUALITY = int(os.getenv("JPG_QUALITY", "90"))
def _jpg_b64(bgr) -> str:
"""BGR 图 → JPG base64。"""
_ok, buf = cv2.imencode(".jpg", bgr, [cv2.IMWRITE_JPEG_QUALITY, _JPG_QUALITY])
return base64.b64encode(buf.tobytes()).decode()
def _png_to_jpg_b64(png_bytes) -> str:
"""ComfyUI 返回的 PNG 字节 → 重编码为 JPG base64;无法解码则原样透传。"""
img = cv2.imdecode(np.frombuffer(png_bytes, np.uint8), cv2.IMREAD_COLOR)
if img is None:
return base64.b64encode(png_bytes).decode()
return _jpg_b64(img)
# ---------------------------------------------------------------------------
# 通用图片请求 BodyJSON 方式,用于 url / base64
# ---------------------------------------------------------------------------
@@ -514,12 +532,10 @@ async def hair_grow(
results = []
for p in items:
_ok, png = cv2.imencode(".png", p["image_bgr"])
grown_b64 = (base64.b64encode(p["grown_png"]).decode()
if p["grown_png"] else None)
results.append({
"image_base64": base64.b64encode(png.tobytes()).decode(),
"grown_image_base64": grown_b64,
"image_base64": _jpg_b64(p["image_bgr"]), # 预览图 JPG
"grown_image_base64": (_png_to_jpg_b64(p["grown_png"]) # 生发图 JPG
if p["grown_png"] else None),
"hairline_type": p["hairline_type"],
"order": p["order"],
})
@@ -602,7 +618,7 @@ async def hair_grow_b(
if res["status"] == "no_line":
return err(1001, "未检测到发际线划线,请确认划线图额头有清晰的手绘发际线")
grown_b64 = base64.b64encode(res["grown_png"]).decode() if res["grown_png"] else None
grown_b64 = _png_to_jpg_b64(res["grown_png"]) if res["grown_png"] else None # 生发图 JPG
data = {
"hair_growth_image_base64": grown_b64,
"hairline_type": "custom",
@@ -783,9 +799,8 @@ async def hairline_generate(
hairline_images = []
for it in res["images"]:
_ok, png = cv2.imencode(".png", it["image_bgr"])
hairline_images.append({
"image_base64": base64.b64encode(png.tobytes()).decode(),
"image_base64": _jpg_b64(it["image_bgr"]), # 发际线叠图 JPG
"order": it["order"],
})
c = res["best_center"]