优化为4b 模型
This commit is contained in:
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -53,11 +53,11 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>接口12 — 发际线带重绘 <span style="font-size:13px;color:#888">(final + 纯红遮罩 → 外部 ComfyUI 重绘)</span></h1>
|
||||
<h1>接口12 — 发际线带重绘 <span style="font-size:13px;color:#888">(final + 纯红遮罩 → ComfyUI 重绘)</span></h1>
|
||||
<div class="subtitle">
|
||||
内部先跑<b>接口11</b>拿到 ④接缝融合最终图(final),再取 <b>⑤-① 发际线重绘带</b>(发际线外推 band_lo_mult×push ~ band_hi_mult×push、经 baseline 截断只留上部)生成
|
||||
<b>纯红遮罩 PNG</b>(遮罩区=(255,0,0,255),其余全透明)。<br>
|
||||
前端拿到 final + 遮罩后,调 <b>外部重绘服务(local_test,默认 :8899)</b>完成重绘。⚠️ 需 ComfyUI(:8188) 在跑。
|
||||
前端拿到 final + 遮罩后,调 <b>后端重绘接口(/api/v1/redraw)</b>完成重绘。⚠️ 需 ComfyUI(:8188) 在跑。
|
||||
对照仅生成不重绘:<a href="/static/test_interface11_debug.html">接口11 调试页</a>。
|
||||
</div>
|
||||
|
||||
@@ -65,11 +65,7 @@
|
||||
<div class="upload-row">
|
||||
<input type="file" id="imageFile" accept="image/*">
|
||||
<button class="btn btn-primary" id="submitBtn" onclick="submitTest()">🎨 生成 final+遮罩</button>
|
||||
<button class="btn btn-green" id="redrawBtn" onclick="runLocalRedraw()" disabled>🧪 调 local_test 重绘</button>
|
||||
</div>
|
||||
<div class="upload-row" style="margin-top:10px">
|
||||
<label style="font-size:13px;font-weight:600;white-space:nowrap">重绘服务地址</label>
|
||||
<input type="text" id="localTestUrl" value="http://10.60.74.221:8899" style="flex:1;min-width:200px;padding:8px;border:1px solid #ddd;border-radius:8px">
|
||||
<button class="btn btn-green" id="redrawBtn" onclick="runLocalRedraw()" disabled>🧪 重绘</button>
|
||||
</div>
|
||||
<div class="upload-row" style="margin-top:10px">
|
||||
<label style="font-size:13px;font-weight:600;white-space:nowrap">重绘提示词</label>
|
||||
@@ -144,9 +140,9 @@
|
||||
<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">⑤-① 发际线重绘带遮罩 <small>纯红 alpha PNG(遮罩区=红+不透明,其余全透明)</small></div><img id="maskPng"></div>
|
||||
<div class="step big"><div class="cap">🧪 local_test 重绘结果 <small>final + 遮罩 → 外部 ComfyUI(0716add-hair.json)</small></div><img id="localResult"></div>
|
||||
<div class="step big"><div class="cap">🧪 重绘结果 <small>final + 遮罩 → ComfyUI(0716add-hair)</small></div><img id="localResult"></div>
|
||||
</div>
|
||||
<div style="font-size:12px;color:#888;margin-top:10px">流程:后端产出 final(接缝融合基底)+ 纯红遮罩 PNG,前端把两者 POST 到 local_test 重绘服务完成发际线补发。</div>
|
||||
<div style="font-size:12px;color:#888;margin-top:10px">流程:后端产出 final(接缝融合基底)+ 纯红遮罩 PNG,再调后端 /api/v1/redraw 完成发际线补发。</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
@@ -191,10 +187,10 @@ const STEPS = [
|
||||
{ key: 'input', title: '原图', sub: '接口输入' },
|
||||
{ key: 'final', title: '接口11 ④ final', sub: '接缝融合最终图(重绘输入基底,无美颜)' },
|
||||
{ key: 'redraw_band_overlay', title: '⑤-① 发际线重绘带', sub: '紫=lo×push↔hi×push之间、经 baseline 截断只留上部' },
|
||||
{ key: 'redraw_band_mask', title: '⑤-② 纯红遮罩 PNG', sub: '遮罩区=(255,0,0,255)、其余全透明;交给 local_test' },
|
||||
{ key: 'redraw_band_mask', title: '⑤-② 纯红遮罩 PNG', sub: '遮罩区=(255,0,0,255)、其余全透明;交给后端重绘' },
|
||||
];
|
||||
|
||||
// 缓存最近一次后端返回的 final(JPG data URI)和纯红遮罩(PNG data URI),供 local_test 重绘使用
|
||||
// 缓存最近一次后端返回的 final(JPG data URI)和纯红遮罩(PNG data URI),供重绘使用
|
||||
let _finalDataUri = '';
|
||||
let _maskDataUri = '';
|
||||
|
||||
@@ -237,7 +233,7 @@ function renderResult(d) {
|
||||
flog(' 渲染 ' + st.key + ': ' + (hasImg ? '有图(' + src.length + '字符)' : '无图'), hasImg ? 'info' : 'warn');
|
||||
grid.appendChild(stepCard(st.title, st.sub, src));
|
||||
});
|
||||
// final + 遮罩 都有 → 允许调 local_test 重绘
|
||||
// final + 遮罩 都有 → 允许调后端重绘
|
||||
const canRedraw = !!(finalSrc && maskSrc);
|
||||
$('redrawBtn').disabled = !canRedraw;
|
||||
flog('renderResult 完成 canRedraw=' + canRedraw, 'info');
|
||||
@@ -346,7 +342,7 @@ async function submitTest() {
|
||||
}
|
||||
}
|
||||
|
||||
// data URI → Blob,用于把后端返回的 final/遮罩图作为文件 POST 给 local_test
|
||||
// data URI → Blob,用于把后端返回的 final/遮罩图作为文件 POST 给后端重绘
|
||||
function dataUriToBlob(dataUri) {
|
||||
const [meta, b64] = dataUri.split(',');
|
||||
const mime = (meta.match(/data:([^;]+)/) || [, 'application/octet-stream'])[1];
|
||||
@@ -358,44 +354,39 @@ function dataUriToBlob(dataUri) {
|
||||
|
||||
async function runLocalRedraw() {
|
||||
if (!_finalDataUri || !_maskDataUri) { setStatus('缺少 final 或遮罩,请先生成', 'error'); return; }
|
||||
const base = $('localTestUrl').value.trim().replace(/\/+$/, '');
|
||||
if (!base) { setStatus('请填写重绘服务地址', 'error'); return; }
|
||||
const prompt = $('localTestPrompt').value.trim() || '填充遮罩区域的头发,皮肤加一点磨皮';
|
||||
const btn = $('redrawBtn');
|
||||
btn.disabled = true; btn.textContent = '⏳ 重绘中...';
|
||||
flog('===== 调 local_test 重绘 =====', 'info');
|
||||
flog('服务地址=' + base + ' 提示词=' + prompt, 'info');
|
||||
flog('===== 调后端重绘 =====', 'info');
|
||||
flog('提示词=' + prompt, 'info');
|
||||
|
||||
const form = new FormData();
|
||||
form.append('image', dataUriToBlob(_finalDataUri), 'final.jpg');
|
||||
form.append('mask', dataUriToBlob(_maskDataUri), 'mask.png');
|
||||
form.append('image_file', dataUriToBlob(_finalDataUri), 'final.jpg');
|
||||
form.append('mask_file', dataUriToBlob(_maskDataUri), 'mask.png');
|
||||
form.append('prompt', prompt);
|
||||
|
||||
const t0 = performance.now();
|
||||
try {
|
||||
flog('fetch POST ' + base + '/api/generate', 'info');
|
||||
const resp = await fetch(base + '/api/generate', { method: 'POST', body: form });
|
||||
flog('收到响应 http=' + resp.status + ' type=' + resp.headers.get('content-type'), resp.ok ? 'info' : 'error');
|
||||
flog('fetch POST ' + API_BASE + '/api/v1/redraw', 'info');
|
||||
const resp = await fetch(API_BASE + '/api/v1/redraw', { method: 'POST', body: form });
|
||||
flog('收到响应 http=' + resp.status, resp.ok ? 'info' : 'error');
|
||||
const dt = ((performance.now() - t0) / 1000).toFixed(2);
|
||||
if (resp.ok && resp.headers.get('content-type', '').includes('image/')) {
|
||||
const blob = await resp.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
$('localResult').src = url;
|
||||
const json = await resp.json();
|
||||
if (json.code === 0 && json.data && json.data.image_base64) {
|
||||
$('localResult').src = json.data.image_base64;
|
||||
$('localResult').onclick = function(){ zoom(this.src); };
|
||||
setStatus('✅ local_test 重绘完成 (' + dt + 's)', 'success');
|
||||
flog('local_test 重绘完成 耗时=' + dt + 's 大小=' + blob.size + 'B', 'info');
|
||||
setStatus('✅ 重绘完成 (' + dt + 's)', 'success');
|
||||
flog('重绘完成 耗时=' + dt + 's', 'info');
|
||||
} else {
|
||||
// 非图片响应 → 多半是 JSON 错误
|
||||
let msg = resp.status + '';
|
||||
try { const j = await resp.json(); msg = j.error || JSON.stringify(j); } catch (_) {}
|
||||
setStatus('❌ local_test 重绘失败:' + msg, 'error');
|
||||
flog('local_test 重绘失败: ' + msg, 'error');
|
||||
const msg = json.message || JSON.stringify(json);
|
||||
setStatus('❌ 重绘失败:' + msg, 'error');
|
||||
flog('重绘失败: ' + msg, 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
setStatus('❌ local_test 网络错误:' + err.message + '(确认服务在跑且已加 CORS)', 'error');
|
||||
flog('local_test 网络错误: ' + err.message, 'error');
|
||||
setStatus('❌ 重绘网络错误:' + err.message, 'error');
|
||||
flog('重绘网络错误: ' + err.message, 'error');
|
||||
} finally {
|
||||
btn.disabled = false; btn.textContent = '🧪 调 local_test 重绘';
|
||||
btn.disabled = false; btn.textContent = '🧪 重绘';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,8 +417,8 @@ async function downloadBackendLog() {
|
||||
|
||||
$('imageFile').addEventListener('change', function(){ if(this.files.length) flog('选择图片: ' + this.files[0].name, 'info'); });
|
||||
|
||||
flog('接口12 重绘测试页加载完成(后端产出 final+纯红遮罩 → 前端调 local_test 重绘)', 'info');
|
||||
flog('默认: hairline=chang_bolang, push=0.8, blend=two_stage, cm_strength=0.4;需 ComfyUI(:8188) 在跑;重绘需 local_test(:8899) 在跑', 'info');
|
||||
flog('接口12 重绘测试页加载完成(后端产出 final+纯红遮罩 → 后端 /api/v1/redraw 重绘)', 'info');
|
||||
flog('默认: hairline=chang_bolang, push=0.8, blend=two_stage, cm_strength=0.4;需 ComfyUI(:8188) 在跑', 'info');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -41,10 +41,10 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>接口12 final — 发际线带重绘 <span style="font-size:13px;color:#888">(精简版:final + 纯红遮罩 → 外部 ComfyUI 重绘)</span></h1>
|
||||
<h1>接口12 final — 发际线带重绘 <span style="font-size:13px;color:#888">(精简版:final + 纯红遮罩 → ComfyUI 重绘)</span></h1>
|
||||
<div class="subtitle">
|
||||
只需上传图片 + 选择发型,其余参数全部用当前调优默认值(<code>/api/v1/hairline/grow_v2_final</code>)。<br>
|
||||
后端产出 <b>④ final(接缝融合基底)</b> + <b>⑤-② 纯红遮罩 PNG</b>,前端调 <b>外部重绘服务(local_test,默认 :8899)</b>完成发际线带重绘。⚠️ 需 ComfyUI(:8188) 在跑。
|
||||
后端产出 <b>④ final(接缝融合基底)</b> + <b>⑤-② 纯红遮罩 PNG</b>,再调 <b>后端重绘接口(/api/v1/redraw)</b>完成发际线带重绘。⚠️ 需 ComfyUI(:8188) 在跑。
|
||||
局部加发版见 <a href="/static/test_interface12_final_v2.html">接口12 final v2</a>;完整参数调试见 <a href="/static/test_interface12.html">接口12 调试页</a>。
|
||||
</div>
|
||||
|
||||
@@ -52,11 +52,7 @@
|
||||
<div class="upload-row">
|
||||
<input type="file" id="imageFile" accept="image/*">
|
||||
<button class="btn btn-primary" id="submitBtn" onclick="submitTest()">🎨 生成 final+遮罩</button>
|
||||
<button class="btn btn-green" id="redrawBtn" onclick="runLocalRedraw()" disabled>🧪 调 local_test 重绘</button>
|
||||
</div>
|
||||
<div class="upload-row" style="margin-top:10px">
|
||||
<label style="font-size:13px;font-weight:600;white-space:nowrap">重绘服务地址</label>
|
||||
<input type="text" id="localTestUrl" value="http://10.60.74.221:8899" style="flex:1;min-width:200px;padding:8px;border:1px solid #ddd;border-radius:8px">
|
||||
<button class="btn btn-green" id="redrawBtn" onclick="runLocalRedraw()" disabled>🧪 重绘</button>
|
||||
</div>
|
||||
<div class="upload-row" style="margin-top:10px">
|
||||
<label style="font-size:13px;font-weight:600;white-space:nowrap">重绘提示词</label>
|
||||
@@ -84,9 +80,9 @@
|
||||
<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">⑤-① 发际线重绘带遮罩 <small>纯红 alpha PNG(遮罩区=红+不透明,其余全透明)</small></div><img id="maskPng"></div>
|
||||
<div class="step big"><div class="cap">🧪 local_test 重绘结果 <small>final + 遮罩 → 外部 ComfyUI(0716add-hair.json)</small></div><img id="localResult"></div>
|
||||
<div class="step big"><div class="cap">🧪 重绘结果 <small>final + 遮罩 → ComfyUI(0716add-hair)</small></div><img id="localResult"></div>
|
||||
</div>
|
||||
<div style="font-size:12px;color:#888;margin-top:10px">流程:后端产出 final(接缝融合基底)+ 纯红遮罩 PNG,前端把两者 POST 到 local_test 重绘服务完成发际线补发。</div>
|
||||
<div style="font-size:12px;color:#888;margin-top:10px">流程:后端产出 final(接缝融合基底)+ 纯红遮罩 PNG,再调后端 /api/v1/redraw 完成发际线补发。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,7 +94,7 @@ const API_BASE = window.location.origin;
|
||||
const ENDPOINT = '/api/v1/hairline/grow_v2_final';
|
||||
const TOKEN = 'dev-shared-secret-2026';
|
||||
|
||||
// 缓存最近一次后端返回的 final(data URI)和纯红遮罩(data URI),供 local_test 重绘使用
|
||||
// 缓存最近一次后端返回的 final(data URI)和纯红遮罩(data URI),供重绘使用
|
||||
let _finalDataUri = '';
|
||||
let _maskDataUri = '';
|
||||
|
||||
@@ -121,7 +117,7 @@ function renderResult(d) {
|
||||
$('redrawBtn').disabled = !canRedraw;
|
||||
}
|
||||
|
||||
// data URI → Blob,用于把后端返回的 final/遮罩图作为文件 POST 给 local_test
|
||||
// data URI → Blob,用于把后端返回的 final/遮罩图作为文件 POST 给后端重绘
|
||||
function dataUriToBlob(dataUri) {
|
||||
const [meta, b64] = dataUri.split(',');
|
||||
const mime = (meta.match(/data:([^;]+)/) || [, 'application/octet-stream'])[1];
|
||||
@@ -173,36 +169,34 @@ async function submitTest() {
|
||||
|
||||
async function runLocalRedraw() {
|
||||
if (!_finalDataUri || !_maskDataUri) { setStatus('缺少 final 或遮罩,请先生成', 'error'); return; }
|
||||
const base = $('localTestUrl').value.trim().replace(/\/+$/, '');
|
||||
if (!base) { setStatus('请填写重绘服务地址', 'error'); return; }
|
||||
const prompt = $('localTestPrompt').value.trim() || '填充遮罩区域的头发,皮肤加一点磨皮';
|
||||
const btn = $('redrawBtn');
|
||||
btn.disabled = true; btn.textContent = '⏳ 重绘中...';
|
||||
|
||||
const form = new FormData();
|
||||
form.append('image', dataUriToBlob(_finalDataUri), 'final.jpg');
|
||||
form.append('mask', dataUriToBlob(_maskDataUri), 'mask.png');
|
||||
form.append('image_file', dataUriToBlob(_finalDataUri), 'final.jpg');
|
||||
form.append('mask_file', dataUriToBlob(_maskDataUri), 'mask.png');
|
||||
form.append('prompt', prompt);
|
||||
|
||||
const t0 = performance.now();
|
||||
try {
|
||||
const resp = await fetch(base + '/api/generate', { method: 'POST', body: form });
|
||||
const resp = await fetch(API_BASE + '/api/v1/redraw', {
|
||||
method: 'POST',
|
||||
body: form,
|
||||
});
|
||||
const dt = ((performance.now() - t0) / 1000).toFixed(2);
|
||||
if (resp.ok && resp.headers.get('content-type', '').includes('image/')) {
|
||||
const blob = await resp.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
$('localResult').src = url;
|
||||
const json = await resp.json();
|
||||
if (json.code === 0 && json.data && json.data.image_base64) {
|
||||
$('localResult').src = json.data.image_base64;
|
||||
$('localResult').onclick = function(){ zoom(this.src); };
|
||||
setStatus('✅ local_test 重绘完成 (' + dt + 's)', 'success');
|
||||
setStatus('✅ 重绘完成 (' + dt + 's)', 'success');
|
||||
} else {
|
||||
let msg = resp.status + '';
|
||||
try { const j = await resp.json(); msg = j.error || JSON.stringify(j); } catch (_) {}
|
||||
setStatus('❌ local_test 重绘失败:' + msg, 'error');
|
||||
setStatus('❌ 重绘失败:' + (json.message || JSON.stringify(json)), 'error');
|
||||
}
|
||||
} catch (err) {
|
||||
setStatus('❌ local_test 网络错误:' + err.message + '(确认服务在跑且已加 CORS)', 'error');
|
||||
setStatus('❌ 重绘网络错误:' + err.message, 'error');
|
||||
} finally {
|
||||
btn.disabled = false; btn.textContent = '🧪 调 local_test 重绘';
|
||||
btn.disabled = false; btn.textContent = '🧪 重绘';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user