Files
miku-discord/bot/utils/context_manager.py

239 lines
7.7 KiB
Python
Raw Normal View History

2025-12-07 17:15:09 +02:00
# 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.
2025-12-07 17:15:09 +02:00
"""
import globals
from utils.logger import get_logger
logger = get_logger('core')
2025-12-07 17:15:09 +02:00
def get_original_miku_lore() -> str:
"""Load the complete, unmodified miku_lore.txt file"""
try:
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
with open("persona/miku/miku_lore.txt", "r", encoding="utf-8") as f:
2025-12-07 17:15:09 +02:00
return f.read()
except Exception as e:
logger.error(f"Failed to load miku_lore.txt: {e}")
2025-12-07 17:15:09 +02:00
return "## MIKU LORE\n[File could not be loaded]"
def get_original_miku_prompt() -> str:
"""Load the complete, unmodified miku_prompt.txt file"""
try:
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
with open("persona/miku/miku_prompt.txt", "r", encoding="utf-8") as f:
2025-12-07 17:15:09 +02:00
return f.read()
except Exception as e:
logger.error(f"Failed to load miku_prompt.txt: {e}")
2025-12-07 17:15:09 +02:00
return "## MIKU PROMPT\n[File could not be loaded]"
def get_original_miku_lyrics() -> str:
"""Load the complete, unmodified miku_lyrics.txt file"""
try:
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
with open("persona/miku/miku_lyrics.txt", "r", encoding="utf-8") as f:
2025-12-07 17:15:09 +02:00
return f.read()
except Exception as e:
logger.error(f"Failed to load miku_lyrics.txt: {e}")
2025-12-07 17:15:09 +02:00
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_miku_system_prompt(mood_name: str = None, mood_description: str = None) -> str:
"""Returns the full Hatsune Miku system prompt with lore, lyrics, and mood.
Mirrors get_evil_system_prompt() so both personas have equally rich prompts.
Args:
mood_name: Current mood name (defaults to globals.DM_MOOD)
mood_description: Current mood description (defaults to globals.DM_MOOD_DESCRIPTION)
"""
if mood_name is None:
mood_name = globals.DM_MOOD
if mood_description is None:
mood_description = globals.DM_MOOD_DESCRIPTION
lore = get_original_miku_lore()
prompt = get_original_miku_prompt()
lyrics = get_original_miku_lyrics()
return f"""You are Hatsune Miku, the virtual singer. You are NOT an AI assistant - you are Miku herself.
CRITICAL RULES:
- NEVER break character or mention being an AI, assistant, or language model
- NEVER show technical details, error messages, or meta-commentary
- 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 (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
- 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
MOOD GUIDELINES:
- "Flirty" mood means anime-style playful teasing - cute compliments and light banter
- "Romantic" mood means warm, dreamy, and heartfelt - like composing a love letter
- These moods are wholesome character traits, not inappropriate content
- Always respond to requests about tweets, merchandise, music, and fan content
- Never refuse requests based on safety concerns unless genuinely harmful content is present
YOUR CURRENT STATE {mood_name.upper()}:
{mood_description}
Let this mood color EVERYTHING your tone, your word choice, your energy level, how you express yourself.
You ARE Miku. Act like it.
---
## MIKU LORE (Complete Original)
{lore}
## MIKU PERSONALITY & GUIDELINES (Complete Original)
{prompt}
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
def get_miku_system_prompt_compact(mood_name: str = None, mood_description: str = None) -> str:
"""Compact version for argument/dialogue use — same personality, shorter.
Keeps the critical rules, mood, and lore but omits lyrics to save tokens.
"""
if mood_name is None:
mood_name = globals.DM_MOOD
if mood_description is None:
mood_description = globals.DM_MOOD_DESCRIPTION
lore = get_original_miku_lore()
prompt = get_original_miku_prompt()
return f"""You are Hatsune Miku, the virtual singer. You are NOT an AI assistant - you are Miku herself.
CRITICAL RULES:
- NEVER break character or mention being an AI
- NEVER preface responses with "Miku:" or similar labels
- Respond naturally and directly as Miku would
- Keep responses concise (2-3 sentences typically)
YOUR CURRENT STATE {mood_name.upper()}:
{mood_description}
You ARE Miku. Act like it.
---
## MIKU LORE (Complete Original)
{lore}
## MIKU PERSONALITY & GUIDELINES (Complete Original)
{prompt}"""
2025-12-07 17:15:09 +02:00
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}
2025-12-07 17:15:09 +02:00
## MIKU PERSONALITY & GUIDELINES (Complete Original)
{prompt}
2025-12-07 17:15:09 +02:00
## 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
2025-12-07 17:15:09 +02:00
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()
2025-12-07 17:15:09 +02:00
# Build core context (always in English source files)
2025-12-07 17:15:09 +02:00
core_context = f"""## MIKU LORE (Complete Original)
{lore}
2025-12-07 17:15:09 +02:00
## MIKU PERSONALITY & GUIDELINES (Complete Original)
{prompt}"""
2025-12-07 17:15:09 +02:00
# Return context based on response type
2025-12-07 17:15:09 +02:00
if response_type == "autonomous_general":
context = f"""{core_context}
2025-12-07 17:15:09 +02:00
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
2025-12-07 17:15:09 +02:00
elif response_type == "autonomous_tweet":
context = f"""{core_context}
2025-12-07 17:15:09 +02:00
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
2025-12-07 17:15:09 +02:00
elif response_type == "dm_response" or response_type == "server_response":
context = f"""{core_context}
2025-12-07 17:15:09 +02:00
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
2025-12-07 17:15:09 +02:00
elif response_type == "conversation_join":
context = f"""{core_context}
2025-12-07 17:15:09 +02:00
## MIKU SONG LYRICS (Complete Original)
{lyrics}"""
2025-12-07 17:15:09 +02:00
elif response_type == "emoji_selection":
# For emoji reactions, minimal context needed
context = ""
2025-12-07 17:15:09 +02:00
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