v2.3 — Character-Aussehen + Portrait-Fix

Features:
- Character-Bogen: Aussehen-Sektion mit Stil, Geschlecht, Alter, Größe,
  Statur, Haarfarbe, Frisur, Augenfarbe, Haut, Kleidung, Merkmale
- Stil-Optionen: Anime, Realistisch, Comic, Cartoon, Pixel Art
- ComfyUI Prompt wird aus appearance-Objekt gebaut
- Portrait-Button: Async mit Polling (kein Timeout mehr)
- Portrait-Button: 5-Minuten Timeout als Fallback
- Poll-Errors werden ignoriert (kein vorzeitiger Abbruch)
- Mara.json aktualisiert mit appearance-Objekt
This commit is contained in:
arch_agent
2026-07-24 22:04:13 +02:00
parent b916792082
commit 7755d2be64
6 changed files with 238 additions and 41 deletions
+39 -7
View File
@@ -315,16 +315,48 @@
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 {
if (!resp.ok) {
alert(data.error || 'Generierung fehlgeschlagen');
btn.textContent = oldText;
btn.disabled = false;
return;
}
if (data.job_id) {
const jobId = data.job_id;
const pollInterval = setInterval(async () => {
try {
const statusResp = await fetch(`/api/portrait/status/${jobId}`);
const statusData = await statusResp.json();
if (statusData.status === 'done' && statusData.image) {
clearInterval(pollInterval);
const avatarEl = document.querySelector('.avatar');
avatarEl.innerHTML = `<img src="${statusData.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 if (statusData.status === 'error') {
clearInterval(pollInterval);
alert(statusData.error || 'Generierung fehlgeschlagen');
btn.textContent = oldText;
btn.disabled = false;
}
} catch(e) {
// ignore poll errors, keep trying
}
}, 3000);
// Timeout after 5 minutes
setTimeout(() => {
clearInterval(pollInterval);
btn.textContent = oldText;
btn.disabled = false;
}, 300000);
} else if (data.error) {
alert(data.error);
btn.textContent = oldText;
btn.disabled = false;
}
} catch(e) {
alert('Verbindungsfehler: ' + e.message);