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 通过
This commit is contained in:
+43
-29
@@ -170,44 +170,58 @@ worker 侧已上线 4 条路由,**网关尚无对应转发路由**(当前仅
|
||||
|
||||
---
|
||||
|
||||
## 9. ✅【新增】接口99 人脸特殊点(`/api/v1/face/special-points`)
|
||||
## 9. ✅【新增】接口99 人脸特殊点(`/api/v1/face/special-points`)— **网关本机实现,不转发 worker**
|
||||
|
||||
**背景**:worker 侧新增接口99——固定编号 MediaPipe 关键点(6 组 60 点)+ 5 个发际线特殊点,
|
||||
返回原图像素坐标 JSON(无图片字段)。
|
||||
**背景**:接口99(固定编号 MediaPipe 关键点 6 组 60 点 + 5 个发际线特殊点,返回像素坐标 JSON)
|
||||
**纯 CPU 可跑**(MediaPipe 本就 CPU;BiSeNet 分割单核实测 <1s)且调用频率低。
|
||||
按约定:**不用 GPU、低频的接口默认网关本机实现**,不占 worker 队列
|
||||
(worker 池 `per_worker_concurrency=1`,转发会排在生发任务后面等)。
|
||||
|
||||
**网关代码已在本仓库 `gateway/app.py` 改好**(同接口1 的盲转发写法,pull 后重启即生效):
|
||||
**网关代码已在本仓库 `gateway/app.py` 改好**——与接口4 同款本机实现(显式 Form 参数 +
|
||||
惰性导入 + `run_in_threadpool` + `gw-` request_id),直接 import 同仓库的
|
||||
`face_analysis/special_points.detect_special_points`。**单路排队**:`_if99_lock` 全局互斥,
|
||||
同一时刻只跑一路推理(限制 CPU 峰值 + 规避 MediaPipe 单例线程安全问题),请求 FIFO 排队。
|
||||
|
||||
```python
|
||||
@app.post("/api/v1/face/special-points", tags=["人脸分析"])
|
||||
async def face_special_points(request: Request):
|
||||
"""接口99:人脸特殊点检测(固定关键点 + 发际线特殊点像素坐标)"""
|
||||
return await _proxy(request, "/api/v1/face/special-points")
|
||||
```
|
||||
### 网关机部署前检查
|
||||
|
||||
**网关机部署/调试步骤**:
|
||||
1. **Python 3.10~3.12**(mediapipe 0.10.14 无 3.13 wheel)。
|
||||
2. **安装依赖**(网关 venv,国内镜像):
|
||||
|
||||
```bash
|
||||
cd /path/to/hair && git pull # 拉取本分支
|
||||
sudo systemctl restart hair-gateway # 或项目实际的网关服务名(uvicorn gateway.app:app)
|
||||
# 验证路由已注册(应能在输出里看到 /api/v1/face/special-points)
|
||||
curl -s http://127.0.0.1:8080/openapi.json | python3 -m json.tool | grep special-points
|
||||
# 冒烟:经网关调一次(multipart 传图,无需 X-Internal-Token,网关会注入)
|
||||
curl -s -X POST http://127.0.0.1:8080/api/v1/face/special-points \
|
||||
-F "image_file=@/tmp/face.jpg" | python3 -m json.tool | head -30
|
||||
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \
|
||||
mediapipe==0.10.14 opencv-python==4.10.0.84 numpy==1.26.4
|
||||
|
||||
# 可选:BiSeNet 头发分割(发际线 5 点需要)。CPU 版 torch 仅 ~200MB:
|
||||
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \
|
||||
torch==2.2.2 torchvision==0.17.2 --index-url https://download.pytorch.org/whl/cpu
|
||||
# 不装 torch 也能跑:60 个关键点正常返回,发际线 5 点为 null(hairline_source="unavailable")
|
||||
```
|
||||
|
||||
**无需额外改动**:
|
||||
- 请求:multipart/form-data,仅图片三选一参数,盲转发即可。
|
||||
- 响应:`data.points` 全是坐标(`{"x":..,"y":..}`),**没有任何 `*_base64` 字段**,
|
||||
现有 `rewrite_base64_to_url` 递归改写天然跳过,原样返回。
|
||||
- 性能:纯本地推理(MediaPipe + BiSeNet,秒级),不依赖 ComfyUI/change_hair,
|
||||
`request_timeout_seconds` 无需调大。
|
||||
3. **权重已入 git**,`git clone/pull` 自动到位:`face_analysis/weights/79999_iter.pth`(51MB)。
|
||||
无需手动下载任何模型文件。
|
||||
|
||||
**注意**:
|
||||
- worker 侧测试页 `static/test_interface99.html` 是 worker 本机直连的(带 token 头),
|
||||
经网关调试请用 curl 或网关 `/docs`(网关只盲转发 `/api/*`,不代理 worker 的 `/static`)。
|
||||
- 契约详见 [`接口文档.md`](接口文档.md) 接口99 章节;worker 错误码 1001(无人脸)/1003(非正面)
|
||||
/1007/1008 原样透传。
|
||||
### 部署与冒烟
|
||||
|
||||
```bash
|
||||
cd /path/to/hair && git pull
|
||||
sudo systemctl restart hair-gateway # 或网关实际服务名(uvicorn gateway.app:app)
|
||||
|
||||
# 冒烟(multipart 传图;经网关无需 X-Internal-Token)
|
||||
curl -s -X POST http://127.0.0.1:8080/api/v1/face/special-points \
|
||||
-F "image_file=@/tmp/face.jpg" | python3 -m json.tool | head -30
|
||||
# 期望 code=0;data.points 含 eyebrow_107 等 60 个关键点 + hair_line_* 5 点
|
||||
# 缺依赖时返回 code=1007 且 message 提示"网关依赖未安装"
|
||||
```
|
||||
|
||||
### 注意
|
||||
|
||||
- **超时无需调大**:单路 CPU 推理 <1s;即使排队,低频下积压可忽略。排队本身无超时,
|
||||
调用方按需自带客户端超时。
|
||||
- **错误码透传契约**:1001(无人脸)/ 1003(非正面)/ 1007(参数/处理失败/缺依赖)/
|
||||
1008(图片格式/下载失败),HTTP 一律 200。
|
||||
- **worker 侧同路径接口保留**(`app.py`),供测试页 `static/test_interface99.html`
|
||||
直连调试(需 token);生产路径是网关本机实现。
|
||||
- 契约详见 [`接口文档.md`](接口文档.md) 接口99 章节。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user