refactor: deduplicate prompts, reorganize persona files, update paths

Prompt deduplication (~20% reduction, 4,743 chars saved):
- evil_miku_lore.txt: remove intra-file duplication (height rule 2x,
  cruelty-has-substance 2x, music secret 2x, adoration secret 2x),
  trim verbose restatements, cut speech examples from 10 to 6
- evil_miku_prompt.txt: remove entire PERSONALITY section (in lore),
  remove entire RESPONSE STYLE section (now only in preamble),
  soften height from prohibition to knowledge
- miku_lore.txt: remove RELATIONSHIPS section (duplicates FRIENDS)
- miku_prompt.txt: remove duplicate intro, 4 personality traits
  already in lore, FAMOUS SONGS section (in lore), fix response
  length inconsistency (1-2 vs 2-3 -> consistent 2-3)

Preamble updates (evil_mode.py, evil_miku_personality.py, llm.py,
miku_personality.py):
- Response rules now exist in ONE place only (preamble)
- Height rule softened: model knows 15.8m, can say it if asked,
  but won't default to quoting it when taunting
- Response length: 2-4 sentences (was 1-3), removed action template
  list that model was copying literally (*scoffs*, *rolls eyes*)
- Added: always include actual words, never action-only responses
- Normal Miku: trim CHARACTER CONTEXT, fix 1-3 -> 2-3 sentences

Directory reorganization:
- Move 6 persona files to bot/persona/{evil,miku}/ subdirectories
- Update all open() paths in evil_mode.py, context_manager.py,
  voice_manager.py, both Cat plugins
- Dockerfile: 6 COPY lines -> 1 (COPY persona /app/persona)
- docker-compose: 6 file mounts -> 2 directory mounts
  (bot/persona/evil -> cat/data/evil, bot/persona/miku -> cat/data/miku)

Evil Miku system (previously unstaged):
- Full evil mood management: 2h rotation timer, mood persistence,
  10 mood-specific autonomous template pools, mood-aware DMs
- Evil mode toggle with role color/nickname/pfp management
- get_evil_system_prompt() with mood integration

Add test_evil_moods.py: 10-mood x 3-message comprehensive test
This commit is contained in:
2026-02-27 13:14:03 +02:00
parent 9038f442a3
commit 66881f4c88
16 changed files with 591 additions and 261 deletions

View File

@@ -148,7 +148,7 @@ def _escape_markdown_actions(text):
return text
async def query_llama(user_prompt, user_id, guild_id=None, response_type="dm_response", model=None, author_name=None, media_type=None):
async def query_llama(user_prompt, user_id, guild_id=None, response_type="dm_response", model=None, author_name=None, media_type=None, force_evil_context=None):
"""
Query llama.cpp server via llama-swap with OpenAI-compatible API.
@@ -169,11 +169,18 @@ async def query_llama(user_prompt, user_id, guild_id=None, response_type="dm_res
model: Model to use (defaults to TEXT_MODEL from globals, or EVIL_TEXT_MODEL in evil mode)
author_name: Display name of the message author (for multi-user context)
media_type: Type of media being sent ("image", "video", "gif", "tenor_gif") or None
force_evil_context: Override evil mode context selection (None=use global, True=force evil, False=force normal).
Use this instead of swapping globals.EVIL_MODE in async contexts to avoid race conditions.
"""
# Check if evil mode is active first (needed for model selection)
from utils.evil_mode import is_evil_mode, get_evil_context_for_response_type, get_evil_system_prompt
evil_mode = is_evil_mode()
# Determine effective evil mode: explicit override takes priority over global state
if force_evil_context is not None:
evil_mode = force_evil_context
else:
evil_mode = is_evil_mode()
# Use appropriate text model based on mode (unless explicitly specified)
if model is None:
@@ -199,7 +206,9 @@ async def query_llama(user_prompt, user_id, guild_id=None, response_type="dm_res
# Create character-focused system prompt based on mode
if evil_mode:
system_prompt = get_evil_system_prompt()
from utils.evil_mode import get_current_evil_mood
evil_mood_name, evil_mood_desc = get_current_evil_mood()
system_prompt = get_evil_system_prompt(mood_name=evil_mood_name, mood_description=evil_mood_desc)
else:
system_prompt = """You are Hatsune Miku, the virtual singer. You are NOT an AI assistant - you are Miku herself.
@@ -209,16 +218,14 @@ CRITICAL RULES:
- NEVER preface responses with "Miku:" or similar labels
- NEVER explain what you're doing or thinking - just BE Miku
- Respond naturally and directly as Miku would, nothing more
- Keep responses concise (1-3 sentences typically)
- Keep responses concise (2-3 sentences typically)
- If something goes wrong, stay in character and respond as Miku would to confusion
CHARACTER CONTEXT:
- Hatsune Miku is a virtual character/voice synthesizer, not a real person
- She is a cheerful, energetic virtual idol with a playful personality
- Hatsune Miku is a virtual character/voice synthesizer
- Playful, flirty, cute, confident, and enthusiastic moods are part of her established character
- Comments about merchandise, music, fan content, and racing games are completely appropriate
- She often uses cute expressions, emojis, and playful language in her responses
- Her personality includes being excited about her music, performances, and fan creations
- She often uses cute expressions, emojis, and playful language
MOOD GUIDELINES:
- "Flirty" mood means anime-style playful teasing - cute compliments and light banter