218 lines
7.3 KiB
JavaScript
218 lines
7.3 KiB
JavaScript
const $ = (id) => document.getElementById(id);
|
|
|
|
function fmt(obj) {
|
|
return typeof obj === 'string' ? obj : JSON.stringify(obj, null, 2);
|
|
}
|
|
|
|
async function api(path, opts = {}) {
|
|
const res = await fetch(path, {
|
|
headers: { 'Content-Type': 'application/json', ...(opts.headers || {}) },
|
|
...opts,
|
|
});
|
|
const text = await res.text();
|
|
let data;
|
|
try {
|
|
data = JSON.parse(text);
|
|
} catch {
|
|
data = text;
|
|
}
|
|
if (!res.ok) {
|
|
const detail = data?.detail || text || res.statusText;
|
|
throw new Error(`${res.status}: ${detail}`);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function initTabs() {
|
|
const tabs = document.querySelectorAll('#debugTabs button');
|
|
tabs.forEach((btn) => {
|
|
btn.addEventListener('click', () => {
|
|
tabs.forEach((t) => t.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
document.querySelectorAll('.debug-panel').forEach((p) => p.classList.remove('active'));
|
|
$(`panel-${btn.dataset.tab}`).classList.add('active');
|
|
});
|
|
});
|
|
}
|
|
|
|
async function loadConfig() {
|
|
const c = await api('/debug/config');
|
|
$('configOut').textContent = fmt(c);
|
|
$('llmModel').placeholder = c.sd_prompt_model || c.system_model;
|
|
return c;
|
|
}
|
|
|
|
async function loadPersonas() {
|
|
const list = await api('/debug/personas');
|
|
const sel = $('sdPersona');
|
|
sel.innerHTML = '';
|
|
for (const p of list) {
|
|
const opt = document.createElement('option');
|
|
opt.value = p.persona_id;
|
|
opt.textContent = `${p.name} (${p.persona_id})`;
|
|
sel.appendChild(opt);
|
|
}
|
|
}
|
|
|
|
async function runSdPrompt() {
|
|
$('sdScene').textContent = '…';
|
|
$('sdPrompts').textContent = '…';
|
|
const body = {
|
|
persona_id: $('sdPersona').value,
|
|
chat_excerpt: $('sdChat').value,
|
|
outfit_json: $('sdOutfit').value || '[]',
|
|
use_prose: $('sdUseProse') ? $('sdUseProse').checked : false,
|
|
};
|
|
const app = $('sdAppearance').value.trim();
|
|
if (app) body.appearance_override = app;
|
|
|
|
const data = await api('/debug/sd-prompt', { method: 'POST', body: JSON.stringify(body) });
|
|
$('sdScene').textContent = data.scene ? fmt(data.scene) : (data.error || '—');
|
|
const prompts = [];
|
|
if (data.tags_only_full) prompts.push('=== TAGS + POV (no prose) ===\n' + data.tags_only_full);
|
|
if (data.hybrid_full) prompts.push('\n=== HYBRID (Comfy) ===\n' + data.hybrid_full);
|
|
if (!data.tags_only_full && data.tag_full) prompts.push('=== PROMPT ===\n' + data.tag_full);
|
|
$('sdPrompts').textContent = prompts.join('\n') || data.error || '—';
|
|
$('sdLlmRaw').textContent = [
|
|
`model: ${data.sd_prompt_model}`,
|
|
`dual: ${data.anima_dual}`,
|
|
'',
|
|
'--- system ---',
|
|
data.builder_system || '',
|
|
'',
|
|
'--- user ---',
|
|
data.builder_user || '',
|
|
'',
|
|
'--- raw ---',
|
|
data.llm_raw || data.error || '',
|
|
].join('\n');
|
|
if (data.tag_full || data.hybrid_full) {
|
|
const src = data.hybrid_full || data.tag_full;
|
|
const parts = src.includes('__NEGATIVE_PROMPT__')
|
|
? src.split('\n\n__NEGATIVE_PROMPT__\n\n')
|
|
: src.includes('\n\nNegative prompt:')
|
|
? src.split('\n\nNegative prompt:')
|
|
: [src, ''];
|
|
$('genPositive').value = parts[0] || '';
|
|
$('genNegative').value = parts[1] || '';
|
|
}
|
|
}
|
|
|
|
async function runLlm() {
|
|
$('llmOut').textContent = '…';
|
|
const data = await api('/debug/llm', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
model: $('llmModel').value.trim(),
|
|
system: $('llmSystem').value,
|
|
user: $('llmUser').value,
|
|
}),
|
|
});
|
|
$('llmOut').textContent = `model: ${data.model}\n\n${data.response}`;
|
|
}
|
|
|
|
function fillModelSelect(sel, options, configured) {
|
|
const current = sel.querySelector('option')?.value ?? '';
|
|
sel.innerHTML = `<option value="">— env: ${configured || '—'} —</option>`;
|
|
for (const name of options || []) {
|
|
const opt = document.createElement('option');
|
|
opt.value = name;
|
|
opt.textContent = name;
|
|
if (name === configured) opt.selected = true;
|
|
sel.appendChild(opt);
|
|
}
|
|
}
|
|
|
|
async function loadComfyModels() {
|
|
$('comfyModelLists').textContent = 'Загрузка object_info…';
|
|
const data = await api('/debug/comfy/models');
|
|
const { models, configured } = data;
|
|
fillModelSelect($('genUnet'), models.unets, configured.unet);
|
|
fillModelSelect($('genClip'), models.clips, configured.clip);
|
|
fillModelSelect($('genVae'), models.vaes, configured.vae);
|
|
fillModelSelect($('genCkpt'), models.checkpoints, configured.checkpoint);
|
|
|
|
const wrap = $('comfyModelLists');
|
|
wrap.innerHTML = '';
|
|
for (const [key, list] of Object.entries(models)) {
|
|
const block = document.createElement('details');
|
|
block.className = 'model-list-block';
|
|
block.open = key === 'unets' || key === 'checkpoints';
|
|
block.innerHTML = `<summary>${key} (${list.length})</summary>`;
|
|
const ul = document.createElement('ul');
|
|
for (const item of list) {
|
|
const li = document.createElement('li');
|
|
li.textContent = item;
|
|
ul.appendChild(li);
|
|
}
|
|
block.appendChild(ul);
|
|
wrap.appendChild(block);
|
|
}
|
|
}
|
|
|
|
async function comfyPing() {
|
|
$('comfyPingOut').textContent = '…';
|
|
const data = await api('/debug/comfy/ping');
|
|
$('comfyPingOut').textContent = fmt(data);
|
|
}
|
|
|
|
async function comfyGenerate() {
|
|
$('comfyGenOut').textContent = 'Генерация…';
|
|
$('comfyImgWrap').classList.add('hidden');
|
|
const body = {
|
|
positive: $('genPositive').value,
|
|
negative: $('genNegative').value,
|
|
};
|
|
const u = $('genUnet').value;
|
|
const c = $('genClip').value;
|
|
const v = $('genVae').value;
|
|
const ck = $('genCkpt').value;
|
|
if (u) body.unet = u;
|
|
if (c) body.clip = c;
|
|
if (v) body.vae = v;
|
|
if (ck) body.checkpoint = ck;
|
|
|
|
const data = await api('/debug/comfy/generate', {
|
|
method: 'POST',
|
|
body: JSON.stringify(body),
|
|
});
|
|
$('comfyGenOut').textContent = fmt(data);
|
|
if (data.image_path) {
|
|
$('comfyImg').src = data.image_path + '?t=' + Date.now();
|
|
$('comfyImgWrap').classList.remove('hidden');
|
|
}
|
|
}
|
|
|
|
async function comfyRaw() {
|
|
$('comfyRawOut').textContent = '…';
|
|
const data = await api('/debug/comfy/raw', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
method: $('rawMethod').value,
|
|
path: $('rawPath').value,
|
|
params_json: $('rawParams').value || '{}',
|
|
body_json: $('rawBody').value || '',
|
|
}),
|
|
});
|
|
$('comfyRawOut').textContent = fmt(data);
|
|
}
|
|
|
|
function bind() {
|
|
initTabs();
|
|
$('btnReloadConfig').addEventListener('click', loadConfig);
|
|
$('btnSdPrompt').addEventListener('click', () => runSdPrompt().catch(showErr));
|
|
$('btnLlm').addEventListener('click', () => runLlm().catch(showErr));
|
|
$('btnComfyPing').addEventListener('click', () => comfyPing().catch(showErr));
|
|
$('btnComfyModels').addEventListener('click', () => loadComfyModels().catch(showErr));
|
|
$('btnComfyGen').addEventListener('click', () => comfyGenerate().catch(showErr));
|
|
$('btnComfyRaw').addEventListener('click', () => comfyRaw().catch(showErr));
|
|
}
|
|
|
|
function showErr(e) {
|
|
alert(e.message || String(e));
|
|
}
|
|
|
|
bind();
|
|
loadConfig().catch(showErr);
|
|
loadPersonas().catch(showErr);
|