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

@@ -578,12 +578,54 @@
#chat-messages::-webkit-scrollbar-thumb:hover {
background: #666;
}
/* Evil Mode Styles */
body.evil-mode h1, body.evil-mode h3 {
color: #ff4444;
}
body.evil-mode .tab-button.active {
border-bottom-color: #ff4444;
}
body.evil-mode #evil-mode-toggle {
background: #ff4444;
border-color: #ff4444;
color: #000;
}
body.evil-mode .server-name {
color: #ff4444;
}
body.evil-mode .chat-message-sender {
color: #ff4444;
}
body.evil-mode .chat-message.assistant-message {
border-left-color: #ff4444;
}
body.evil-mode #notification {
border-color: #ff4444;
}
/* Override any blue status text in evil mode */
body.evil-mode [style*="color: #007bff"],
body.evil-mode [style*="color: rgb(0, 123, 255)"] {
color: #ff4444 !important;
}
</style>
</head>
<body>
<div class="panel">
<h1>Miku Control Panel</h1>
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
<h1 id="panel-title">Miku Control Panel</h1>
<button id="evil-mode-toggle" onclick="toggleEvilMode()" style="background: #333; color: #fff; padding: 0.5rem 1rem; border: 2px solid #666; border-radius: 4px; cursor: pointer; font-weight: bold;">
😈 Evil Mode: OFF
</button>
</div>
<p style="color: #ccc; margin-bottom: 2rem;">
💬 <strong>DM Support:</strong> Users can message Miku directly in DMs. She responds to every message using the DM mood (auto-rotating every 2 hours).
</p>
@@ -1223,6 +1265,7 @@
// Global variables
let currentMood = 'neutral';
let servers = [];
let evilMode = false;
// Mood emoji mapping
const MOOD_EMOJIS = {
@@ -1242,6 +1285,14 @@ const MOOD_EMOJIS = {
"silly": "🪿"
};
// Evil mood emoji mapping
const EVIL_MOOD_EMOJIS = {
"aggressive": "👿",
"cunning": "🐍",
"sarcastic": "😈",
"evil_neutral": ""
};
// Tab switching functionality
function switchTab(tabId) {
// Hide all tab contents
@@ -1273,6 +1324,7 @@ document.addEventListener('DOMContentLoaded', function() {
loadServers();
loadLastPrompt();
loadLogs();
checkEvilModeStatus(); // Check evil mode on load
console.log('🚀 DOMContentLoaded - initializing figurine subscribers list');
refreshFigurineSubscribers();
loadProfilePictureMetadata();
@@ -1563,7 +1615,7 @@ async function sendFigurineNowToAll() {
const statusDiv = document.getElementById('figurine-all-status');
statusDiv.textContent = 'Sending...';
statusDiv.style.color = '#007bff';
statusDiv.style.color = evilMode ? '#ff4444' : '#007bff';
const formData = new FormData();
if (tweetUrl) {
@@ -1609,7 +1661,7 @@ async function sendFigurineToSingleUser() {
console.log(`📨 Figurines: Sending to single user ${userId}, tweet: ${tweetUrl || 'random'}`);
statusDiv.textContent = 'Sending...';
statusDiv.style.color = '#007bff';
statusDiv.style.color = evilMode ? '#ff4444' : '#007bff';
const formData = new FormData();
formData.append('user_id', userId);
@@ -1934,7 +1986,9 @@ async function updateBedtimeRange(guildId) {
async function setMood() {
const mood = document.getElementById('mood').value;
try {
await apiCall('/mood', 'POST', { mood: mood });
// Use different endpoint for evil mode
const endpoint = evilMode ? '/evil-mode/mood' : '/mood';
await apiCall(endpoint, 'POST', { mood: mood });
showNotification(`Mood set to ${mood}`);
currentMood = mood;
} catch (error) {
@@ -1962,6 +2016,89 @@ async function calmMiku() {
}
}
// Evil Mode Functions
async function checkEvilModeStatus() {
try {
const result = await apiCall('/evil-mode');
evilMode = result.evil_mode;
updateEvilModeUI();
// If evil mode is on, set the current evil mood in dropdown
if (evilMode && result.mood) {
const moodSelect = document.getElementById('mood');
moodSelect.value = result.mood;
}
} catch (error) {
console.error('Failed to check evil mode status:', error);
}
}
async function toggleEvilMode() {
try {
const toggleBtn = document.getElementById('evil-mode-toggle');
toggleBtn.disabled = true;
toggleBtn.textContent = '⏳ Switching...';
const result = await apiCall('/evil-mode/toggle', 'POST');
evilMode = result.evil_mode;
updateEvilModeUI();
if (evilMode) {
showNotification('😈 Evil Mode enabled! Evil Miku has awakened...');
} else {
showNotification('🎤 Evil Mode disabled. Normal Miku is back!');
}
} catch (error) {
console.error('Failed to toggle evil mode:', error);
showNotification('Failed to toggle evil mode: ' + error.message, 'error');
}
}
function updateEvilModeUI() {
const body = document.body;
const title = document.getElementById('panel-title');
const toggleBtn = document.getElementById('evil-mode-toggle');
const moodSelect = document.getElementById('mood');
if (evilMode) {
body.classList.add('evil-mode');
title.textContent = 'Evil Miku Control Panel';
toggleBtn.textContent = '😈 Evil Mode: ON';
toggleBtn.disabled = false;
// Switch mood dropdown to evil moods
moodSelect.innerHTML = `
<option value="aggressive">👿 aggressive</option>
<option value="cunning">🐍 cunning</option>
<option value="sarcastic">😈 sarcastic</option>
<option value="evil_neutral" selected>evil neutral</option>
`;
} else {
body.classList.remove('evil-mode');
title.textContent = 'Miku Control Panel';
toggleBtn.textContent = '😈 Evil Mode: OFF';
toggleBtn.disabled = false;
// Switch mood dropdown back to normal moods
moodSelect.innerHTML = `
<option value="angry">💢 angry</option>
<option value="asleep">💤 asleep</option>
<option value="bubbly">🫧 bubbly</option>
<option value="curious">👀 curious</option>
<option value="excited">✨ excited</option>
<option value="flirty">🫦 flirty</option>
<option value="irritated">😒 irritated</option>
<option value="melancholy">🍷 melancholy</option>
<option value="neutral" selected>neutral</option>
<option value="romantic">💌 romantic</option>
<option value="serious">👔 serious</option>
<option value="shy">👉👈 shy</option>
<option value="silly">🪿 silly</option>
<option value="sleepy">🌙 sleepy</option>
`;
}
}
// Autonomous Actions
async function triggerAutonomous(actionType) {
const selectedServer = document.getElementById('server-select').value;