Files
miku-discord/MOOD_SYSTEM_ANALYSIS.md

13 KiB

Mood System Analysis & Issues

Overview

After examining the Miku Discord bot's mood, mood rotation, and emoji nickname system, I've identified several critical issues that explain why they don't function correctly.


System Architecture

1. Dual Mood System

The bot has TWO independent mood systems:

  • DM Mood: Global mood for all direct messages (globals.DM_MOOD)
  • Server Mood: Per-server mood tracked in ServerConfig objects

2. Mood Rotation

  • DM Mood: Rotates every 2 hours (via rotate_dm_mood())
  • Server Mood: Rotates every 1 hour per server (via rotate_server_mood())

3. Nickname System

Nicknames show mood emojis via the MOOD_EMOJIS dictionary in utils/moods.py


🔴 CRITICAL ISSUES FOUND

Issue #1: Nickname Update Logic Conflict

Location: utils/moods.py lines 143-163

Problem: The update_all_server_nicknames() function uses DM mood to update all server nicknames:

async def update_all_server_nicknames():
    """Update nickname for all servers to show current DM mood"""
    try:
        mood = globals.DM_MOOD.lower()  # ❌ Uses DM mood
        print(f"🔍 DM mood is: {mood}")
        emoji = MOOD_EMOJIS.get(mood, "")
        
        nickname = f"Hatsune Miku{emoji}"
        print(f"🔍 New nickname will be: {nickname}")
        
        for guild in globals.client.guilds:  # ❌ Updates ALL servers
            me = guild.get_member(globals.BOT_USER.id)
            if me is not None:
                try:
                    await me.edit(nick=nickname)

Impact:

  • Server nicknames show DM mood instead of their own server mood
  • All servers get the same nickname despite having independent moods
  • The per-server mood system is functionally broken for nicknames

Expected Behavior: Each server should display its own mood emoji based on server_config.current_mood_name


Issue #2: DM Mood Rotation Updates Server Nicknames

Location: utils/moods.py lines 121-142

Problem: The rotate_dm_mood() function is called by the DM mood scheduler but doesn't update any nicknames:

async def rotate_dm_mood():
    """Rotate DM mood automatically (no keyword triggers)"""
    try:
        old_mood = globals.DM_MOOD
        new_mood = old_mood
        attempts = 0
        
        while new_mood == old_mood and attempts < 5:
            new_mood = random.choice(globals.AVAILABLE_MOODS)
            attempts += 1
        
        globals.DM_MOOD = new_mood
        globals.DM_MOOD_DESCRIPTION = load_mood_description(new_mood)
        
        print(f"🔄 DM mood rotated from {old_mood} to {new_mood}")
        
        # Note: We don't update server nicknames here because servers have their own independent moods.
        # DM mood only affects direct messages to users.

Impact:

  • Comment says "servers have their own independent moods"
  • But update_all_server_nicknames() uses DM mood anyway
  • Inconsistent design philosophy

Issue #3: Incorrect Nickname Function Called After Server Mood Rotation

Location: server_manager.py line 647

Problem: After rotating a server's mood, the system calls update_server_nickname() which is correct, BUT there's confusion in the codebase:

async def rotate_server_mood(guild_id: int):
    """Rotate mood for a specific server"""
    try:
        # ... mood rotation logic ...
        
        server_manager.set_server_mood(guild_id, new_mood_name, load_mood_description(new_mood_name))
        
        # Update nickname for this specific server
        await update_server_nickname(guild_id)  # ✅ Correct function
        
        print(f"🔄 Rotated mood for server {guild_id} from {old_mood_name} to {new_mood_name}")

Analysis: This part is actually correct, but...


Issue #4: nickname_mood_emoji() Function Ambiguity

Location: utils/moods.py lines 165-171

Problem: This function can call either server-specific OR all-server update:

async def nickname_mood_emoji(guild_id: int = None):
    """Update nickname with mood emoji for a specific server or all servers"""
    if guild_id is not None:
        # Update nickname for specific server
        await update_server_nickname(guild_id)
    else:
        # Update nickname for all servers (using DM mood)
        await update_all_server_nicknames()

