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 = `
-
+