Files
miku-discord/bot/utils/context_manager.py
koko210Serve 66881f4c88 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
2026-02-27 13:14:03 +02:00

146 lines
4.4 KiB
Python

# utils/context_manager.py
"""
Structured context management for Miku's personality and knowledge.
Replaces the vector search system with organized, complete context.
Preserves original content files in their entirety.
When LANGUAGE_MODE is "japanese", appends a Japanese instruction to ensure
all responses are in Japanese without requiring separate files.
"""
import globals
from utils.logger import get_logger
logger = get_logger('core')
def get_original_miku_lore() -> str:
"""Load the complete, unmodified miku_lore.txt file"""
try:
with open("persona/miku/miku_lore.txt", "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
logger.error(f"Failed to load miku_lore.txt: {e}")
return "## MIKU LORE\n[File could not be loaded]"
def get_original_miku_prompt() -> str:
"""Load the complete, unmodified miku_prompt.txt file"""
try:
with open("persona/miku/miku_prompt.txt", "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
logger.error(f"Failed to load miku_prompt.txt: {e}")
return "## MIKU PROMPT\n[File could not be loaded]"
def get_original_miku_lyrics() -> str:
"""Load the complete, unmodified miku_lyrics.txt file"""
try:
with open("persona/miku/miku_lyrics.txt", "r", encoding="utf-8") as f:
return f.read()
except Exception as e:
logger.error(f"Failed to load miku_lyrics.txt: {e}")
return "## MIKU LYRICS\n[File could not be loaded]"
def _get_japanese_instruction() -> str:
"""
Returns the Japanese language instruction to append to context.
Ensures all responses are in Japanese when in Japanese mode.
This is a secondary reminder - the primary enforcement is in the system prompt.
"""
return """
[日本語モード有効 - Japanese Mode Active]
必ず日本語(ひらがな・カタカナ・漢字)のみで返答してください。
ローマ字・英語は使用禁止です。
"""
def get_complete_context() -> str:
"""
Returns all essential Miku context using original files in their entirety.
If LANGUAGE_MODE is "japanese", appends a Japanese instruction to ensure
all responses are in Japanese.
"""
lore = get_original_miku_lore()
prompt = get_original_miku_prompt()
lyrics = get_original_miku_lyrics()
combined = f"""## MIKU LORE (Complete Original)
{lore}
## MIKU PERSONALITY & GUIDELINES (Complete Original)
{prompt}
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
# Append Japanese instruction if in Japanese mode
if globals.LANGUAGE_MODE == "japanese":
combined += _get_japanese_instruction()
logger.info(f"[core] Context loaded in {globals.LANGUAGE_MODE} mode")
return combined
def get_context_for_response_type(response_type: str) -> str:
"""
Returns appropriate context based on the type of response being generated.
If LANGUAGE_MODE is "japanese", appends Japanese instruction to all contexts
to ensure responses are in Japanese.
"""
lore = get_original_miku_lore()
prompt = get_original_miku_prompt()
lyrics = get_original_miku_lyrics()
# Build core context (always in English source files)
core_context = f"""## MIKU LORE (Complete Original)
{lore}
## MIKU PERSONALITY & GUIDELINES (Complete Original)
{prompt}"""
# Return context based on response type
if response_type == "autonomous_general":
context = f"""{core_context}
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
elif response_type == "autonomous_tweet":
context = f"""{core_context}
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
elif response_type == "dm_response" or response_type == "server_response":
context = f"""{core_context}
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
elif response_type == "conversation_join":
context = f"""{core_context}
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
elif response_type == "emoji_selection":
# For emoji reactions, minimal context needed
context = ""
else:
# Default: comprehensive context
context = get_complete_context()
# Append Japanese instruction if in Japanese mode
if globals.LANGUAGE_MODE == "japanese" and context:
context += _get_japanese_instruction()
return context