feat(接口4): 新增轮廓类型 contour_type + 提示词防漏键加固
- 豆包提示词追加「轮廓类型(轮廓偏曲/轮廓适中/轮廓偏直)」,_KEY_MAP 映射为 contour_type - 提示词显式要求包含全部键:实测豆包随机漏键(面部年龄历史 ~26% 缺失),加固后 9/9 次全字段返回 - 同步接口文档/测试页至 7 字段;测试页顺带移除硬编码内部密码
This commit is contained in:
+5
-4
@@ -365,7 +365,7 @@
|
||||
|
||||
### 输出(data)
|
||||
|
||||
`data.features` 是一个 **JSON 字符串**(不是对象,客户端 `JSON.parse()` 后用),**仅含以下 6 个英文字段**:
|
||||
`data.features` 是一个 **JSON 字符串**(不是对象,客户端 `JSON.parse()` 后用),**仅含以下 7 个英文字段**:
|
||||
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
@@ -375,6 +375,7 @@
|
||||
| dynamic_static_type | 动静类型(静态型/动态型)|
|
||||
| gender | 性别(男/女)|
|
||||
| gene_style | 基因风格(如"自然型")|
|
||||
| contour_type | 轮廓类型(轮廓偏曲/轮廓适中/轮廓偏直)|
|
||||
|
||||
> 无人脸返回 `1001`(据 doubao「图片是否有人脸」判定)。⚠️ 本接口是唯一调**外网云模型**的接口,
|
||||
> worker 需可访问 `ark.cn-beijing.volces.com`;API Key 走 worker 配置/环境变量。
|
||||
@@ -387,12 +388,12 @@
|
||||
"message": "success",
|
||||
"request_id": "mock-request-id",
|
||||
"data": {
|
||||
"features": "{\"face_shape\":\"鹅蛋脸\",\"eyebrow_shape\":\"平眉\",\"facial_age\":\"18-25岁\",\"dynamic_static_type\":\"静态型\",\"gender\":\"女\",\"gene_style\":\"少年型\"}"
|
||||
"features": "{\"face_shape\":\"鹅蛋脸\",\"eyebrow_shape\":\"平眉\",\"facial_age\":\"18-25岁\",\"dynamic_static_type\":\"静态型\",\"gender\":\"女\",\"gene_style\":\"少年型\",\"contour_type\":\"轮廓适中\"}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> `features` 为字符串形式的 JSON,固定上述 6 个字段。
|
||||
> `features` 为字符串形式的 JSON,固定上述 7 个字段。
|
||||
|
||||
---
|
||||
|
||||
@@ -700,7 +701,7 @@
|
||||
| 2 C 端生发 | `/api/v1/hair/grow` | 用户照片 + gender + hair_style(多选) | 每发型预览 PNG + 生发图(female 1..5=换发型+重绘,其余=原生生发) |
|
||||
| 7 C 端生发 v2 | `/api/v1/hair/grow-v2` | 同接口2 | 同接口2(add_hair2 工作流,已弃用隐藏) |
|
||||
| 3 B 端生发 | `/api/v1/hair/grow-b` | 划线图片 | 检测到的发际线 + 生发后图片 |
|
||||
| 4 用户特征 | `/api/v1/face/features` | 用户照片 | 6 个用户特征字段(脸形/眉形/年龄/动静/性别/基因风格),网关本机实现 |
|
||||
| 4 用户特征 | `/api/v1/face/features` | 用户照片 | 7 个用户特征字段(脸形/眉形/年龄/动静/性别/基因风格/轮廓类型),网关本机实现 |
|
||||
| 5 发际线 PNG | `/api/v1/hairline/generate` | 用户照片 + gender + hair_style(多选) | 每个选中发型 middle/high/low 三档发际线叠图 + 生发图 + 最合适发际线面部中间点坐标 |
|
||||
| 9 头发遮罩 | `/api/v1/head/mask` | 用户照片 | 头发遮罩 + 分步可视化(BiSeNet/SegFormer 双路) |
|
||||
| 10 外缘膨胀带 | `/api/v1/head/band` | 用户照片 | 头部外缘带状遮罩 + 分步可视化 |
|
||||
|
||||
+12
-7
@@ -1,6 +1,6 @@
|
||||
"""接口4:用户面部特征分析。
|
||||
|
||||
- 眉形 / 面部年龄 / 动静类型 / 性别 / 基因风格:火山方舟豆包视觉模型
|
||||
- 眉形 / 面部年龄 / 动静类型 / 性别 / 基因风格 / 轮廓类型:火山方舟豆包视觉模型
|
||||
- face_shape(脸型):本机 MediaPipe 分类(face/face_shape_classifier.py)覆盖,
|
||||
不用豆包结果
|
||||
|
||||
@@ -26,15 +26,20 @@ _KEY_MAP = {
|
||||
"动静类型": "dynamic_static_type",
|
||||
"性别": "gender",
|
||||
"基因风格": "gene_style",
|
||||
"轮廓类型": "contour_type",
|
||||
}
|
||||
|
||||
# 豆包只问 5 项 + 是否有人脸;脸型由本地分类器给出
|
||||
# 豆包只问 6 项 + 是否有人脸;脸型由本地分类器给出。
|
||||
# 「必须包含全部键」:实测豆包会随机漏键(尤其面部年龄,历史 ~26% 缺失),
|
||||
# 显式要求可显著降低漏键率。
|
||||
_PROMPT = (
|
||||
"分析一下图片告诉我以下特征,只要答案,格式为json字符串,"
|
||||
"必须包含以下全部键且每键都要有值、缺一不可:"
|
||||
"图片是否有人脸(有人/没人) "
|
||||
"眉形 "
|
||||
"面部年龄(给出区间年龄) 动静类型(静态型/动态型) 性别(男/女) "
|
||||
"基因风格(戏剧型/睿智型/自然型/古典型/优雅型/浪漫型/前卫型/少女型/少年型)"
|
||||
"面部年龄(给出区间年龄,如18-25岁) 动静类型(静态型/动态型) 性别(男/女) "
|
||||
"基因风格(戏剧型/睿智型/自然型/古典型/优雅型/浪漫型/前卫型/少女型/少年型) "
|
||||
"轮廓类型(轮廓偏曲/轮廓适中/轮廓偏直)"
|
||||
)
|
||||
|
||||
_client = None # 缓存的 Ark client(api_key 变更时自动重建)
|
||||
@@ -137,10 +142,10 @@ def _local_face_shape(image_bytes: bytes = None, image_url: str = None) -> str:
|
||||
|
||||
|
||||
def analyze_features(image_bytes: bytes = None, image_url: str = None):
|
||||
"""豆包分析 5 项特征 + 本机 MediaPipe 覆盖 face_shape。
|
||||
"""豆包分析 6 项特征 + 本机 MediaPipe 覆盖 face_shape。
|
||||
|
||||
Returns: dict —— 6 个英文字段(face_shape/eyebrow_shape/facial_age/
|
||||
dynamic_static_type/gender/gene_style);**无人脸返回 None**(调用方据此判 1001)。
|
||||
Returns: dict —— 7 个英文字段(face_shape/eyebrow_shape/facial_age/
|
||||
dynamic_static_type/gender/gene_style/contour_type);**无人脸返回 None**(调用方据此判 1001)。
|
||||
"""
|
||||
url = _image_to_url(image_bytes, image_url)
|
||||
resp = get_client().chat.completions.create(
|
||||
|
||||
+1
-1
@@ -493,7 +493,7 @@ async def face_features(
|
||||
image_url: Optional[str] = Form(default=None, description="图片 URL"),
|
||||
image_base64: Optional[str] = Form(default=None, description="图片 base64(需带前缀)"),
|
||||
):
|
||||
"""接口4:用户特征分析 — 豆包 5 项 + 本机 MediaPipe 脸型(face/),不经过 worker。"""
|
||||
"""接口4:用户特征分析 — 豆包 6 项 + 本机 MediaPipe 脸型(face/),不经过 worker。"""
|
||||
import uuid as _uuid
|
||||
|
||||
# 三选一校验
|
||||
|
||||
@@ -112,10 +112,10 @@
|
||||
<script>
|
||||
const API_BASE = window.location.origin;
|
||||
|
||||
const EN_KEYS = ['face_shape','eyebrow_shape','facial_age','dynamic_static_type','gender','gene_style'];
|
||||
const EN_KEYS = ['face_shape','eyebrow_shape','facial_age','dynamic_static_type','gender','gene_style','contour_type'];
|
||||
const EN_LABELS = {
|
||||
face_shape:'脸型', eyebrow_shape:'眉形', facial_age:'面部年龄',
|
||||
dynamic_static_type:'动静类型', gender:'性别', gene_style:'基因风格'
|
||||
dynamic_static_type:'动静类型', gender:'性别', gene_style:'基因风格', contour_type:'轮廓类型'
|
||||
};
|
||||
|
||||
function $(id) { return document.getElementById(id); }
|
||||
@@ -133,7 +133,7 @@ async function submitTest() {
|
||||
const fd = new FormData(); fd.append('image_file', f);
|
||||
const _reqStart = performance.now();
|
||||
try {
|
||||
const r = await fetch(API_BASE + '/api/v1/face/features', { method:'POST', headers: { 'X-Internal-Token': 'dev-shared-secret-2026' }, body:fd });
|
||||
const r = await fetch(API_BASE + '/api/v1/face/features', { method:'POST', body:fd });
|
||||
const json = await r.json();
|
||||
const _elapsed = ((performance.now() - _reqStart) / 1000).toFixed(2);
|
||||
$('jsonContent').textContent = JSON.stringify(json, null, 2);
|
||||
|
||||
Reference in New Issue
Block a user