From ebcaff1295b5edf11b1c0de911a0cff21cf31326 Mon Sep 17 00:00:00 2001 From: xsl Date: Mon, 7 Sep 2026 00:35:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=8E=A5=E5=8F=A34):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=BD=AE=E5=BB=93=E7=B1=BB=E5=9E=8B=20contour=5Ftype=20+=20?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D=E9=98=B2=E6=BC=8F=E9=94=AE=E5=8A=A0?= =?UTF-8?q?=E5=9B=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 豆包提示词追加「轮廓类型(轮廓偏曲/轮廓适中/轮廓偏直)」,_KEY_MAP 映射为 contour_type - 提示词显式要求包含全部键:实测豆包随机漏键(面部年龄历史 ~26% 缺失),加固后 9/9 次全字段返回 - 同步接口文档/测试页至 7 字段;测试页顺带移除硬编码内部密码 --- docs/接口文档.md | 9 +++++---- face_features.py | 19 ++++++++++++------- gateway/app.py | 2 +- static/test_interface4.html | 6 +++--- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/docs/接口文档.md b/docs/接口文档.md index b02a46c..4924577 100644 --- a/docs/接口文档.md +++ b/docs/接口文档.md @@ -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` | 用户照片 | 头部外缘带状遮罩 + 分步可视化 | diff --git a/face_features.py b/face_features.py index d3bf0a0..61e6074 100644 --- a/face_features.py +++ b/face_features.py @@ -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( diff --git a/gateway/app.py b/gateway/app.py index 236b925..f3c2e32 100644 --- a/gateway/app.py +++ b/gateway/app.py @@ -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 # 三选一校验 diff --git a/static/test_interface4.html b/static/test_interface4.html index 822d77c..f5ab72c 100644 --- a/static/test_interface4.html +++ b/static/test_interface4.html @@ -112,10 +112,10 @@