Impact:

  • If called without guild_id, it overwrites all server nicknames with DM mood
  • Creates confusion about which mood system is active
  • This function might be called incorrectly from various places

Issue #5: Mood Detection in bot.py May Not Trigger Nickname Updates

Location: bot.py lines 469-512

Problem: When mood is auto-detected from keywords in messages, nickname updates are scheduled but may race with the rotation system:

if detected and detected != server_config.current_mood_name:
    print(f"🔄 Auto mood detection for server {message.guild.name}: {server_config.current_mood_name} -> {detected}")
    
    # Block direct transitions to asleep unless from sleepy
    if detected == "asleep" and server_config.current_mood_name != "sleepy":
        print("❌ Ignoring asleep mood; server wasn't sleepy before.")
    else:
        # Update server mood
        server_manager.set_server_mood(message.guild.id, detected)
        
        # Update nickname for this server
        from utils.moods import update_server_nickname
        globals.client.loop.create_task(update_server_nickname(message.guild.id))

Analysis: This part looks correct, but creates a task that may conflict with hourly rotation.


Issue #6: No Emoji for "neutral" Mood

Location: utils/moods.py line 16

MOOD_EMOJIS = {
    "asleep": "💤",
    "neutral": "",  # ❌ Empty string
    "bubbly": "🫧",
    # ... etc
}

Impact: When bot is in neutral mood, nickname becomes just "Hatsune Miku" with no emoji, making it hard to tell if the system is working.

Recommendation: Add an emoji like "🎤" or "" for neutral mood.


🔧 ROOT CAUSE ANALYSIS

The core problem is architectural confusion between two competing systems:

  1. Original Design Intent: Servers should have independent moods with per-server nicknames
  2. Broken Implementation: update_all_server_nicknames() uses global DM mood for all servers
  3. Mixed Signals: Comments say servers are independent, but code says otherwise

Fix #1: Remove update_all_server_nicknames() Entirely

This function violates the per-server mood architecture. It should never be called.

Action:

  • Delete or deprecate update_all_server_nicknames()
  • Ensure all nickname updates go through update_server_nickname(guild_id)

Fix #2: Update nickname_mood_emoji() to Only Support Server-Specific Updates

Current Code:

async def nickname_mood_emoji(guild_id: int = None):
    if guild_id is not None:
        await update_server_nickname(guild_id)
    else:
        await update_all_server_nicknames()  # ❌ Remove this

Fixed Code:

async def nickname_mood_emoji(guild_id: int):
    """Update nickname with mood emoji for a specific server"""
    await update_server_nickname(guild_id)

Fix #3: Add Neutral Mood Emoji

Current:

"neutral": "",

Fixed:

"neutral": "🎤",  # Or ✨, 🎵, etc.

Fix #4: Audit All Calls to Nickname Functions

Search for any calls to:

  • update_all_server_nicknames() - should not exist
  • nickname_mood_emoji() - must always pass guild_id

FOUND ISSUES:

api.py - THREE broken endpoints:

  1. Line 113-114: /mood endpoint sets DM mood but updates ALL server nicknames
  2. Line 126-127: /mood/reset endpoint sets DM mood but updates ALL server nicknames
  3. Line 139-140: /mood/calm endpoint sets DM mood but updates ALL server nicknames

Code:

@app.post("/mood")
async def set_mood_endpoint(data: MoodSetRequest):
    # Update DM mood
    globals.DM_MOOD = data.mood
    globals.DM_MOOD_DESCRIPTION = load_mood_description(data.mood)
    
    # ❌ WRONG: Updates ALL servers with DM mood
    from utils.moods import update_all_server_nicknames
    globals.client.loop.create_task(update_all_server_nicknames())

Impact:

  • API endpoints that change DM mood incorrectly change ALL server nicknames
  • This is the smoking gun! When you use the API/dashboard to change mood, it breaks server nicknames
  • Confirms that DM mood and server moods should be completely independent

Fix:

  • Remove nickname update calls from these endpoints
  • DM mood should NOT affect server nicknames at all
  • If you want to update server nicknames, use the per-server endpoints

