- static/test_interface4.html: 上传照片 → 英文优先字段 + 全部42项特征表格 + 原始JSON - gateway/app.py: 首页索引增加 if4_features 测试页 - static/integration.html: 接入说明补充接口4测试页链接
278 lines
15 KiB
HTML
278 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>旷视五接口 — 前端接入说明</title>
|
||
<style>
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #f8f9fb; color: #1e293b; line-height: 1.6; }
|
||
.wrap { max-width: 960px; margin: 0 auto; padding: 32px 24px; }
|
||
|
||
h1 { font-size: 26px; margin-bottom: 8px; }
|
||
.subtitle { color: #64748b; font-size: 14px; margin-bottom: 32px; }
|
||
|
||
.card { background: #fff; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,.05); margin-bottom: 24px; overflow: hidden; }
|
||
.card h2 { font-size: 16px; padding: 16px 20px; border-bottom: 1px solid #f1f5f9; background: #fafbfc; }
|
||
.card-body { padding: 18px 20px; }
|
||
|
||
table { width: 100%; border-collapse: collapse; font-size: 13px; }
|
||
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid #f1f5f9; }
|
||
th { background: #f8fafc; font-weight: 700; color: #475569; font-size: 11px; text-transform: uppercase; letter-spacing: .5px; }
|
||
tr:last-child td { border-bottom: none; }
|
||
|
||
code { font-family: "SF Mono", "Fira Code", monospace; font-size: 12.5px; background: #f1f5f9; padding: 2px 6px; border-radius: 4px; color: #0f172a; }
|
||
pre { background: #1e293b; color: #e2e8f0; padding: 16px 20px; border-radius: 8px; font-family: "SF Mono", "Fira Code", monospace; font-size: 12.5px; line-height: 1.5; overflow-x: auto; }
|
||
|
||
.badge { display: inline-block; padding: 2px 10px; border-radius: 10px; font-size: 11px; font-weight: 700; }
|
||
.badge.post { background: #dbeafe; color: #1e40af; }
|
||
.badge.get { background: #d1fae5; color: #065f46; }
|
||
.badge.warn { background: #fef3c7; color: #92400e; }
|
||
|
||
.endpoint { margin-bottom: 20px; }
|
||
.endpoint .url { font-size: 15px; font-weight: 700; margin-bottom: 6px; }
|
||
.endpoint .desc { color: #64748b; font-size: 13px; margin-bottom: 10px; }
|
||
.endpoint .params { font-size: 12px; color: #94a3b8; margin-bottom: 8px; }
|
||
|
||
.link { color: #2563eb; text-decoration: none; font-size: 13px; }
|
||
.link:hover { text-decoration: underline; }
|
||
|
||
.toc { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 24px; }
|
||
.toc a { font-size: 13px; color: #2563eb; text-decoration: none; padding: 4px 12px; background: #eff6ff; border-radius: 6px; }
|
||
.toc a:hover { background: #dbeafe; }
|
||
|
||
hr { border: none; border-top: 1px solid #e2e8f0; margin: 20px 0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="wrap">
|
||
<h1>📡 旷视五接口 — 前端接入说明</h1>
|
||
<p class="subtitle">Base URL: <code>https://hair.xiangsilian.com</code> | 在线文档: <a href="/docs" class="link">/docs</a> | 在线测试页见底部</p>
|
||
|
||
<div class="toc">
|
||
<a href="#overview">通用约定</a>
|
||
<a href="#if1">接口1</a>
|
||
<a href="#if2">接口2</a>
|
||
<a href="#if3">接口3</a>
|
||
<a href="#if4">接口4</a>
|
||
<a href="#if5">接口5</a>
|
||
<a href="#errors">错误码</a>
|
||
<a href="#test">在线测试</a>
|
||
</div>
|
||
|
||
<!-- ======== 通用约定 ======== -->
|
||
<div class="card" id="overview">
|
||
<h2>🔧 通用约定</h2>
|
||
<div class="card-body">
|
||
<table>
|
||
<tr><td>协议</td><td>HTTPS</td></tr>
|
||
<tr><td>请求方式</td><td>全部 <span class="badge post">POST</span></td></tr>
|
||
<tr><td>编码</td><td>UTF-8</td></tr>
|
||
<tr><td>Content-Type</td><td><code>multipart/form-data</code></td></tr>
|
||
<tr><td>图片参数</td><td>三选一:<code>image_file</code>(文件上传)/ <code>image_url</code>(URL)/ <code>image_base64</code>(base64 + 前缀)</td></tr>
|
||
<tr><td>图片格式</td><td>JPG / PNG,≤ 1 MB,单人正面照</td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:14px;font-size:13px"><strong>统一响应结构</strong>:</p>
|
||
<pre>{
|
||
"code": 0, // 0=成功,非0=错误
|
||
"message": "success",
|
||
"request_id": "...", // 请求追踪 ID
|
||
"data": { ... } // 业务数据,各接口不同
|
||
}</pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ======== 接口1 ======== -->
|
||
<div class="card" id="if1">
|
||
<h2>1. 四庭七眼测量 <span class="badge post">POST</span> <code>/api/v1/face/measure</code></h2>
|
||
<div class="card-body">
|
||
<p class="desc">上传正面照 → 返回标注好的 PNG(仅标注图层,透明底)+ 四庭七眼厘米数值 + 关键点像素坐标。</p>
|
||
|
||
<p><strong>入参</strong></p>
|
||
<table>
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>image_file</td><td>file</td><td>三选一</td><td>上传图片文件</td></tr>
|
||
<tr><td>image_url</td><td>string</td><td>三选一</td><td>图片 URL</td></tr>
|
||
<tr><td>image_base64</td><td>string</td><td>三选一</td><td>base64 字符串,需带 data:image/...;base64, 前缀</td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:12px"><strong>data 字段</strong></p>
|
||
<table>
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td><code>annotated_image_url</code></td><td>string</td><td>标注 PNG URL(仅标注图层,透明底,叠加到原图上显示)</td></tr>
|
||
<tr><td><code>face_total_height_cm</code></td><td>number</td><td>全脸高度(cm)</td></tr>
|
||
<tr><td><code>four_courts</code></td><td>object</td><td>四庭:top/upper/middle/lower,各含 _cm 和 ratios</td></tr>
|
||
<tr><td><code>seven_eyes</code></td><td>object</td><td>七眼:eye_width/face_width/inter_eye_distance,各含 _cm 和 ratios</td></tr>
|
||
<tr><td><code>landmarks</code></td><td>object</td><td>5 个关键点像素坐标:hair_top/hairline/brow_center/nose_bottom/chin_tip</td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:12px;font-size:12px;color:#64748b">💡 前端把标注图叠加到原图上即可呈现测量效果(标注图白色线条 #FFFFFF,透明底)。</p>
|
||
|
||
<p style="margin-top:8px"><strong>请求示例</strong>(fetch):</p>
|
||
<pre>const fd = new FormData();
|
||
fd.append('image_file', file); // 或 image_url / image_base64
|
||
|
||
const res = await fetch('https://hair.xiangsilian.com/api/v1/face/measure', {
|
||
method: 'POST',
|
||
body: fd
|
||
});
|
||
const { code, data } = await res.json();
|
||
// data.annotated_image_url → 标注 PNG
|
||
// data.face_total_height_cm → 全脸高度
|
||
// data.four_courts.ratios → { top_court: 0.25, ... }
|
||
// 前端叠加显示:原图 + annotated_image_url(absolute 叠加)</pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ======== 接口2 ======== -->
|
||
<div class="card" id="if2">
|
||
<h2>2. C端生发 <span class="badge post">POST</span> <code>/api/v1/hair/grow</code></h2>
|
||
<div class="card-body">
|
||
<p class="desc">上传正面照 + 性别 → 多组发际线方案。每组含发际线叠加预览图 + ComfyUI 生发效果图。</p>
|
||
|
||
<p><strong>入参</strong></p>
|
||
<table>
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>image_file / image_url / image_base64</td><td>—</td><td>三选一</td><td>用户正面照</td></tr>
|
||
<tr><td>gender</td><td>string</td><td>✅ 必填</td><td><code>"male"</code> / <code>"female"</code></td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:12px"><strong>data.results[] 元素</strong></p>
|
||
<table>
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td><code>image_url</code></td><td>string</td><td>发际线叠加预览图(曲线叠在原图上)</td></tr>
|
||
<tr><td><code>grown_image_url</code></td><td>string</td><td>生发后效果图(ComfyUI/Flux「植发3个月」)⚠ 可空</td></tr>
|
||
<tr><td><code>hairline_type</code></td><td>string</td><td>发际线类型 key</td></tr>
|
||
<tr><td><code>order</code></td><td>int</td><td>排序(1=最佳,当前按贴图顺序)</td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:8px;font-size:12px;color:#64748b">
|
||
Female 5 种:ellipse/flower/heart/straight/wave |
|
||
Male 4 种:ellipse/m/straight/inverse_arc<br>
|
||
⚠ 生发图由本机 ComfyUI 生成,耗时可达数分钟,fetch 超时需放大(≥5min)。
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ======== 接口3 ======== -->
|
||
<div class="card" id="if3">
|
||
<h2>3. B端生发(医生端) <span class="badge post">POST</span> <code>/api/v1/hair/grow-b</code></h2>
|
||
<div class="card-body">
|
||
<p class="desc">医生用马克笔在用户照片额头画线 → 拍照上传 → 系统生成生发效果图。</p>
|
||
|
||
<p><strong>入参</strong></p>
|
||
<table>
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>marked_image_file / marked_image_url / marked_image_base64</td><td>—</td><td>✅ 三选一</td><td>已用马克笔标注发际线的图片</td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:12px"><strong>data 字段</strong></p>
|
||
<table>
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td><code>hair_growth_image_url</code></td><td>string</td><td>生发后效果图 URL ⚠ 可空</td></tr>
|
||
<tr><td><code>hairline_type</code></td><td>string</td><td>固定 <code>"custom"</code>(手绘定制)</td></tr>
|
||
</table>
|
||
|
||
<p style="font-size:12px;color:#64748b">⚠ 划线图未检测到划线(或无人脸)→ code=1001</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ======== 接口4 ======== -->
|
||
<div class="card" id="if4">
|
||
<h2>4. 用户特征分析 <span class="badge post">POST</span> <code>/api/v1/face/features</code></h2>
|
||
<div class="card-body">
|
||
<p class="desc">上传照片 → 火山方舟豆包视觉模型分析 → 返回几十项面部特征(脸型/眉形/肤色/四季色彩…)。</p>
|
||
|
||
<p><strong>入参</strong>:image_file / image_url / image_base64 三选一。无其他参数。</p>
|
||
|
||
<p style="margin-top:12px"><strong>data 字段</strong></p>
|
||
<table>
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td><code>features</code></td><td>string</td><td><strong>JSON 字符串</strong>(不是对象!客户端需 <code>JSON.parse()</code>)</td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:8px"><strong>features 英文优先字段</strong>(其余中文字段同时返回,共~42个):</p>
|
||
<table>
|
||
<tr><th>字段</th><th>说明</th><th>字段</th><th>说明</th></tr>
|
||
<tr><td>face_shape</td><td>脸型</td><td>eyebrow_shape</td><td>眉形</td></tr>
|
||
<tr><td>facial_age</td><td>面部年龄区间</td><td>gender</td><td>性别</td></tr>
|
||
<tr><td>dynamic_static_type</td><td>动静类型</td><td>gene_style</td><td>基因风格</td></tr>
|
||
</table>
|
||
|
||
<pre>const res = await fetch('https://hair.xiangsilian.com/api/v1/face/features', {
|
||
method: 'POST',
|
||
body: fd
|
||
});
|
||
const { code, data } = await res.json();
|
||
const features = JSON.parse(data.features); // ← 注意:data.features 是字符串!
|
||
console.log(features.face_shape); // "鹅蛋脸"
|
||
console.log(features['四季色彩季型']); // "冷夏型"(中文字段也保留)</pre>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ======== 接口5 ======== -->
|
||
<div class="card" id="if5">
|
||
<h2>5. 发际线 PNG 生成 <span class="badge post">POST</span> <code>/api/v1/hairline/generate</code></h2>
|
||
<div class="card-body">
|
||
<p class="desc">上传正面照 + 性别 → N 张发际线叠加图 + 最佳发际线中心点坐标。</p>
|
||
|
||
<p><strong>入参</strong></p>
|
||
<table>
|
||
<tr><th>参数</th><th>类型</th><th>必填</th><th>说明</th></tr>
|
||
<tr><td>image_file / image_url / image_base64</td><td>—</td><td>三选一</td><td>用户正面照</td></tr>
|
||
<tr><td>gender</td><td>string</td><td>✅ 必填</td><td><code>"male"</code> / <code>"female"</code></td></tr>
|
||
</table>
|
||
|
||
<p style="margin-top:12px"><strong>data 字段</strong></p>
|
||
<table>
|
||
<tr><th>字段</th><th>类型</th><th>说明</th></tr>
|
||
<tr><td><code>hairline_images[]</code></td><td>object[]</td><td>发际线叠加图列表,每项含 image_url + order</td></tr>
|
||
<tr><td><code>best_hairline_center_point</code></td><td>object</td><td>最佳发际线中心点像素坐标 <code>{ x: number, y: number }</code></td></tr>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ======== 错误码 ======== -->
|
||
<div class="card" id="errors">
|
||
<h2>⚠ 错误码</h2>
|
||
<div class="card-body">
|
||
<table>
|
||
<tr><th>code</th><th>message</th><th>说明</th></tr>
|
||
<tr><td>1001</td><td>无法识别人像</td><td>未检测到人脸</td></tr>
|
||
<tr><td>1002</td><td>人像分辨率过低</td><td>低于最低分辨率</td></tr>
|
||
<tr><td>1003</td><td>角度问题,非正面照</td><td>非正面 / 角度过大</td></tr>
|
||
<tr><td>1005</td><td>检测到多张人脸</td><td>仅支持单人</td></tr>
|
||
<tr><td>1006</td><td>文件超出大小限制</td><td>单文件 > 1 MB</td></tr>
|
||
<tr><td>1007</td><td>图片参数错误 / 后端不可用</td><td>参数传错 / 服务繁忙请稍后重试</td></tr>
|
||
<tr><td>1008</td><td>图片格式不支持</td><td>非 JPG/PNG / base64 解码失败</td></tr>
|
||
</table>
|
||
<p style="font-size:12px;color:#94a3b8;margin-top:8px">1004 已废弃(接口2 不再自动判性别,改由客户端传 gender 参数)。</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ======== 在线测试页 ======== -->
|
||
<div class="card" id="test">
|
||
<h2>🧪 在线测试页面</h2>
|
||
<div class="card-body">
|
||
<table>
|
||
<tr><th>接口</th><th>测试页</th><th>功能</th></tr>
|
||
<tr><td>1. 四庭七眼</td><td><a href="/static/test_interface1.html" class="link">/static/test_interface1.html</a></td><td>上传照片 → 原图+标注叠加,底图/标注开关,指标卡片</td></tr>
|
||
<tr><td>2. C端生发</td><td><a href="/static/test_interface2.html" class="link">/static/test_interface2.html</a></td><td>上传+性别 → 方案一覧(原图/叠加/生发),双图对比</td></tr>
|
||
<tr><td>3. B端生发</td><td><a href="/static/test_interface3.html" class="link">/static/test_interface3.html</a></td><td>划线图上传 → 生发效果图</td></tr>
|
||
<tr><td>4. 用户特征</td><td><a href="/static/test_interface4.html" class="link">/static/test_interface4.html</a></td><td>上传照片 → 42项面部特征表格 + 原始JSON</td></tr>
|
||
<tr><td>5. 发际线PNG</td><td><a href="/static/test_interface5.html" class="link">/static/test_interface5.html</a></td><td>上传+性别 → 发际线方案+中心点坐标</td></tr>
|
||
</table>
|
||
<p style="font-size:12px;color:#94a3b8;margin-top:12px">
|
||
完整 API 文档:<a href="/docs" class="link">/docs</a>(Swagger UI)
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<p style="text-align:center;font-size:12px;color:#cbd5e1;margin-top:32px">
|
||
Base: https://hair.xiangsilian.com | Swagger: /docs | 接入说明: /static/integration.html
|
||
</p>
|
||
</div>
|
||
</body>
|
||
</html>
|