feat: 拆分接口11/12,新增接口12 final / final v2 精简重绘端点
- 接口11 移除重绘,仅生成 final;接口12 (grow_v2) 负责发际线带 Flux-2 重绘 - 接口12 重绘带改为发际线外推 band_lo_mult~band_hi_mult 倍 push(默认 0.5~1.5),页面可调 - 接口12 同时产出 A 整帧重绘 与 B 局部加发+全脸美颜(beauty_alpha 可调) - 新增 grow_v2_final(整帧重绘)/ grow_v2_final_v2(B 局部+美颜)端点:仅需图片+发型 ID,其余用固化默认值(color_match 关闭) - 配套精简测试页 test_interface12_final.html / test_interface12_final_v2.html / test_interface12.html - 恢复接口11 调试页多频段与换发型可调参数、color_match 默认不勾选 - 删除旧脚本 batch_grow_v2.py / gen_report_hairline_v2.py / test_simple.html Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>接口12 final v2 — 发际线带重绘(局部加发+全脸美颜)</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #f5f5f5; color: #333; }
|
||||
.container { max-width: 1240px; margin: 0 auto; padding: 24px; }
|
||||
h1 { font-size: 22px; margin-bottom: 4px; }
|
||||
h2 { font-size: 16px; margin: 20px 0 12px; }
|
||||
.subtitle { color: #888; font-size: 13px; margin-bottom: 16px; line-height: 1.6; }
|
||||
.card { background: #fff; border-radius: 12px; padding: 20px; box-shadow: 0 1px 4px rgba(0,0,0,.06); margin-bottom: 20px; }
|
||||
.upload-row { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
|
||||
input[type=file] { flex: 1; min-width: 200px; padding: 8px; border: 2px dashed #ddd; border-radius: 8px; cursor: pointer; }
|
||||
.btn { padding: 10px 20px; border: none; border-radius: 8px; font-size: 14px; cursor: pointer; font-weight: 600; }
|
||||
.btn-primary { background: #7c3aed; color: #fff; }
|
||||
.btn-primary:disabled { background: #c4b5fd; cursor: not-allowed; }
|
||||
.btn-outline { background: #fff; border: 1px solid #d1d5db; color: #374151; }
|
||||
.btn-green { background: #059669; color: #fff; }
|
||||
.params { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 14px; margin-top: 16px; }
|
||||
.pf { display: flex; flex-direction: column; gap: 4px; }
|
||||
.pf label { font-size: 13px; font-weight: 600; }
|
||||
.pf select { padding: 8px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; }
|
||||
.status { padding: 10px 16px; border-radius: 8px; font-size: 14px; margin-bottom: 16px; display: none; font-family: monospace; }
|
||||
.status.info { background: #ede9fe; color: #5b21b6; display: block; }
|
||||
.status.error { background: #fee2e2; color: #991b1b; display: block; }
|
||||
.status.success { background: #d1fae5; color: #065f46; display: block; }
|
||||
.steps { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
|
||||
.step { background: #fff; border-radius: 10px; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
|
||||
.step .cap { font-size: 13px; font-weight: 600; padding: 8px 12px; background: #fafafa; border-bottom: 1px solid #f0f0f0; }
|
||||
.step .cap small { color: #999; font-weight: 400; display:block; margin-top:2px; }
|
||||
.step img { width: 100%; display: block; background: #eee; cursor: zoom-in; }
|
||||
.big img { max-height: 520px; object-fit: contain; }
|
||||
.lightbox { position: fixed; inset: 0; background: rgba(0,0,0,.85); display: none; align-items: center; justify-content: center; z-index: 50; cursor: zoom-out; }
|
||||
.lightbox img { max-width: 95%; max-height: 95%; }
|
||||
.hidden { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>接口12 final v2 — 发际线带重绘 <span style="font-size:13px;color:#888">(局部加发+全脸美颜)</span></h1>
|
||||
<div class="subtitle">
|
||||
只需上传图片 + 选择发型,其余参数全部用当前调优默认值(<code>/api/v1/hairline/grow_v2_final_v2</code>)。<br>
|
||||
重绘输出为 <b>B 局部加发+全脸美颜</b>(加发只在发际线带、band 外保留 final 结构并叠加全脸美颜)。⚠️ 需 ComfyUI(:8188) 在跑。
|
||||
整帧重绘版见 <a href="/static/test_interface12_final.html">接口12 final</a>;完整参数调试见 <a href="/static/test_interface12.html">接口12 调试页</a>。
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="upload-row">
|
||||
<input type="file" id="imageFile" accept="image/*">
|
||||
<button class="btn btn-primary" id="submitBtn" onclick="submitTest()">🎨 提交重绘</button>
|
||||
</div>
|
||||
<div class="params">
|
||||
<div class="pf">
|
||||
<label>发际线类型 ID</label>
|
||||
<select id="hairlineId">
|
||||
<option value="chang_bolang" selected>chang_bolang(波浪)</option>
|
||||
<option value="chang_zhixian">chang_zhixian(直线)</option>
|
||||
<option value="chang_tuoyuan">chang_tuoyuan(椭圆)</option>
|
||||
<option value="chang_xinxing">chang_xinxing(心形)</option>
|
||||
<option value="chang_huaban">chang_huaban(花瓣)</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status" id="statusBar"></div>
|
||||
|
||||
<div id="resultsArea" class="hidden">
|
||||
<div class="card">
|
||||
<h2 style="margin-top:0">🎯 局部加发+全脸美颜结果</h2>
|
||||
<div class="steps" style="grid-template-columns: repeat(auto-fill, minmax(300px, 1fr))">
|
||||
<div class="step big"><div class="cap">接口11 final <small>④ 接缝融合(重绘输入基底,无美颜)</small></div><img id="finalBase"></div>
|
||||
<div class="step big"><div class="cap">B · 局部加发+全脸美颜 <small>加发只在发际线带、美颜保留全脸</small></div><img id="outBand"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="lightbox" id="lightbox" onclick="this.style.display='none'"><img id="lightboxImg" alt=""></div>
|
||||
|
||||
<script>
|
||||
const API_BASE = window.location.origin;
|
||||
const ENDPOINT = '/api/v1/hairline/grow_v2_final_v2';
|
||||
const TOKEN = 'dev-shared-secret-2026';
|
||||
|
||||
function $(id) { return document.getElementById(id); }
|
||||
function setStatus(text, type) { const b = $('statusBar'); b.textContent = text; b.className = 'status ' + type; }
|
||||
function pick(obj, name) { if (!obj) return null; return obj[name + '_url'] || obj[name + '_base64'] || null; }
|
||||
function zoom(src) { $('lightboxImg').src = src; $('lightbox').style.display = 'flex'; }
|
||||
|
||||
function renderResult(d) {
|
||||
const s = d.steps || {};
|
||||
$('finalBase').src = pick(s, 'final') || '';
|
||||
$('finalBase').onclick = function(){ zoom(this.src); };
|
||||
$('outBand').src = pick(s, 'redraw_band') || '';
|
||||
$('outBand').onclick = function(){ zoom(this.src); };
|
||||
}
|
||||
|
||||
async function submitTest() {
|
||||
const file = $('imageFile').files[0];
|
||||
if (!file) { setStatus('请先选择图片', 'error'); return; }
|
||||
|
||||
const btn = $('submitBtn');
|
||||
btn.disabled = true; btn.textContent = '⏳ 重绘中...';
|
||||
setStatus('正在请求(内部先跑接口11,再 Flux-2 重绘,约 15~30s)...', 'info');
|
||||
$('resultsArea').classList.remove('hidden');
|
||||
|
||||
const form = new FormData();
|
||||
form.append('image_file', file);
|
||||
form.append('hairline_id', $('hairlineId').value);
|
||||
|
||||
const t0 = performance.now();
|
||||
try {
|
||||
const resp = await fetch(API_BASE + ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: { 'X-Internal-Token': TOKEN },
|
||||
body: form,
|
||||
});
|
||||
const json = await resp.json();
|
||||
const dt = ((performance.now() - t0) / 1000).toFixed(2);
|
||||
|
||||
if (json.code === 0) {
|
||||
const d = json.data;
|
||||
const okRedraw = d.redraw && d.redraw.enabled && !d.redraw.c_error && pick(d.steps, 'redraw_band');
|
||||
setStatus((okRedraw ? '✅ 局部加发+全脸美颜成功' : '⚠️ 已返回(重绘可能未生效)') + ' (' + dt + 's)', okRedraw ? 'success' : 'error');
|
||||
renderResult(d);
|
||||
} else {
|
||||
setStatus('❌ 业务错误 code=' + json.code + ':' + json.message, 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
setStatus('❌ 网络错误: ' + err.message, 'error');
|
||||
} finally {
|
||||
btn.disabled = false; btn.textContent = '🎨 提交重绘';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user