定位
pf-face-service 是图模工坊的独立人脸检测微服务——为”自动避脸裁剪”提供算力。
- 运行时:Python 3.12+
- Web 框架:FastAPI
- 推理引擎:ONNX Runtime
- 模型:SCRFD-500m(SCRFD 系列,500MB FLOPs 量级,CPU 即可实时跑)
- 包管理:uv(比 pip / poetry 快一个数量级)
- 端口:开发环境
3010
为什么单独建一个 Python 服务? TS 生态里没有质量稳定的人脸检测库;Python + ONNX 是工程最短路径。把它做成”接口稳定的微服务”而非”动态库 + 进程内 FFI”,让
pf-service可以无脑横向扩展 Bun 进程,不必把 Python 模型一起复制。
接口协议
POST /api/face/detect
1 | // 请求 |
x / y / w / h 都是**相对原图的归一化坐标 [0, 1]**——这样无论原图 1024 还是 4096,前后端拿到的语义一致,缩放计算放调用方做。
GET /health
1 | { |
模型未加载或加载失败时,状态会变成 degraded,reason 给出原因。
调用链路
1 | ┌───────────┐ |
也可以由后端合成 Job 在内部直接调用 —— 用于带 faceSafe: true 节点的合成场景,先取人脸框、再算最佳裁剪窗口。
模型与配置
| 项 | 默认值 | 环境变量 |
|---|---|---|
| 模型路径 | apps/pf-face-service/models/scrfd_500m_bnkps.onnx |
FACE_MODEL_PATH |
| 推理输入尺寸 | 640 |
FACE_INPUT_SIZE |
| 下载图片超时 | 8000 ms |
FACE_DETECT_TIMEOUT_MS |
模型输出兼容策略(见 app/main.py):
- 自动归一
[N, C]与[1, N, C]两种 shape - 不兼容时启动阶段直接 fail-fast,避免运行期才暴露
部署
1 | cd apps/pf-face-service |
monorepo 一键启动:
1 | bun run --filter @wangijun/pf-face-service dev |
容器化建议:
- 基础镜像:
python:3.12-slim - 必装:
libgl1(OpenCV)、libglib2.0-0 - 入口:
uvicorn app.main:app --host 0.0.0.0 --port 3010 - 健康探针:
GET /health
性能
| 维度 | 表现 |
|---|---|
| 单图检测(CPU, i7 12 代) | ~ 60–100 ms |
| 内存占用 | 约 300–500 MB(含模型常驻) |
| 模型切换 | 替换 onnx 文件 + 重启 |
| GPU 加速 | 替换 ONNX Runtime 为 CUDA EP(可选) |
CPU 单实例即可满足绝大多数打印电商的请求量;高峰场景横向多实例 + 负载均衡。
安全与边界
- 接口本身不带鉴权——务必置于内网,前端调用必须经过
pf-service的/shared/face/detect - 下载图片失败 / 超时会返回明确错误码,不挂起
- 仅支持 HTTP/HTTPS URL;不接受 base64 / 文件上传(保持职责单一)
- 单进程单模型;多模型同时上线建议跑多副本而非进程内动态加载
二开提示
要换检测模型(例如想识别”二维码 / 文字行 / 物体”):
- 把同协议的 ONNX 模型放到
models/ - 在
app/main.py替换model_zoo调用,保持响应字段不变 - 升
modelVersion字段以便上游识别