From 03cbda5dcefe670fc9a72c27ed98bcaa019af22f Mon Sep 17 00:00:00 2001 From: grigo Date: Tue, 2 Jun 2026 15:03:39 +0300 Subject: [PATCH] Fixed SD Promt --- database/db.py | 8 + main.py | 10 +- ...st-a-friendly-hug-3ccb4b5342bb_spec_v2.png | Bin 0 -> 257298 bytes ...-obsessive-girlfriend-af26ead7_spec_v2.png | Bin 0 -> 400679 bytes main_delta-125aa7a6_spec_v2.png | Bin 0 -> 348525 bytes main_violet-merino-d2e9f62b5d77_spec_v2.png | Bin 0 -> 1586970 bytes main_vulpisfoglia-e0a6befda921_spec_v2.png | Bin 0 -> 1374355 bytes ...perheroine-friend-c65bf1fe881c_spec_v2.png | Bin 0 -> 2755898 bytes models/schemas.py | 5 + routers/characters.py | 1 + routers/chat.py | 406 +++++----- routers/debug.py | 248 ++++++ routers/personas.py | 1 + routers/sessions.py | 41 +- services/character_card.py | 25 +- services/chat_prompt.py | 26 + services/comfy_models.py | 40 + services/llm.py | 125 +++- services/memory.py | 141 +++- services/opening.py | 178 +++++ services/personas.py | 25 +- services/rpg_facts.py | 19 +- services/rpg_narrator.py | 44 +- services/rpg_plot.py | 16 +- services/sd_images.py | 48 ++ services/sd_prompt.py | 708 ++++++++++++++++-- services/sdbackend.py | 345 ++++++++- services/session_identity.py | 31 + services/system_message_migration.py | 21 + .../avatars/card_carrie_0578318a_dbee17bc.png | Bin 0 -> 257298 bytes .../avatars/card_carrie_926629e6_09f02497.png | Bin 0 -> 257298 bytes .../avatars/card_carrie_926629e6_8b9b8891.png | Bin 0 -> 257298 bytes .../avatars/card_carrie_926629e6_e01546a5.png | Bin 0 -> 257298 bytes static/css/app.css | 16 +- static/css/debug.css | 209 ++++++ static/debug.html | 134 ++++ static/index.html | 6 +- static/js/chat.js | 99 ++- static/js/chatSettings.js | 65 +- static/js/debug.js | 217 ++++++ static/js/newChatWizard.js | 126 ++-- static/js/personas.js | 32 +- static/js/sessions.js | 13 +- static/js/state.js | 20 +- static/js/utils.js | 22 +- tests/test_sd_prompt.py | 243 ++++++ 46 files changed, 3285 insertions(+), 429 deletions(-) create mode 100644 main_carrie-just-a-friendly-hug-3ccb4b5342bb_spec_v2.png create mode 100644 main_clingy-obsessive-girlfriend-af26ead7_spec_v2.png create mode 100644 main_delta-125aa7a6_spec_v2.png create mode 100644 main_violet-merino-d2e9f62b5d77_spec_v2.png create mode 100644 main_vulpisfoglia-e0a6befda921_spec_v2.png create mode 100644 main_your-scumbag-superheroine-friend-c65bf1fe881c_spec_v2.png create mode 100644 routers/debug.py create mode 100644 services/chat_prompt.py create mode 100644 services/comfy_models.py create mode 100644 services/opening.py create mode 100644 services/sd_images.py create mode 100644 services/session_identity.py create mode 100644 services/system_message_migration.py create mode 100644 static/avatars/card_carrie_0578318a_dbee17bc.png create mode 100644 static/avatars/card_carrie_926629e6_09f02497.png create mode 100644 static/avatars/card_carrie_926629e6_8b9b8891.png create mode 100644 static/avatars/card_carrie_926629e6_e01546a5.png create mode 100644 static/css/debug.css create mode 100644 static/debug.html create mode 100644 static/js/debug.js create mode 100644 tests/test_sd_prompt.py diff --git a/database/db.py b/database/db.py index 38f7a49..1667631 100644 --- a/database/db.py +++ b/database/db.py @@ -86,6 +86,10 @@ async def _migrate_messages_columns(db): await db.execute("ALTER TABLE messages ADD COLUMN image_prompt TEXT") if "image_path" not in cols: await db.execute("ALTER TABLE messages ADD COLUMN image_path TEXT") + if "image_prompt_alt" not in cols: + await db.execute("ALTER TABLE messages ADD COLUMN image_prompt_alt TEXT") + if "image_path_alt" not in cols: + await db.execute("ALTER TABLE messages ADD COLUMN image_path_alt TEXT") async def _migrate_personas_columns(db): @@ -105,6 +109,8 @@ async def _migrate_personas_columns(db): await db.execute("ALTER TABLE personas ADD COLUMN avatar_path TEXT DEFAULT ''") if "alternate_greetings_json" not in cols: await db.execute("ALTER TABLE personas ADD COLUMN alternate_greetings_json TEXT DEFAULT '[]'") + if "appearance_prose" not in cols: + await db.execute("ALTER TABLE personas ADD COLUMN appearance_prose TEXT DEFAULT ''") async def _migrate_sessions_columns(db): @@ -170,3 +176,5 @@ async def _migrate_characters_columns(db): await db.execute("ALTER TABLE characters ADD COLUMN avatar_path TEXT DEFAULT ''") if "alternate_greetings_json" not in cols: await db.execute("ALTER TABLE characters ADD COLUMN alternate_greetings_json TEXT DEFAULT '[]'") + if "appearance_prose" not in cols: + await db.execute("ALTER TABLE characters ADD COLUMN appearance_prose TEXT DEFAULT ''") diff --git a/main.py b/main.py index 802a95a..869840c 100644 --- a/main.py +++ b/main.py @@ -3,9 +3,10 @@ from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse -from routers import chat, personas, sessions, characters, images, translate +from routers import chat, personas, sessions, characters, images, translate, debug from database.db import init_db from services.persona_seed import seed_default_personas +from services.system_message_migration import migrate_static_system_messages logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s") @@ -14,6 +15,7 @@ logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(messag async def lifespan(app: FastAPI): await init_db() await seed_default_personas() + await migrate_static_system_messages() yield @@ -25,6 +27,7 @@ app.include_router(sessions.router) app.include_router(characters.router) app.include_router(images.router) app.include_router(translate.router) +app.include_router(debug.router) app.mount("/static", StaticFiles(directory="static"), name="static") @@ -34,6 +37,11 @@ async def root(): return FileResponse("static/index.html") +@app.get("/debug") +async def debug_page(): + return FileResponse("static/debug.html") + + @app.get("/health") async def health(): return {"status": "ok"} diff --git a/main_carrie-just-a-friendly-hug-3ccb4b5342bb_spec_v2.png b/main_carrie-just-a-friendly-hug-3ccb4b5342bb_spec_v2.png new file mode 100644 index 0000000000000000000000000000000000000000..8ef6eb05234e01e6d970cf4a10409bcad07edd7e GIT binary patch literal 257298 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