Files
hair/static/test_interface12_final_v2.html
T
xslandCursor 659c037270 feat: ComfyUI 改走 10.60.74.221,测试页上传图超阈值自动降采样
将 worker 默认 ComfyUI 地址改为远端 10.60.74.221:8188;前端测试页在像素超过 1536000 时等比缩小到 786432 以内。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-17 02:23:35 +08:00

144 lines
7.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>
<script src="/static/img_downscale.js"></script>
</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() {
let file = $('imageFile').files[0];
if (!file) { setStatus('请先选择图片', 'error'); return; }
file = await window.downscaleImageFile(file);
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>