# 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_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}""" 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