Files
hair/CLAUDE.md
T
xsl 27c402c259 feat(接口99): 网关改本机实现(纯CPU+单路排队锁),文档同步
- gateway/app.py: 接口99 从盲转发改为本机实现(同接口4 模式):
  显式 Form 三选一 + 惰性导入(缺依赖仅本接口报1007)+ run_in_threadpool
- 单路排队: _if99_lock 全局互斥——串行推理限制 CPU 峰值 +
  规避 MediaPipe 单例线程安全问题;实测 req2≈2×req1 确认串行
- 网关待改动 §9 重写: 本机实现部署步骤 + 依赖清单(mediapipe/opencv/
  numpy<2,torch CPU 版可选——不装则发际线5点null)+ 权重已入git说明
- 实现说明/接口文档/CLAUDE.md 同步: 接口4/99 网关本机实现不转发
- 实测: BiSeNet 13.3M参数/51MB;CPU单核 0.46-0.65s/张;网关路径
  70/70点;worker 路径保留(测试页直连);pytest 15 通过
2026-09-06 23:32:24 +08:00

8.0 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

旷视接口服务 — FastAPI 人像分析/生发服务,一个仓库、两种部署角色:

  • worker(app.py + face_analysis/ + hairline/):跑真实算法(本地模型 + ComfyUI + change_hair),监听 0.0.0.0:8187。本机(GPU 机)即 worker 角色,不跑网关。
  • 网关(gateway/):外网机器上的薄反向代理,负责鉴权/健康检查/派发,并把 worker 返回的 *_base64 落盘改写为 *_url。接口4(豆包)和接口99(人脸特殊点,纯 CPU)在网关本机实现,不转发 worker。

历史包袱:app.py 的 FastAPI description 和 docs/接口文档.md 部分示例仍写「Mock 第一版」字样,实际全部接口已是真实算法实现。架构以 docs/实现说明.md 为准,契约以 docs/接口文档.md 为准。

Commands

# ---- worker(本机)----
./run_worker.sh                      # 后台启动(0.0.0.0:8187,日志 worker.log)
FOREGROUND=1 ./run_worker.sh         # 前台调试
./stop_worker.sh                     # 停止
sudo systemctl restart hair-worker   # systemd 方式(生产)
journalctl -u hair-worker -f

# ---- 依赖服务(worker 之前要先起)----
sudo systemctl start comfyui         # ComfyUI 127.0.0.1:8188(Flux-2 生图)
cd /home/ubuntu/change_hair && bash start_all.sh start   # 换发型三件套 8801/32678/57860

# ---- 测试 ----
./venv/bin/pytest tests/             # 单元测试(conftest 会准备 fixtures)
./venv/bin/python -m hairline.comfyui tests/output/comfy_input.png   # 手动跑一次生发工作流

依赖装在 ./venv(Python 3.10,torch 2.7.1+cu128,RTX 4090 CUDA 可用)。requirements.txt 里的 torch 2.2.2/5090 注释是旧机器的记录,本机 venv 实际是 cu128 版。

Architecture

接口一览(worker 侧路由,app.py)

接口 路径 实现位置 说明
1 POST /api/v1/face/measure face_analysis/ 四庭七眼测量 + 标注 PNG
6 POST /api/v1/face/measure-v2 同上(variant="v6") 接口1 去顶庭变体
2 POST /api/v1/hair/grow hairline/service.py C端生发。female 1..5 走 change_hair swapHair + Flux-2 整帧重绘(接口12 final 管线);female 6/7 与 male 全部走 ComfyUI add_hair.json inpaint
7 POST /api/v1/hair/grow-v2(hidden/deprecated) 同上 同接口2,用 add_hair2.json 工作流
3 POST /api/v1/hair/grow-b hairline/marker_detect.py B端马克笔划线生发(黑帽响应 + Dijkstra)
4 POST /api/v1/face/features worker 有实现;生产走网关本机(豆包) 用户特征
5 POST /api/v1/hairline/generate hairline/service.py 发际线 PNG 三档(middle/high/low)+ 生发
9 POST /api/v1/head/mask face_analysis/head_mask.py 头发遮罩 + 分步可视化(BiSeNet/SegFormer 双路)
10 POST /api/v1/head/band face_analysis/head_band.py 头部外缘膨胀带遮罩
11 POST /api/v1/hairline/grow face_analysis/hairline_grow.py 发际线生发(接口9 遮罩 + change_hair + 接缝融合),不含重绘
12 POST /api/v1/hairline/grow_v2 同上 接口11 final + 发际线重绘带 → Flux-2 保色重绘
12f POST /api/v1/hairline/grow_v2_final 同上(_V2_FINAL_DEFAULTS) 精简版:仅图片 + hairline_id,取整帧重绘
12f2 POST /api/v1/hairline/grow_v2_final_v2 同上 同上,取 B 局部加发+全脸美颜
99 POST /api/v1/face/special-points face_analysis/special_points.py(网关直接 import 本机实现 + _if99_lock 单路排队;worker 保留同路径备份) 固定编号关键点 + 发际线特殊点(射线求交头发 mask)像素坐标
代理 POST /api/swapHair/v1、/hairColor/v2 httpx 转发 127.0.0.1:8801 解决测试页 CORS
工具 POST /api/v1/redraw hairline/redraw.py 直接 ComfyUI 重绘(图+遮罩+prompt)
调试 POST /api/v1/debug/grow-timing、GET /api/v1/debug/hairline_log — 免鉴权,分步计时/下载日志

