- 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 通过
104 lines
8.0 KiB
Markdown
104 lines
8.0 KiB
Markdown
# 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
|
||
|
||
```bash
|
||
# ---- 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` — 离线模型权重/字体清单
|