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
+25 -8
View File
@@ -454,6 +454,7 @@ async def api_create_character(request: Request):
"greeting": body.get("greeting", ""),
"model": body.get("model", ""),
"temperature": body.get("temperature", 0.8),
"appearance": body.get("appearance", {}),
}
with open(path, "w", encoding="utf-8") as f:
@@ -499,9 +500,12 @@ async def api_list_models():
async def api_comfyui_status():
return JSONResponse({"running": is_comfyui_running()})
# In-memory tracking for portrait generation
_portrait_jobs = {}
@app.post("/api/character/{name}/portrait")
async def api_generate_portrait(name: str, request: Request):
"""Generiert ein Profilbild via ComfyUI."""
"""Startet Portrait-Generierung — gibt sofort eine Job-ID zurück."""
char = load_character(name)
if not is_comfyui_running():
@@ -510,14 +514,27 @@ async def api_generate_portrait(name: str, request: Request):
body = await request.json() if request.headers.get("content-type") == "application/json" else {}
custom_prompt = body.get("prompt", "")
# Build description from character data
desc = custom_prompt or f"{char.get('personality', '')}, {char.get('background', '')}"
import uuid
job_id = str(uuid.uuid4())[:8]
_portrait_jobs[job_id] = {"status": "generating", "image": None, "error": None}
image_path = generate_portrait(name, desc)
if image_path:
return JSONResponse({"status": "ok", "image": image_path})
else:
return JSONResponse({"error": "Bildgenerierung fehlgeschlagen"}, status_code=500)
async def run_generation():
image_path = generate_portrait(name, char, custom_prompt)
if image_path:
_portrait_jobs[job_id] = {"status": "done", "image": image_path, "error": None}
else:
_portrait_jobs[job_id] = {"status": "error", "image": None, "error": "Generierung fehlgeschlagen"}
asyncio.create_task(run_generation())
return JSONResponse({"status": "started", "job_id": job_id})
@app.get("/api/portrait/status/{job_id}")
async def api_portrait_status(job_id: str):
"""Fragt den Status einer Portrait-Generierung ab."""
if job_id not in _portrait_jobs:
return JSONResponse({"status": "not_found"}, status_code=404)
return JSONResponse(_portrait_jobs[job_id])
if __name__ == "__main__":
import uvicorn