配套测试页在 static/test_interface{1..12}*.html,经 /static 挂载。

关键模式

  • 统一信封:ok(data) / err(code, message) 构造 {code, message, request_id, data};业务错误 HTTP 一律 200。错误码:1001 无人像 / 1002 分辨率低 / 1003 非正面 / 1004 gender 非法 / 1005 多人 / 1006 >1MB / 1007 参数或处理失败 / 1008 格式不支持。
  • 图片三选一:每个接口 image_file(multipart) / image_url / image_base64(带 data: 前缀)严格互斥,由 resolve_image_bytes() 统一处理(0 个或多个 → 1007)。接口3 是 marked_image_*。
  • 阻塞算法进线程池:所有推理 handler 用 run_in_threadpool(...),避免卡事件循环。
  • 内网鉴权:HTTP 中间件校验 /api/* 的 X-Internal-Token 头,密码来自 worker_config.json 的 accept_passwords(或环境变量 WORKER_ACCEPT_PASSWORDS)。豁免前缀见 _AUTH_EXEMPT(health/docs/static/debug/redraw/swapHair/hairColor)。
  • 发型序号映射:hairline/service.py 的 _HAIRSTYLE_ORDER 显式定义 1..7 顺序(不靠文件名字母序);female 1..5 → change_hair chang_* 映射在 _FEMALE_KEY_TO_CHANG。
  • 接口12 固化参数:_V2_FINAL_DEFAULTS(app.py)是生产默认值(push=0.8cm / two_stage / color_match=关 等),接口2 female 重绘也复用它。

外部依赖(worker 视角)

依赖 地址 用途 配置
ComfyUI http://127.0.0.1:8188(COMFYUI_URL) Flux-2 生图/重绘,走 HTTP API(hairline/comfyui.py) Basic Auth admin,密码:COMFYUI_PASSWORD → worker_config.json.comfyui_password → password.txt
change_hair http://127.0.0.1:8801(SWAP_HAIR_URL/HAIR_GROW_URL/CHANGE_HAIR_BASE) 换发型(SD WebUI + LoRA)、hairGrow 服务目录 /home/ubuntu/change_hair,start_all.sh 启停

ComfyUI 工作流 JSON 在仓库根:add_hair.json(接口2/3/5 生发)、add_hair2.json(接口7)、0716add-hair-api.json(接口12/2女 重绘)、hair_repaint.json。节点约定:26 输入图 / 6 seed / 60 提示词 / 16 unet(.gguf 自动切 UnetLoaderGGUF)/ 61 CLIP(4b↔9b 自动配套)。

性能/显存相关的坑

  • 三个生发接口共用同一提示词字符串以命中 ComfyUI 的 CLIP 文本条件缓存——prompt 变了会触发 Flux(7.7G)+qwen CLIP(3.9G) 互相挤显存重载(每次 +4s)。
  • 接口2 女性重绘管线默认把输入长边压到 REDRAW_MAX_SIDE(env,默认 1024)再放大回原尺寸;redraw_max_side=0 表示不缩图。
  • comfyui.run(front=True) 可插队(接口2 对时延敏感);超时 COMFY_TIMEOUT(默认 600s)。

Deployment(本机 = gpu_worker)

systemd 单元(仓库根有副本,实装在 /etc/systemd/system/):

服务 端口 说明
comfyui.service 127.0.0.1:8188 ComfyUI/venv 的 main.py --cache-classic --fast
hair-worker.service 0.0.0.0:8187 本仓库 app:app(Wants comfyui + change_hair-hair)
change_hair-{webui,photo,hair}.service 57860 / 32678 / 8801 conda envs sdwebui/py310/my_hair,依赖顺序 webui→photo→hair

网关机另行部署 gateway/(config:workers 列表 + shared_password + ark key),见 gateway/config.example.json 与 docs/网关待改动.md。

Documentation

  • docs/接口文档.md — 对外 API 契约(唯一权威)
  • docs/实现说明.md — 架构总览 + 各接口实现简述 + 部署要点
  • docs/发际线增强算法.md、docs/发际线生发遮罩算法_pushed模式.md — 接口11/12 算法推导
  • docs/gpu-worker改动说明.md、docs/网关待改动.md — worker↔网关 协同变更记录
  • OFFLINE_ASSETS.md — 离线模型权重/字体清单