Implement Evil Miku mode with persistence, fix API event loop issues, and improve formatting

- Added Evil Miku mode with 4 evil moods (aggressive, cunning, sarcastic, evil_neutral)
- Created evil mode content files (evil_miku_lore.txt, evil_miku_prompt.txt, evil_miku_lyrics.txt)
- Implemented persistent evil mode state across restarts (saves to memory/evil_mode_state.json)
- Fixed API endpoints to use client.loop.create_task() to prevent timeout errors
- Added evil mode toggle in web UI with red theme styling
- Modified mood rotation to handle evil mode
- Configured DarkIdol uncensored model for evil mode text generation
- Reduced system prompt redundancy by removing duplicate content
- Added markdown escape for single asterisks (actions) while preserving bold formatting
- Evil mode now persists username, pfp, and nicknames across restarts without re-applying changes
This commit is contained in:
2026-01-02 17:11:58 +02:00
parent b38bdf2435
commit 6ec33bcecb
38 changed files with 5707 additions and 164 deletions

View File

@@ -79,13 +79,22 @@ async def miku_say_something_general_for_server(guild_id: int):
print(f"⚠️ Autonomous channel not found for server {guild_id}")
return
# Use server-specific mood
mood = server_config.current_mood_name
time_of_day = get_time_of_day()
emoji = MOOD_EMOJIS.get(mood, "")
# Check if evil mode is active
from utils.evil_mode import is_evil_mode, get_evil_general_prompt, get_evil_mood_emoji, get_current_evil_mood
evil_mode = is_evil_mode()
# Special handling for sleep state
if mood == "asleep":
# Use appropriate mood based on mode
if evil_mode:
mood, _ = get_current_evil_mood()
emoji = get_evil_mood_emoji(mood)
else:
mood = server_config.current_mood_name
emoji = MOOD_EMOJIS.get(mood, "")
time_of_day = get_time_of_day()
# Special handling for sleep state (only in non-evil mode)
if mood == "asleep" and not evil_mode:
message = random.choice(SLEEP_RESPONSES)
await channel.send(message)
return
@@ -96,13 +105,17 @@ async def miku_say_something_general_for_server(guild_id: int):
history_summary = "\n".join(f"- {msg}" for msg in _server_autonomous_messages[guild_id][-5:]) if _server_autonomous_messages[guild_id] else "None yet."
prompt = (
f"Miku is feeling {mood}. It's currently {time_of_day}. "
f"Write a short, natural message that Miku might say out of the blue in a chat. "
f"She might greet everyone, make a cute observation, ask a silly question, or say something funny. "
f"Make sure it feels casual and spontaneous, like a real person might say.\n\n"
f"Here are some things Miku recently said, do not repeat them or say anything too similar:\n{history_summary}"
)
# Use evil prompt if in evil mode
if evil_mode:
prompt = get_evil_general_prompt(mood, time_of_day, history_summary)
else:
prompt = (
f"Miku is feeling {mood}. It's currently {time_of_day}. "
f"Write a short, natural message that Miku might say out of the blue in a chat. "
f"She might greet everyone, make a cute observation, ask a silly question, or say something funny. "
f"Make sure it feels casual and spontaneous, like a real person might say.\n\n"
f"Here are some things Miku recently said, do not repeat them or say anything too similar:\n{history_summary}"
)
for attempt in range(3): # retry up to 3 times if message is too similar
# Use consistent user_id per guild for autonomous actions to enable conversation history
@@ -117,7 +130,8 @@ async def miku_say_something_general_for_server(guild_id: int):
_server_autonomous_messages[guild_id].append(message)
if len(_server_autonomous_messages[guild_id]) > MAX_HISTORY:
_server_autonomous_messages[guild_id].pop(0)
print(f"💬 Miku said something general in #{channel.name} (Server: {server_config.guild_name})")
character_name = "Evil Miku" if evil_mode else "Miku"
print(f"💬 {character_name} said something general in #{channel.name} (Server: {server_config.guild_name})")
except Exception as e:
print(f"⚠️ Failed to send autonomous message: {e}")
@@ -200,59 +214,76 @@ async def miku_engage_random_user_for_server(guild_id: int, user_id: str = None,
is_invisible = target.status == Status.offline
display_name = target.display_name
# Build prompt based on engagement_type
prompt = f"Miku is feeling {mood} {emoji} during the {time_of_day}. "
if engagement_type == 'activity':
# Force activity-based engagement
if activity_name:
prompt += (
f"She notices {display_name} is currently playing or doing: {activity_name}. "
f"Miku wants to comment on this activity and start a friendly conversation about it."
)
else:
prompt += (
f"She wants to ask {display_name} what they're up to or what they like to do for fun."
)
elif engagement_type == 'status':
# Force status-based engagement
prompt += f"She notices {display_name}'s current status is {target.status.name}. "
if is_invisible:
prompt += (
f"Miku suspects that {display_name} is being sneaky and invisible 👻. "
f"She wants to playfully call them out in a fun, teasing, but still affectionate way."
)
else:
prompt += (
f"Miku wants to comment on their current status and start a conversation."
)
elif engagement_type == 'general':
# Force general conversation
prompt += (
f"Miku wants to casually start a conversation with {display_name}, "
f"maybe ask how they're doing, what they're up to, or talk about something random."
)
else:
# Auto-detect (original behavior)
prompt += f"She notices {display_name}'s current status is {target.status.name}. "
if is_invisible:
prompt += (
f"Miku suspects that {display_name} is being sneaky and invisible 👻. "
f"She wants to playfully call them out in a fun, teasing, but still affectionate way. "
)
elif activity_name:
prompt += (
f"They appear to be playing or doing: {activity_name}. "
f"Miku wants to comment on this and start a friendly conversation."
)
else:
prompt += (
f"Miku wants to casually start a conversation with them, maybe ask how they're doing, what they're up to, or even talk about something random with them."
)
# Check if evil mode is active
from utils.evil_mode import is_evil_mode, get_evil_engage_user_prompt, get_evil_mood_emoji, get_current_evil_mood
evil_mode = is_evil_mode()
prompt += (
f"\nThe message should be short and reflect Miku's current mood."
)
# Use appropriate mood based on mode
if evil_mode:
mood, _ = get_current_evil_mood()
emoji = get_evil_mood_emoji(mood)
else:
# Use server-specific mood instead of global
mood = server_config.current_mood_name
emoji = MOOD_EMOJIS.get(mood, "")
# Build prompt based on engagement_type and mode
if evil_mode:
prompt = get_evil_engage_user_prompt(mood, emoji, time_of_day, display_name,
activity_name, is_invisible, engagement_type)
else:
prompt = f"Miku is feeling {mood} {emoji} during the {time_of_day}. "
if engagement_type == 'activity':
# Force activity-based engagement
if activity_name:
prompt += (
f"She notices {display_name} is currently playing or doing: {activity_name}. "
f"Miku wants to comment on this activity and start a friendly conversation about it."
)
else:
prompt += (
f"She wants to ask {display_name} what they're up to or what they like to do for fun."
)
elif engagement_type == 'status':
# Force status-based engagement
prompt += f"She notices {display_name}'s current status is {target.status.name}. "
if is_invisible:
prompt += (
f"Miku suspects that {display_name} is being sneaky and invisible 👻. "
f"She wants to playfully call them out in a fun, teasing, but still affectionate way."
)
else:
prompt += (
f"Miku wants to comment on their current status and start a conversation."
)
elif engagement_type == 'general':
# Force general conversation
prompt += (
f"Miku wants to casually start a conversation with {display_name}, "
f"maybe ask how they're doing, what they're up to, or talk about something random."
)
else:
# Auto-detect (original behavior)
prompt += f"She notices {display_name}'s current status is {target.status.name}. "
if is_invisible:
prompt += (
f"Miku suspects that {display_name} is being sneaky and invisible 👻. "
f"She wants to playfully call them out in a fun, teasing, but still affectionate way. "
)
elif activity_name:
prompt += (
f"They appear to be playing or doing: {activity_name}. "
f"Miku wants to comment on this and start a friendly conversation."
)
else:
prompt += (
f"Miku wants to casually start a conversation with them, maybe ask how they're doing, what they're up to, or even talk about something random with them."
)
prompt += (
f"\nThe message should be short and reflect Miku's current mood."
)
if engagement_type:
print(f"💬 Engagement type: {engagement_type}")
@@ -262,7 +293,8 @@ async def miku_engage_random_user_for_server(guild_id: int, user_id: str = None,
message = await query_llama(prompt, user_id=f"miku-engage-{guild_id}", guild_id=guild_id)
await channel.send(f"{target.mention} {message}")
_server_user_engagements[guild_id][target.id] = time.time()
print(f"👤 Miku engaged {display_name} in server {server_config.guild_name}")
character_name = "Evil Miku" if evil_mode else "Miku"
print(f"👤 {character_name} engaged {display_name} in server {server_config.guild_name}")
except Exception as e:
print(f"⚠️ Failed to engage user: {e}")
@@ -329,22 +361,32 @@ async def miku_detect_and_join_conversation_for_server(guild_id: int, force: boo
f"{msg.author.display_name}: {msg.content}" for msg in convo_lines
)
# Use server-specific mood instead of global
mood = server_config.current_mood_name
emoji = MOOD_EMOJIS.get(mood, "")
# Check if evil mode is active
from utils.evil_mode import is_evil_mode, get_evil_conversation_join_prompt, get_evil_mood_emoji, get_current_evil_mood
evil_mode = is_evil_mode()
prompt = (
f"Miku is watching a conversation happen in the chat. Her current mood is {mood} {emoji}. "
f"She wants to say something relevant, playful, or insightful based on what people are talking about.\n\n"
f"Here's the conversation:\n{history_text}\n\n"
f"Write a short reply that feels natural and adds to the discussion. It should reflect Miku's mood and personality."
)
# Use appropriate mood based on mode
if evil_mode:
mood, _ = get_current_evil_mood()
emoji = get_evil_mood_emoji(mood)
prompt = get_evil_conversation_join_prompt(mood, emoji, history_text)
else:
# Use server-specific mood instead of global
mood = server_config.current_mood_name
emoji = MOOD_EMOJIS.get(mood, "")
prompt = (
f"Miku is watching a conversation happen in the chat. Her current mood is {mood} {emoji}. "
f"She wants to say something relevant, playful, or insightful based on what people are talking about.\n\n"
f"Here's the conversation:\n{history_text}\n\n"
f"Write a short reply that feels natural and adds to the discussion. It should reflect Miku's mood and personality."
)
try:
# Use consistent user_id for joining conversations to enable conversation history
reply = await query_llama(prompt, user_id=f"miku-conversation-{guild_id}", guild_id=guild_id, response_type="conversation_join")
await channel.send(reply)
print(f"💬 Miku joined an ongoing conversation in server {server_config.guild_name}")
character_name = "Evil Miku" if evil_mode else "Miku"
print(f"💬 {character_name} joined an ongoing conversation in server {server_config.guild_name}")
except Exception as e:
print(f"⚠️ Failed to interject in conversation: {e}")
@@ -375,17 +417,30 @@ async def share_miku_tweet_for_server(guild_id: int):
save_last_sent_tweets()
# Prepare prompt - use server-specific mood instead of global
mood = server_config.current_mood_name
emoji = MOOD_EMOJIS.get(mood, "")
base_prompt = f"Here's a tweet from @{tweet['username']}:\n\n{tweet['text']}\n\nComment on it in a fun Miku style! Miku's current mood is {mood} {emoji}. Make sure the comment reflects Miku's mood and personality."
# Check if evil mode is active
from utils.evil_mode import is_evil_mode, get_evil_tweet_prompt, get_evil_mood_emoji, get_current_evil_mood
evil_mode = is_evil_mode()
# Optionally analyze first image if media exists
img_desc = None
if tweet.get("media") and len(tweet["media"]) > 0:
first_img_url = tweet["media"][0]
base64_img = await download_and_encode_image(first_img_url)
if base64_img:
img_desc = await analyze_image_with_qwen(base64_img)
# Prepare prompt based on mode
if evil_mode:
mood, _ = get_current_evil_mood()
emoji = get_evil_mood_emoji(mood)
base_prompt = get_evil_tweet_prompt(mood, emoji, tweet['username'], tweet['text'], img_desc)
else:
# Use server-specific mood instead of global
mood = server_config.current_mood_name
emoji = MOOD_EMOJIS.get(mood, "")
base_prompt = f"Here's a tweet from @{tweet['username']}:\n\n{tweet['text']}\n\nComment on it in a fun Miku style! Miku's current mood is {mood} {emoji}. Make sure the comment reflects Miku's mood and personality."
if img_desc:
base_prompt += f"\n\nThe image looks like this: {img_desc}"
miku_comment = await query_llama(base_prompt, user_id=f"autonomous-{guild_id}", guild_id=guild_id, response_type="autonomous_tweet")