v2.4 — Character Editor + Image-to-Image Portrait Consistency

Features:
- /edit/{name} route: Character nachträglich bearbeiten
- /api/character/update/{name}: API zum Aktualisieren
- create.html dient als Editor und Creator (mode=edit/create)
- Index-Seite: ✏️ Button pro Character
- Portrait-Vorschau im Editor
- Image-to-Image: Folge-Portraits nutzen bestehendes Bild als Referenz
  - LoadImage → ImageScale → VAEEncode → KSampler (denoise=0.45)
  - Aussehen bleibt konsistent über mehrere Generierungen
  - Fallback auf Text-to-Image wenn kein Referenzbild existiert
- ComfyUI Image Upload via /upload/image API
- Jinja2 if-Expressions für vorausgefüllte Formularfelder
This commit is contained in:
arch_agent
2026-07-24 22:08:15 +02:00
parent f454d7b785
commit ea1b231fea
6 changed files with 216 additions and 52 deletions
+39 -1
View File
@@ -295,7 +295,17 @@ async def index(request: Request, session_id: str = Cookie(None, alias=SESSION_C
@app.get("/create", response_class=HTMLResponse)
async def create_page(request: Request):
return templates.TemplateResponse(request, "create.html", {})
return templates.TemplateResponse(request, "create.html", {"mode": "create", "character": None})
@app.get("/edit/{character_name}", response_class=HTMLResponse)
async def edit_page(request: Request, character_name: str):
char = load_character(character_name)
safe_name = character_name.lower().replace(" ", "_")
return templates.TemplateResponse(request, "create.html", {
"mode": "edit",
"character": char,
"character_filename": safe_name,
})
@app.get("/chat/{character_name}", response_class=HTMLResponse)
async def chat_page(request: Request, character_name: str, session_id: str = Cookie(None, alias=SESSION_COOKIE_NAME)):
@@ -463,6 +473,34 @@ async def api_create_character(request: Request):
return JSONResponse({"status": "ok", "character": safe_name})
@app.post("/api/character/update/{character_name}")
async def api_update_character(character_name: str, request: Request):
"""Aktualisiert einen bestehenden Character."""
path = CHARACTERS_DIR / f"{character_name}.json"
if not path.exists():
raise HTTPException(status_code=404, detail=f"Character {character_name} not found")
body = await request.json()
# Load existing, update fields
with open(path, "r", encoding="utf-8") as f:
char = json.load(f)
# Update all fields
for key in ["name", "avatar", "description", "personality", "background",
"behavior", "tone", "scenario", "nsfw", "greeting", "model", "temperature"]:
if key in body:
char[key] = body[key]
# Update appearance
if "appearance" in body:
char["appearance"] = body["appearance"]
with open(path, "w", encoding="utf-8") as f:
json.dump(char, f, indent=2, ensure_ascii=False)
return JSONResponse({"status": "ok", "character": character_name})
@app.get("/api/character/{name}")
async def api_get_character(name: str):
char = load_character(name)