接口2 变更: - 新增必填 hair_style(int) 参数,按序号只生成一张(不再全量) - female:1-5 male:1-4,越界返回1007 接口7 新增: - POST /api/v1/hair/grow-v2,功能与接口2一致 - 使用 add_hair2.json 工作流(Flux-2 Klein 9b) - SaveImage输出节点自动检测(75) comfyui.py 重构: - run() 支持 workflow_path 参数,多工作流按路径缓存 - SaveImage 输出节点自动检测,不再硬编码 - 输入/种子/提示词节点ID两个工作流相同(26/6/60) 文档: - 接口文档、实现说明、网关待改动 三份同步更新 - 网关只需加一行路由,base64→URL改写无需改动 Co-Authored-By: Claude <noreply@anthropic.com>
8.4 KiB
8.4 KiB
旷视五接口 — 实现说明(总)
把原先分散的「各接口技术方案 + 开发任务书 + 系统架构 + 网关任务书」合并成这一份简要总览。 对外 API 契约以
接口文档.md为唯一权威;原始需求见旷视具体需求.md; 离线模型清单见../OFFLINE_ASSETS.md。
1. 架构
两台机器、一个仓库:
客户端 ──HTTPS──> 外网网关(gateway/) ──HTTP(X-Internal-Token)──> worker(GPU 机, app.py)
│ 薄代理 + 落盘改URL │ 跑算法(本地模型/ComfyUI)
└ 接口4 本机直接调豆包(不转发) └ 接口1/2/3/5/7
- worker(
app.py+face_analysis/+hairline/):跑真正的算法,纯本地、无外网依赖。 对/api/*校验X-Internal-Token(密码在worker_config.json的accept_passwords);/health模型就绪才返回 200。监听 8187(./start.sh控制开关,./run_worker.sh热重载)。 - 网关(
gateway/):薄反向代理,健康检查/派发/鉴权/把 worker 的*_base64落盘改成*_url。 唯一例外是接口4 在网关本机直接实现(调外网豆包,不转发 worker)。 - 图片三选一:所有接口图片入参
image_file/image_url/image_base64严格三选一(接口3 是marked_image_*)。 - 响应信封:
{code, message, request_id, data};业务错误用code(HTTP 一律 200)。
base64 → URL 映射(网关落盘改写,递归进数组、可空保留 null)
| 接口 | worker 字段(内部) | 对外字段 |
|---|---|---|
| 1 | annotated_image_base64 |
annotated_image_url |
| 2 | results[].image_base64 / results[].grown_image_base64(可空) |
results[].image_url / results[].grown_image_url |
| 3 | hair_growth_image_base64(可空) |
hair_growth_image_url |
| 5 | hairline_images[].image_base64 |
hairline_images[].image_url |
| 7 | results[].image_base64 / results[].grown_image_base64(可空) |
results[].image_url / results[].grown_image_url |
| 4 | (网关本机产出,无图片字段,features 为 JSON 字符串) |
— |
实现建议:递归遍历 data,凡 key 以
_base64结尾就落盘改_url,自动覆盖嵌套/新增字段。 图片格式:接口1 标注图含透明用 PNG;接口2/3/5 是不透明照片用 JPG(小很多,~9×)。 网关落盘按内容嗅探扩展名(PNG 头→.png,否则.jpg)。
错误码
1001 无法识别人像 | 1002 分辨率过低 | 1003 非正面 | 1004 gender 必填/非法(接口2/5/7)|
1006 >1MB | 1007 图片参数错误(0或多个)/未预期异常 | 1008 格式不支持。
2. 五个接口实现简述
接口1 四庭七眼测量 /api/v1/face/measure(worker)
- 做什么:正面照 → 四庭(顶/上/中/下庭) + 七眼(眼宽/脸宽/间距) 的 cm 与占比、5 个关键点坐标、一张透明底标注 PNG。
- 怎么实现(
face_analysis/):MediaPipe Face Mesh 468+虹膜点 → solvePnP 姿态校验(非正面 1003) → 虹膜直径法定标(px→cm) → 眉心以下实测;眉心以上用 BiSeNet 头发分割取真实发际线/头顶(方案B), 失败回退比例推算(方案A,hairline_source透出)。标注图 numpy 向量化渐变线 + 思源黑体。返回annotated_image_base64。 - 门槛可配:
MIN_SHORT_SIDE/MIN_LONG_SIDE(默认600/800)、姿态阈值FRONTAL_*_THR(默认30°)。
接口2 C端生发 /api/v1/hair/grow(worker)—— 预览 + 生发图
- 做什么:正面照 +
gender(必填) +hair_style(必填,int) → 指定发际线类型 1 组:预览图(发际线叠在照片上) + 生发后图(植发3个月效果)。 - 怎么实现(
hairline/):移植 head3d——MediaPipe(Tasks) + SegFormer 分割 + 17 锚点射线检测 → 502 点 mesh, 按face_ext.obj的 UV 把发际线贴图渲染到额头(预览)。生发:黑贴图渲染遮罩 → 调本机 ComfyUI 8182 的add_hair.json(Flux-2) 出图。关键坑:obj 是重排序,需INDEX_MAP_468把 MP 序→OBJ 序。 单张请求(~5s)。返回results[].image_base64+grown_image_base64。 hair_style映射:female 1=ellipse 2=flower 3=heart 4=straight 5=wave;male 1=ellipse 2=inverse_arc 3=m 4=straight。
接口7 C端生发 v2 /api/v1/hair/grow-v2(worker)—— 接口2同款,add_hair2 工作流
- 做什么:与接口 2 完全一致(正面照 +
gender+hair_style→ 1 组预览+生发图)。 - 与接口 2 的唯一区别:ComfyUI 工作流使用
add_hair2.json(Flux-2 Klein 9b),输入/遮罩节点同为 26, SaveImage 输出节点为 75(自动检测)。其他参数、响应结构、错误码完全相同。 - 网关改动:在
gateway/app.py新增路由POST /api/v1/hair/grow-v2,转发到 worker 同路径即可(盲转发, base64→URL 改写逻辑无需改动,数组内图片字段已覆盖)。详见网关待改动.md。
接口3 B端生发 /api/v1/hair/grow-b(worker)—— 马克笔发际线
- 做什么:医生用马克笔在额头画好发际线,只传这一张划线图 → 检测线 → 生发图。输出
hair_growth_image_url+hairline_type="custom"。 - 怎么实现:检测算法源自 headmark——黑帽响应图 + 鬓角锚点(MediaPipe 21/251) + Dijkstra 最小路径(scikit-image), 比全局阈值鲁棒;路径平均响应过低→拒识(1001)。检测路径建遮罩,划线图原样送 ComfyUI(提示词清除黑线)。
接口4 用户特征 /api/v1/face/features(网关本机)
- 做什么:照片 → 几十项面部特征(脸型/眉形/肤色/三庭五眼/四季色彩季型/量感/基因风格/性别…)。
data.features是 JSON 字符串。 - 怎么实现(
gateway/,逻辑参考 workerface_features.py//home/xsl/fuyan):调火山方舟 豆包视觉模型doubao-seed-1-6-vision(OpenAI 兼容,base64 data URI 喂图),解析 JSON + 映射 6 个英文优先字段并保留全部中文。 无人脸→1001。唯一调外网的接口:网关需可达ark.cn-beijing.volces.com,API Key 走网关配置(不入 git)。
接口5 发际线PNG生成 /api/v1/hairline/generate(worker)
- 做什么:照片 +
gender(必填) → N 张发际线叠加图(同接口2预览) + 最佳(order1)发际线曲线的面部中间点坐标。 - 怎么实现:复用接口2 的 502 点渲染管线,输出 N 张叠图 +
best_hairline_center_point(眉心 x × 该处发际线 y)。无生发。
3. 部署 / 环境要点
worker(GPU 机)
- Python 3.12(系统 3.13 无 mediapipe/torch wheel);venv 在
./venv,依赖requirements.txt。 numpy<2(1.26.4),scikit-image==0.24.0(别升 0.25+,会顶 numpy≥2 顶崩 mediapipe)。- ⚠️ 本机 RTX 5090(sm_120),pinned
torch 2.2.2(cu121)只到 sm_90 → GPU 算子报 "no kernel image", 代码已自动回退 CPU(BiSeNet/SegFormer CPU 推理可用)。要用 5090 GPU 需换 torch cu128(≥2.7)。 - 模型权重/字体见
../OFFLINE_ASSETS.md;BiSeNet/SegFormer/face_landmarker.task 本地。 - 生发接口依赖本机 ComfyUI(8188)(Flux-2,它自带支持 5090 的 torch);worker 只调其 HTTP API,不跑 Flux。
ComfyUI 开了 HTTP Basic Auth(user
admin+ 密码);密码放password.txt(不入 git) /worker_config.json.comfyui_password/ 环境变量COMFYUI_PASSWORD,URL 用COMFYUI_URL。 worker_config.json(不入 git):accept_passwords(鉴权) + 鉴权头X-Internal-Token。
网关机
- 很轻:FastAPI/uvicorn/httpx + 接口4 的
volcengine-python-sdk[ark](或直接 httpx 调,OpenAI 兼容)。 - 不装 torch/mediapipe/opencv。配置
gateway/config.json(不入 git):workers列表、shared_password、ark的 api_key/base_url/model、public_base_url、超时(生发接口慢,request_timeout_seconds调大 ≥120s)。 - 托管
/static/annotations/(落盘的图),定期清理。
维护:本文为简要总览;字段以
接口文档.md为准。各接口更细的算法推导可查 git 历史中已合并的旧技术方案文档。