diff --git a/comfyui_integration.py b/comfyui_integration.py index d7276a3..a51b240 100644 --- a/comfyui_integration.py +++ b/comfyui_integration.py @@ -120,18 +120,18 @@ def build_prompt_from_appearance(character: dict, context: str = "") -> str: # Gender — Danbooru tags for anime, natural language for others if use_danbooru: if gender == "female": - gender_tag = "1girl, woman, " + gender_tag = "1girl, solo" elif gender == "male": - gender_tag = "1boy, man, " + gender_tag = "1boy, solo" else: - gender_tag = "person, " + gender_tag = "solo" else: if gender == "female": - gender_tag = "young woman, " + gender_tag = "young woman" elif gender == "male": - gender_tag = "young man, " + gender_tag = "young man" else: - gender_tag = "person, " + gender_tag = "person" # Translation map: German appearance values → English tags for the model translate_map = { @@ -183,7 +183,7 @@ def build_prompt_from_appearance(character: dict, context: str = "") -> str: # Build prompt — use established Danbooru tags for NoobAI-XL parts = [ - f"cowboy shot, {style_prefix}{gender_tag.strip()}", + f"{style_prefix}{gender_tag}", f"{age} years old", ] if build: @@ -216,8 +216,8 @@ def build_portrait_workflow(prompt: str, negative: str = "", width: int = 1024, "class_type": "KSampler", "inputs": { "seed": int(time.time()) % (2**32), - "steps": 30, - "cfg": 7.0, + "steps": 35, + "cfg": 6.5, "sampler_name": "dpmpp_2m", "scheduler": "karras", "denoise": 1.0, @@ -245,7 +245,7 @@ def build_portrait_workflow(prompt: str, negative: str = "", width: int = 1024, "7": { "class_type": "CLIPTextEncode", "inputs": { - "text": f"lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, blurry, deformed, ugly, {negative}", + "text": f"realistic, 3d, render, photorealistic, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, blurry, deformed, ugly, multiple views, split screen, repetition, duplicate, {negative}", "clip": ["4", 1] } }, @@ -322,7 +322,7 @@ def build_i2i_workflow(prompt: str, negative: str, reference_image_path: str, wi "7": { "class_type": "CLIPTextEncode", "inputs": { - "text": f"lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, blurry, deformed, ugly, {negative}", + "text": f"realistic, 3d, render, photorealistic, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, blurry, deformed, ugly, multiple views, split screen, repetition, duplicate, {negative}", "clip": ["4", 1] } }, diff --git a/static/avatars/mara.png b/static/avatars/mara.png index bac2a38..0c9d6b6 100644 Binary files a/static/avatars/mara.png and b/static/avatars/mara.png differ diff --git a/templates/chat.html b/templates/chat.html index d96ca1a..ebd949a 100644 --- a/templates/chat.html +++ b/templates/chat.html @@ -321,12 +321,14 @@ if (data.job_id) { const jobId = data.job_id; + let portraitAdded = false; // Guard against duplicate insertion const pollInterval = setInterval(async () => { try { const statusResp = await fetch(`/api/portrait/status/${jobId}`); const statusData = await statusResp.json(); - if (statusData.status === 'done' && statusData.image) { + if (statusData.status === 'done' && statusData.image && !portraitAdded) { + portraitAdded = true; // Prevent duplicate clearInterval(pollInterval); const imgUrl = `${statusData.image}?t=${Date.now()}`; @@ -334,13 +336,13 @@ const avatarEl = document.querySelector('.avatar'); avatarEl.innerHTML = ``; - // Also show the portrait in the chat as a message + // Show portrait in chat as a message (only once!) const portraitMsg = document.createElement('div'); portraitMsg.className = 'msg msg-bot'; portraitMsg.style.padding = '0'; portraitMsg.style.overflow = 'hidden'; portraitMsg.innerHTML = ` - +
🖼️ Neues Portrait generiert
`; chat.appendChild(portraitMsg);