api.py also has CORRECT per-server endpoints (line 145+):

  • /servers/{guild_id}/mood - Gets server mood (correct)
  • Likely has POST endpoints for setting server mood (need to verify)

Locations checked:

  • bot.py - Uses update_server_nickname(guild_id) correctly
  • server_manager.py - Rotation calls correct function
  • api.py - DM mood endpoints incorrectly update all servers
  • ⚠️ command_router.py - Imports nickname_mood_emoji but doesn't seem to use it

Fix #5: Add Logging to Verify Mood/Nickname Sync

Add debug logging to update_server_nickname() to track:

  • What mood the server thinks it has
  • What emoji is being applied
  • Whether the Discord API call succeeds

Fix #6: Consider Removing DM Mood Entirely (Optional)

Question: Should DMs have their own mood system?

Current Design:

  • DMs use globals.DM_MOOD
  • DM mood rotates every 2 hours
  • DM mood does NOT affect nicknames (correctly)

Recommendation: This is fine IF the nickname system stops using it. The current separation is logical.


📋 VERIFICATION CHECKLIST

After fixes, verify:

  1. Each server maintains its own mood independently
  2. Server nicknames update when server mood changes
  3. Hourly mood rotation updates the correct server's nickname
  4. Keyword mood detection updates the correct server's nickname
  5. DM mood changes do NOT affect any server nicknames
  6. Neutral mood shows an emoji (or document that empty is intentional)
  7. No race conditions between rotation and manual mood changes

🧪 TESTING PROCEDURE

  1. Test Server Mood Independence:

    • Join multiple servers
    • Manually trigger mood change in one server
    • Verify other servers maintain their moods
  2. Test Nickname Updates:

    • Trigger mood rotation
    • Check nickname shows correct emoji
    • Compare against MOOD_EMOJIS dictionary
  3. Test DM Mood Isolation:

    • Send DM to bot
    • Wait for DM mood rotation
    • Verify server nicknames don't change
  4. Test Mood Detection:

    • Send message with mood keywords
    • Verify mood changes and nickname updates
    • Check logs for correct mood detection

📊 SUMMARY

Component Status Issue
Server Mood System ⚠️ Partially Broken Nicknames use wrong mood when API called
DM Mood System Working Isolated correctly in bot logic
Mood Rotation Working Logic is correct
Nickname Updates 🔴 BROKEN API endpoints use DM mood for servers
Mood Detection Working Keywords trigger correctly
Emoji System ⚠️ Minor Issue Neutral has no emoji
Per-Server API Working /servers/{guild_id}/mood endpoints correct
Global DM API 🔴 BROKEN /mood endpoints incorrectly update servers

KEY FINDING: The bug is primarily in the API layer, not the core bot logic!

When you (or a dashboard) calls:

  • /mood endpoint → Changes DM mood → Updates ALL server nicknames
  • /mood/reset endpoint → Resets DM mood → Updates ALL server nicknames
  • /mood/calm endpoint → Calms DM mood → Updates ALL server nicknames

This explains why it "doesn't seem like they function right" - the API is sabotaging the per-server system!


🚀 PRIORITY FIX ORDER

  1. 🔥 CRITICAL: Fix API endpoints in api.py - Remove update_all_server_nicknames() calls from:

    • /mood endpoint (line 113-114)
    • /mood/reset endpoint (line 126-127)
    • /mood/calm endpoint (line 139-140)
  2. HIGH: Deprecate update_all_server_nicknames() function in utils/moods.py

    • Add deprecation warning
    • Eventually delete it entirely
  3. HIGH: Fix nickname_mood_emoji() to require guild_id

    • Remove the guild_id=None default
    • Remove the DM mood branch
  4. MEDIUM: Add neutral mood emoji - user experience

  5. LOW: Add debug logging - future maintenance

IMMEDIATE ACTION: Fix the three API endpoints. This is the root cause of the visible bug.


📝 CODE LOCATIONS REFERENCE

  • Mood definitions: utils/moods.py
  • Server config: server_manager.py
  • Bot message handling: bot.py
  • LLM mood usage: utils/llm.py
  • Global DM mood: globals.py
  • Mood files: moods/*.txt