Files
2026-06-04 08:05:06 +03:00

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);