// ============================================================================
// Miku Control Panel — Status Module
// Status display, last prompt, autonomous stats
// ============================================================================
// ===== Status =====
async function loadStatus() {
try {
const result = await apiCall('/status');
const statusDiv = document.getElementById('status');
if (result.evil_mode !== undefined && result.evil_mode !== evilMode) {
evilMode = result.evil_mode;
updateEvilModeUI();
if (evilMode && result.mood) {
const moodSelect = document.getElementById('mood');
if (moodSelect) moodSelect.value = result.mood;
}
}
if (result.mood) {
const moodSelect = document.getElementById('mood');
if (moodSelect && moodSelect.querySelector(`option[value="${result.mood}"]`)) {
moodSelect.value = result.mood;
}
currentMood = result.mood;
}
let serverMoodsHtml = '';
if (result.server_moods) {
serverMoodsHtml = '
Server Moods:
';
for (const [guildId, mood] of Object.entries(result.server_moods)) {
const server = servers.find(s => s.guild_id == guildId);
const serverName = server ? server.guild_name : `Server ${guildId}`;
const emojiMap = evilMode ? EVIL_MOOD_EMOJIS : MOOD_EMOJIS;
serverMoodsHtml += `• ${serverName}: ${mood} ${emojiMap[mood] || ''}
`;
}
serverMoodsHtml += '
';
}
const moodEmoji = evilMode ? (EVIL_MOOD_EMOJIS[result.mood] || '') : (MOOD_EMOJIS[result.mood] || '');
const moodLabel = evilMode ? `😈 ${result.mood} ${moodEmoji}` : `${result.mood} ${moodEmoji}`;
statusDiv.innerHTML = `
Status: ${result.status}
DM Mood: ${moodLabel}
Servers: ${result.servers}
Active Schedulers: ${result.active_schedulers}
💬 DM Support: Users can message Miku directly in DMs. She responds to every DM message using the DM mood (auto-rotating every 2 hours).
${serverMoodsHtml}
`;
} catch (error) {
console.error('Failed to load status:', error);
}
}
// ===== Last Prompt =====
async function loadLastPrompt() {
const source = localStorage.getItem('miku-prompt-source') || 'cat';
const promptEl = document.getElementById('last-prompt');
const infoEl = document.getElementById('prompt-cat-info');
try {
if (source === 'cat') {
const result = await apiCall('/prompt/cat');
if (result.timestamp) {
infoEl.innerHTML = `User: ${escapeHtml(result.user || '?')} | Mood: ${escapeHtml(result.mood || '?')} | Time: ${new Date(result.timestamp).toLocaleString()}`;
promptEl.textContent = result.full_prompt + `\n\n${'═'.repeat(60)}\n[Cat Response]\n${result.response}`;
} else {
infoEl.textContent = '';
promptEl.textContent = result.full_prompt || 'No Cheshire Cat interaction yet.';
}
} else {
infoEl.textContent = '';
const result = await apiCall('/prompt');
promptEl.textContent = result.prompt;
}
} catch (error) {
console.error('Failed to load last prompt:', error);
}
}
// ===== Autonomous Stats =====
async function loadAutonomousStats() {
const serverSelect = document.getElementById('autonomous-server-select');
const selectedGuildId = serverSelect.value;
if (!selectedGuildId) {
document.getElementById('autonomous-stats-display').innerHTML = 'Please select a server to view autonomous stats.
';
return;
}
try {
const data = await apiCall('/autonomous/stats');
if (!data.servers || !data.servers[selectedGuildId]) {
document.getElementById('autonomous-stats-display').innerHTML = 'Server not found or not initialized.
';
return;
}
const serverData = data.servers[selectedGuildId];
displayAutonomousStats(serverData);
} catch (error) {
console.error('Failed to load autonomous stats:', error);
}
}
function displayAutonomousStats(data) {
const container = document.getElementById('autonomous-stats-display');
if (!data.context) {
container.innerHTML = `
⚠️ Context Not Initialized
This server hasn't had any activity yet. Context tracking will begin once messages are sent.
Current Mood: ${data.mood} ${MOOD_EMOJIS[data.mood] || ''}
Energy: ${data.mood_profile.energy}
Sociability: ${data.mood_profile.sociability}
Impulsiveness: ${data.mood_profile.impulsiveness}
`;
return;
}
const ctx = data.context;
const profile = data.mood_profile;
const lastActionMin = Math.floor(ctx.time_since_last_action / 60);
const lastInteractionMin = Math.floor(ctx.time_since_last_interaction / 60);
container.innerHTML = `
🎭 Mood & Personality Profile
Current Mood
${data.mood} ${MOOD_EMOJIS[data.mood] || ''}
Energy Level
${(profile.energy * 100).toFixed(0)}%
Sociability
${(profile.sociability * 100).toFixed(0)}%
Impulsiveness
${(profile.impulsiveness * 100).toFixed(0)}%
📈 Activity Metrics
Messages (Last 5 min) ⚡ ephemeral
${ctx.messages_last_5min}
Messages (Last Hour) ⚡ ephemeral
${ctx.messages_last_hour}
Conversation Momentum 💾 saved
${(ctx.conversation_momentum * 100).toFixed(0)}%
Decays with downtime (half-life: 10min)
Unique Users Active ⚡ ephemeral
${ctx.unique_users_active}
👥 User Events
Users Joined Recently
${ctx.users_joined_recently}
Status Changes
${ctx.users_status_changed}
Active Activities
${ctx.users_started_activity.length}
${ctx.users_started_activity.length > 0 ? `
${ctx.users_started_activity.join(', ')}
` : ''}
⏱️ Timing & Context
Time Since Last Action 💾 saved
${lastActionMin} min
${ctx.time_since_last_action.toFixed(1)}s
Time Since Last Interaction 💾 saved
${lastInteractionMin} min
${ctx.time_since_last_interaction.toFixed(1)}s
Messages Since Last Appearance 💾 saved
${ctx.messages_since_last_appearance}
Current Time Context ⚡ ephemeral
${ctx.hour_of_day}:00
${ctx.is_weekend ? '📅 Weekend' : '📆 Weekday'}
🧠 Base Energy Level
From current mood personality
${(ctx.mood_energy_level * 100).toFixed(0)}%
💡 Combined with activity metrics to determine action likelihood.
📝 High energy = shorter wait times, higher action chance.
💾 Persisted across restarts
`;
}
function getStatColor(value) {
if (value >= 0.8) return '#4caf50';
if (value >= 0.6) return '#8bc34a';
if (value >= 0.4) return '#ffc107';
if (value >= 0.2) return '#ff9800';
return '#f44336';
}
function getMomentumColor(value) {
if (value >= 0.7) return '#4caf50';
if (value >= 0.4) return '#2196f3';
return '#9e9e9e';
}
function populateAutonomousServerDropdown() {
const select = document.getElementById('autonomous-server-select');
if (!select) return;
const currentValue = select.value;
select.innerHTML = '';
servers.forEach(server => {
const option = document.createElement('option');
option.value = server.guild_id;
option.textContent = `${server.guild_name} (${server.guild_id})`;
select.appendChild(option);
});
if (currentValue && servers.some(s => String(s.guild_id) === currentValue)) {
select.value = currentValue;
}
}