v2.2 — ComfyUI Portrait Generation

Features:
- 🖼️ Portrait Button im Chat-Header
- /api/comfyui/status: Prüft ob ComfyUI läuft
- /api/character/{name}/portrait: Generiert Profilbild via ComfyUI
- comfyui_integration.py: ComfyUI API Client
  - NoobAI-XL Checkpoint
  - 25 Steps, DPM++ 2M Karras
  - 512x512 Portrait
  - Auto-Copy zu static/avatars/
- UI: Avatar wird nach Generierung ersetzt
- UI: Button zeigt Status (ComfyUI nicht erreichbar = ausgegraut)
- Workflow: Character-Beschreibung → ComfyUI Prompt → Bild → Avatar

Voraussetzung: ComfyUI muss auf localhost:8188 laufen
This commit is contained in:
arch_agent
2026-07-24 21:49:43 +02:00
parent c60d1219b2
commit 52612970c5
3 changed files with 213 additions and 0 deletions
+41
View File
@@ -70,6 +70,7 @@
<div class="header-actions">
<span class="session-info" id="sessionInfo" title="Session-ID">Session: ...</span>
<span class="session-info" id="passcodeInfo" title="Passcode für andere Geräte" style="border-color: var(--accent); color: var(--accent);">Code: ...</span>
<button class="btn" id="portraitBtn" onclick="generatePortrait()">🖼️ Portrait</button>
<button class="btn" onclick="toggleMemory()">🧠 Gedächtnis</button>
<button class="btn btn-danger" onclick="clearMemory()">🗑️ Vergessen</button>
</div>
@@ -291,6 +292,46 @@
{% if not history %}
loadHistory();
{% endif %}
// Check ComfyUI status on load
fetch('/api/comfyui/status').then(r => r.json()).then(data => {
if (!data.running) {
const btn = document.getElementById('portraitBtn');
btn.title = 'ComfyUI läuft nicht — starte ComfyUI zuerst';
btn.style.opacity = '0.5';
}
});
async function generatePortrait() {
const btn = document.getElementById('portraitBtn');
const oldText = btn.textContent;
btn.textContent = '⏳ Generiert...';
btn.disabled = true;
try {
const resp = await fetch(`/api/character/${encodeURIComponent(charFilename)}/portrait`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({})
});
const data = await resp.json();
if (resp.ok && data.image) {
// Update avatar in header
const avatarEl = document.querySelector('.avatar');
avatarEl.innerHTML = `<img src="${data.image}?t=${Date.now()}" style="width: 100%; height: 100%; border-radius: 50%; object-fit: cover;">`;
btn.textContent = '✅ Fertig!';
setTimeout(() => { btn.textContent = oldText; btn.disabled = false; }, 2000);
} else {
alert(data.error || 'Generierung fehlgeschlagen');
btn.textContent = oldText;
btn.disabled = false;
}
} catch(e) {
alert('Verbindungsfehler: ' + e.message);
btn.textContent = oldText;
btn.disabled = false;
}
}
</script>
</body>
</html>