This commit completes a major refactoring of the Miku control panel from a single 7,191-line monolithic HTML file to a modern modular architecture: CHANGES: - Extracted 872 lines of CSS into css/style.css - Created 10 specialized JavaScript modules (4,964 lines total): * core.js: Global state, utilities, initialization, polling system * servers.js: Server management and mood handling * modes.js: Evil mode, GPU selection, bipolar mode, scoreboard * actions.js: Autonomous/manual actions, custom prompts, reactions * image-gen.js: Image generation system * status.js: Status display and statistics * dm.js: DM user management and conversation analysis * chat.js: LLM chat interface with streaming and voice calls * memories.js: Cheshire Cat memory integration (episodic/declarative/procedural) * profile.js: Profile picture, album gallery, activities editor - Cleaned index.html to 1,351 lines (structure only, zero inline JS/CSS) - Removed 12 duplicate variable declarations - Maintained strict script load order for dependency resolution - Added backup comment to index.html.bak for historical reference VERIFICATION COMPLETED: ✓ All 191 functions/variables from original accounted for ✓ Cross-referenced with backup to ensure nothing lost ✓ All onclick handlers and modal systems validated ✓ No circular dependencies or broken references ✓ HTML structure integrity verified (11 tabs, all buttons/modals intact) ✓ CropperJS CDN links preserved The refactored code is production-ready with improved maintainability and clear separation of concerns.
685 lines
26 KiB
JavaScript
685 lines
26 KiB
JavaScript
// ===== Server Management Functions =====
|
||
|
||
async function loadServers() {
|
||
try {
|
||
console.log('🎭 Loading servers...');
|
||
const data = await apiCall('/servers');
|
||
console.log('🎭 Servers response:', data);
|
||
|
||
if (data.servers) {
|
||
servers = data.servers;
|
||
console.log(`🎭 Loaded ${servers.length} servers:`, servers);
|
||
|
||
// Debug: Log each server's guild_id
|
||
servers.forEach((server, index) => {
|
||
console.log(`🎭 Server ${index}: guild_id = ${server.guild_id}, name = ${server.guild_name}`);
|
||
});
|
||
|
||
// Debug: Show raw response data
|
||
console.log('🎭 Raw API response data:', JSON.stringify(data, null, 2));
|
||
|
||
// Display servers
|
||
displayServers();
|
||
populateServerDropdowns();
|
||
populateMoodDropdowns(); // Populate mood dropdowns after servers are loaded
|
||
} else {
|
||
console.warn('🎭 No servers found in response');
|
||
servers = [];
|
||
}
|
||
} catch (error) {
|
||
console.error('🎭 Failed to load servers:', error);
|
||
servers = [];
|
||
}
|
||
}
|
||
|
||
function displayServers() {
|
||
const container = document.getElementById('servers-list');
|
||
|
||
if (servers.length === 0) {
|
||
container.innerHTML = '<p>No servers configured</p>';
|
||
return;
|
||
}
|
||
|
||
container.innerHTML = servers.map(server => `
|
||
<div class="server-card">
|
||
<div class="server-header">
|
||
<div class="server-name">${server.guild_name}</div>
|
||
<div class="server-actions">
|
||
<button onclick="editServer('${String(server.guild_id)}')">Edit</button>
|
||
<button onclick="removeServer('${String(server.guild_id)}')" style="background: #d32f2f;">Remove</button>
|
||
</div>
|
||
</div>
|
||
<div><strong>Guild ID:</strong> ${server.guild_id}</div>
|
||
<div><strong>Autonomous Channel:</strong> #${server.autonomous_channel_name} (${server.autonomous_channel_id})</div>
|
||
<div><strong>Bedtime Channels:</strong> ${server.bedtime_channel_ids.join(', ')}</div>
|
||
<div><strong>Features:</strong>
|
||
${server.enabled_features.map(feature => `<span class="feature-tag">${feature}</span>`).join('')}
|
||
</div>
|
||
<div><strong>Autonomous Interval:</strong> ${server.autonomous_interval_minutes} minutes</div>
|
||
<div><strong>Conversation Detection:</strong> ${server.conversation_detection_interval_minutes} minutes</div>
|
||
<div><strong>Bedtime Range:</strong> ${String(server.bedtime_hour || 21).padStart(2, '0')}:${String(server.bedtime_minute || 0).padStart(2, '0')} - ${String(server.bedtime_hour_end || 23).padStart(2, '0')}:${String(server.bedtime_minute_end || 59).padStart(2, '0')}</div>
|
||
|
||
<!-- Bedtime Configuration -->
|
||
<div style="margin-top: 1rem; padding: 1rem; background: #2a2a2a; border-radius: 4px;">
|
||
<h4 style="margin: 0 0 0.5rem 0; color: #61dafb;">Bedtime Settings</h4>
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 0.5rem;">
|
||
<div>
|
||
<label style="display: block; font-size: 0.9rem; margin-bottom: 0.2rem;">Start Time:</label>
|
||
<input type="time" id="bedtime-start-${String(server.guild_id)}" value="${String(server.bedtime_hour || 21).padStart(2, '0')}:${String(server.bedtime_minute || 0).padStart(2, '0')}" style="padding: 0.3rem; background: #333; color: white; border: 1px solid #555; border-radius: 3px; width: 100%;">
|
||
</div>
|
||
<div>
|
||
<label style="display: block; font-size: 0.9rem; margin-bottom: 0.2rem;">End Time:</label>
|
||
<input type="time" id="bedtime-end-${String(server.guild_id)}" value="${String(server.bedtime_hour_end || 23).padStart(2, '0')}:${String(server.bedtime_minute_end || 59).padStart(2, '0')}" style="padding: 0.3rem; background: #333; color: white; border: 1px solid #555; border-radius: 3px; width: 100%;">
|
||
</div>
|
||
</div>
|
||
<button onclick="updateBedtimeRange('${String(server.guild_id)}')" style="background: #4caf50;">Update Bedtime Range</button>
|
||
</div>
|
||
|
||
<!-- Per-Server Mood Display -->
|
||
<div style="margin-top: 1rem; padding: 1rem; background: #2a2a2a; border-radius: 4px;">
|
||
<h4 style="margin: 0 0 0.5rem 0; color: #61dafb;">Server Mood</h4>
|
||
<div><strong>Current Mood:</strong> ${server.current_mood_name || 'neutral'} ${MOOD_EMOJIS[server.current_mood_name] || ''}</div>
|
||
<div><strong>Sleeping:</strong> ${server.is_sleeping ? 'Yes' : 'No'}</div>
|
||
<div style="margin-top: 0.5rem;">
|
||
<select id="mood-select-${String(server.guild_id)}" style="margin-right: 0.5rem; padding: 0.3rem; background: #333; color: white; border: 1px solid #555; border-radius: 3px;">
|
||
<option value="">Select Mood...</option>
|
||
</select>
|
||
<button onclick="setServerMood('${String(server.guild_id)}')" style="margin-right: 0.5rem;">Change Mood</button>
|
||
<button onclick="resetServerMood('${String(server.guild_id)}')" style="background: #ff9800;">Reset Mood</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
|
||
// Debug: Log what element IDs were created
|
||
console.log('🎭 Server cards rendered. Checking for mood-select elements:');
|
||
document.querySelectorAll('[id^="mood-select-"]').forEach(el => {
|
||
console.log(`🎭 Found mood-select element: ${el.id}`);
|
||
});
|
||
|
||
// Populate mood dropdowns after server cards are created
|
||
populateMoodDropdowns();
|
||
}
|
||
|
||
async function populateServerDropdowns() {
|
||
const serverSelect = document.getElementById('server-select');
|
||
const manualServerSelect = document.getElementById('manual-server-select');
|
||
const customPromptServerSelect = document.getElementById('custom-prompt-server-select');
|
||
|
||
// Clear existing options except "All Servers"
|
||
serverSelect.innerHTML = '<option value="all">All Servers</option>';
|
||
manualServerSelect.innerHTML = '<option value="all">All Servers</option>';
|
||
customPromptServerSelect.innerHTML = '<option value="all">All Servers</option>';
|
||
|
||
console.log('🎭 Populating server dropdowns with', servers.length, 'servers');
|
||
|
||
// Add server options
|
||
servers.forEach(server => {
|
||
console.log(`🎭 Adding server to dropdown: ${server.guild_name} (guild_id: ${server.guild_id}, type: ${typeof server.guild_id})`);
|
||
|
||
const option = document.createElement('option');
|
||
option.value = server.guild_id;
|
||
option.textContent = server.guild_name;
|
||
|
||
serverSelect.appendChild(option.cloneNode(true));
|
||
manualServerSelect.appendChild(option);
|
||
customPromptServerSelect.appendChild(option.cloneNode(true));
|
||
});
|
||
|
||
// Debug: Check what's actually in the manual-server-select dropdown
|
||
console.log('🎭 manual-server-select options:');
|
||
Array.from(manualServerSelect.options).forEach((opt, idx) => {
|
||
console.log(` [${idx}] value="${opt.value}" text="${opt.textContent}"`);
|
||
});
|
||
|
||
// Populate autonomous stats dropdown
|
||
populateAutonomousServerDropdown();
|
||
}
|
||
|
||
// Figurine subscribers UI functions (must be global for onclick handlers)
|
||
async function refreshFigurineSubscribers() {
|
||
try {
|
||
console.log('🔄 Figurines: Fetching subscribers...');
|
||
const data = await apiCall('/figurines/subscribers');
|
||
console.log('📋 Figurines: Received subscribers:', data);
|
||
displayFigurineSubscribers(data.subscribers || []);
|
||
showNotification('Subscribers refreshed');
|
||
} catch (e) {
|
||
console.error('❌ Figurines: Failed to fetch subscribers:', e);
|
||
}
|
||
}
|
||
|
||
function displayFigurineSubscribers(subscribers) {
|
||
const container = document.getElementById('figurine-subscribers-list');
|
||
if (!container) return;
|
||
if (!subscribers.length) {
|
||
container.innerHTML = '<p>No subscribers yet.</p>';
|
||
return;
|
||
}
|
||
let html = '<ul>';
|
||
subscribers.forEach(uid => {
|
||
const uidStr = String(uid);
|
||
html += `<li><code>${uidStr}</code> <button onclick="removeFigurineSubscriber('${uidStr}')">Remove</button></li>`;
|
||
});
|
||
html += '</ul>';
|
||
container.innerHTML = html;
|
||
}
|
||
|
||
async function addFigurineSubscriber() {
|
||
try {
|
||
console.log('➕ Figurines: Adding subscriber...');
|
||
const uid = document.getElementById('figurine-user-id').value.trim();
|
||
if (!uid) {
|
||
showNotification('Enter a user ID', 'error');
|
||
return;
|
||
}
|
||
const form = new FormData();
|
||
form.append('user_id', uid);
|
||
const res = await fetch('/figurines/subscribers', { method: 'POST', body: form });
|
||
const data = await res.json();
|
||
console.log('➕ Figurines: Add subscriber response:', data);
|
||
if (data.status === 'ok') {
|
||
showNotification('Subscriber added');
|
||
document.getElementById('figurine-user-id').value = '';
|
||
refreshFigurineSubscribers();
|
||
} else {
|
||
showNotification(data.message || 'Failed to add subscriber', 'error');
|
||
}
|
||
} catch (e) {
|
||
console.error('❌ Figurines: Failed to add subscriber:', e);
|
||
showNotification('Failed to add subscriber', 'error');
|
||
}
|
||
}
|
||
|
||
async function removeFigurineSubscriber(uid) {
|
||
try {
|
||
console.log(`🗑️ Figurines: Removing subscriber ${uid}...`);
|
||
const data = await apiCall(`/figurines/subscribers/${uid}`, 'DELETE');
|
||
console.log('🗑️ Figurines: Remove subscriber response:', data);
|
||
if (data.status === 'ok') {
|
||
showNotification('Subscriber removed');
|
||
refreshFigurineSubscribers();
|
||
} else {
|
||
showNotification(data.message || 'Failed to remove subscriber', 'error');
|
||
}
|
||
} catch (e) {
|
||
console.error('❌ Figurines: Failed to remove subscriber:', e);
|
||
}
|
||
}
|
||
|
||
async function sendFigurineNowToAll() {
|
||
try {
|
||
console.log('📨 Figurines: Triggering send to all subscribers...');
|
||
const tweetUrl = document.getElementById('figurine-tweet-url-all').value.trim();
|
||
const statusDiv = document.getElementById('figurine-all-status');
|
||
|
||
statusDiv.textContent = 'Sending...';
|
||
statusDiv.style.color = evilMode ? '#ff4444' : '#007bff';
|
||
|
||
const formData = new FormData();
|
||
if (tweetUrl) {
|
||
formData.append('tweet_url', tweetUrl);
|
||
}
|
||
|
||
const res = await fetch('/figurines/send_now', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
const data = await res.json();
|
||
|
||
console.log('📨 Figurines: Send to all response:', data);
|
||
if (data.status === 'ok') {
|
||
showNotification('Figurine DMs queued for all subscribers');
|
||
statusDiv.textContent = 'Queued successfully';
|
||
statusDiv.style.color = '#28a745';
|
||
document.getElementById('figurine-tweet-url-all').value = ''; // Clear input
|
||
} else {
|
||
showNotification(data.message || 'Bot not ready', 'error');
|
||
statusDiv.textContent = 'Failed: ' + (data.message || 'Unknown error');
|
||
statusDiv.style.color = '#dc3545';
|
||
}
|
||
} catch (e) {
|
||
console.error('❌ Figurines: Failed to queue figurine DMs for all:', e);
|
||
showNotification('Failed to queue figurine DMs', 'error');
|
||
document.getElementById('figurine-all-status').textContent = 'Error: ' + e.message;
|
||
document.getElementById('figurine-all-status').style.color = '#dc3545';
|
||
}
|
||
}
|
||
|
||
async function sendFigurineToSingleUser() {
|
||
try {
|
||
const userId = document.getElementById('figurine-single-user-id').value.trim();
|
||
const tweetUrl = document.getElementById('figurine-tweet-url-single').value.trim();
|
||
const statusDiv = document.getElementById('figurine-single-status');
|
||
|
||
if (!userId) {
|
||
showNotification('Enter a user ID', 'error');
|
||
return;
|
||
}
|
||
|
||
console.log(`📨 Figurines: Sending to single user ${userId}, tweet: ${tweetUrl || 'random'}`);
|
||
|
||
statusDiv.textContent = 'Sending...';
|
||
statusDiv.style.color = evilMode ? '#ff4444' : '#007bff';
|
||
|
||
const formData = new FormData();
|
||
formData.append('user_id', userId);
|
||
if (tweetUrl) {
|
||
formData.append('tweet_url', tweetUrl);
|
||
}
|
||
|
||
const res = await fetch('/figurines/send_to_user', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
const data = await res.json();
|
||
|
||
console.log('📨 Figurines: Send to single user response:', data);
|
||
if (data.status === 'ok') {
|
||
showNotification(`Figurine DM queued for user ${userId}`);
|
||
statusDiv.textContent = 'Queued successfully';
|
||
statusDiv.style.color = '#28a745';
|
||
document.getElementById('figurine-single-user-id').value = ''; // Clear inputs
|
||
document.getElementById('figurine-tweet-url-single').value = '';
|
||
} else {
|
||
showNotification(data.message || 'Failed to queue DM', 'error');
|
||
statusDiv.textContent = 'Failed: ' + (data.message || 'Unknown error');
|
||
statusDiv.style.color = '#dc3545';
|
||
}
|
||
} catch (e) {
|
||
console.error('❌ Figurines: Failed to queue figurine DM for single user:', e);
|
||
showNotification('Failed to queue figurine DM', 'error');
|
||
document.getElementById('figurine-single-status').textContent = 'Error: ' + e.message;
|
||
document.getElementById('figurine-single-status').style.color = '#dc3545';
|
||
}
|
||
}
|
||
|
||
// Keep the old function for backward compatibility
|
||
async function sendFigurineNow() {
|
||
return sendFigurineNowToAll();
|
||
}
|
||
|
||
async function addServer() {
|
||
// Don't use parseInt() for Discord IDs - they're too large for JS integers
|
||
const guildId = document.getElementById('new-guild-id').value.trim();
|
||
const guildName = document.getElementById('new-guild-name').value;
|
||
const autonomousChannelId = document.getElementById('new-autonomous-channel-id').value.trim();
|
||
const autonomousChannelName = document.getElementById('new-autonomous-channel-name').value;
|
||
const bedtimeChannelIds = document.getElementById('new-bedtime-channel-ids').value
|
||
.split(',').map(id => id.trim()).filter(id => id.length > 0);
|
||
|
||
const enabledFeatures = [];
|
||
if (document.getElementById('feature-autonomous').checked) enabledFeatures.push('autonomous');
|
||
if (document.getElementById('feature-bedtime').checked) enabledFeatures.push('bedtime');
|
||
if (document.getElementById('feature-monday-video').checked) enabledFeatures.push('monday_video');
|
||
|
||
if (!guildId || !guildName || !autonomousChannelId || !autonomousChannelName) {
|
||
showNotification('Please fill in all required fields', 'error');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await apiCall('/servers', 'POST', {
|
||
guild_id: guildId,
|
||
guild_name: guildName,
|
||
autonomous_channel_id: autonomousChannelId,
|
||
autonomous_channel_name: autonomousChannelName,
|
||
bedtime_channel_ids: bedtimeChannelIds.length > 0 ? bedtimeChannelIds : [autonomousChannelId],
|
||
enabled_features: enabledFeatures
|
||
});
|
||
|
||
showNotification('Server added successfully');
|
||
loadServers();
|
||
|
||
// Clear form
|
||
document.getElementById('new-guild-id').value = '';
|
||
document.getElementById('new-guild-name').value = '';
|
||
document.getElementById('new-autonomous-channel-id').value = '';
|
||
document.getElementById('new-autonomous-channel-name').value = '';
|
||
document.getElementById('new-bedtime-channel-ids').value = '';
|
||
} catch (error) {
|
||
console.error('Failed to add server:', error);
|
||
}
|
||
}
|
||
|
||
async function removeServer(guildId) {
|
||
if (!confirm('Are you sure you want to remove this server?')) {
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await apiCall(`/servers/${guildId}`, 'DELETE');
|
||
showNotification('Server removed successfully');
|
||
loadServers();
|
||
} catch (error) {
|
||
console.error('Failed to remove server:', error);
|
||
}
|
||
}
|
||
|
||
async function editServer(guildId) {
|
||
// For now, just show a notification - you can implement a full edit form later
|
||
showNotification('Edit functionality coming soon!');
|
||
}
|
||
|
||
async function repairConfig() {
|
||
if (!confirm('This will attempt to repair corrupted server configurations. Are you sure?')) {
|
||
return;
|
||
}
|
||
try {
|
||
await apiCall('/servers/repair', 'POST');
|
||
showNotification('Configuration repair initiated. Please refresh the page to see updated server list.');
|
||
loadServers(); // Reload servers to reflect potential changes
|
||
} catch (error) {
|
||
console.error('Failed to repair config:', error);
|
||
showNotification(error.message || 'Failed to repair configuration', 'error');
|
||
}
|
||
}
|
||
|
||
// Populate mood dropdowns with available moods
|
||
async function populateMoodDropdowns() {
|
||
try {
|
||
console.log('🎭 Loading available moods...');
|
||
const data = await apiCall('/moods/available');
|
||
console.log('🎭 Available moods response:', data);
|
||
|
||
if (data.moods) {
|
||
console.log(`🎭 Found ${data.moods.length} moods:`, data.moods);
|
||
const emojiMap = evilMode ? EVIL_MOOD_EMOJIS : MOOD_EMOJIS;
|
||
|
||
// Populate the DM mood dropdown (#mood on tab1)
|
||
const dmMoodSelect = document.getElementById('mood');
|
||
if (dmMoodSelect) {
|
||
dmMoodSelect.innerHTML = '';
|
||
data.moods.forEach(mood => {
|
||
const opt = document.createElement('option');
|
||
opt.value = mood;
|
||
opt.textContent = `${emojiMap[mood] || ''} ${mood}`.trim();
|
||
if (mood === 'neutral') opt.selected = true;
|
||
dmMoodSelect.appendChild(opt);
|
||
});
|
||
}
|
||
|
||
// Populate the chat mood dropdown (#chat-mood-select on tab7)
|
||
const chatMoodSelect = document.getElementById('chat-mood-select');
|
||
if (chatMoodSelect) {
|
||
chatMoodSelect.innerHTML = '';
|
||
data.moods.forEach(mood => {
|
||
const opt = document.createElement('option');
|
||
opt.value = mood;
|
||
opt.textContent = `${emojiMap[mood] || ''} ${mood}`.trim();
|
||
if (mood === 'neutral') opt.selected = true;
|
||
chatMoodSelect.appendChild(opt);
|
||
});
|
||
}
|
||
|
||
// Populate per-server mood dropdowns (mood-select-{guildId})
|
||
document.querySelectorAll('[id^="mood-select-"]').forEach(select => {
|
||
// Keep only the first option ("Select Mood...")
|
||
while (select.children.length > 1) {
|
||
select.removeChild(select.lastChild);
|
||
}
|
||
});
|
||
|
||
data.moods.forEach(mood => {
|
||
const moodOption = document.createElement('option');
|
||
moodOption.value = mood;
|
||
moodOption.textContent = `${mood} ${emojiMap[mood] || ''}`;
|
||
|
||
document.querySelectorAll('[id^="mood-select-"]').forEach(select => {
|
||
select.appendChild(moodOption.cloneNode(true));
|
||
});
|
||
});
|
||
|
||
console.log('🎭 All mood dropdowns populated successfully');
|
||
} else {
|
||
console.warn('🎭 No moods found in response');
|
||
}
|
||
} catch (error) {
|
||
console.error('🎭 Failed to load available moods:', error);
|
||
}
|
||
}
|
||
|
||
// Per-Server Mood Management
|
||
async function setServerMood(guildId) {
|
||
console.log(`🎭 setServerMood called with guildId: ${guildId} (type: ${typeof guildId})`);
|
||
|
||
// Ensure guildId is a string for consistency
|
||
const guildIdStr = String(guildId);
|
||
console.log(`🎭 Using guildId as string: ${guildIdStr}`);
|
||
|
||
// Debug: Check what elements exist
|
||
const elementId = `mood-select-${guildIdStr}`;
|
||
console.log(`🎭 Looking for element with ID: ${elementId}`);
|
||
|
||
const moodSelect = document.getElementById(elementId);
|
||
console.log(`🎭 Found element:`, moodSelect);
|
||
|
||
if (!moodSelect) {
|
||
console.error(`🎭 ERROR: Element with ID '${elementId}' not found!`);
|
||
console.log(`🎭 Available mood-select elements:`, document.querySelectorAll('[id^="mood-select-"]'));
|
||
showNotification(`Error: Mood selector not found for server ${guildIdStr}`, 'error');
|
||
return;
|
||
}
|
||
|
||
const selectedMood = moodSelect.value;
|
||
|
||
console.log(`🎭 Setting mood for server ${guildIdStr} to ${selectedMood}`);
|
||
|
||
if (!selectedMood) {
|
||
showNotification('Please select a mood', 'error');
|
||
return;
|
||
}
|
||
|
||
// Get the button and store original text before any changes
|
||
const button = moodSelect.nextElementSibling;
|
||
const originalText = button.textContent;
|
||
|
||
try {
|
||
// Show loading state
|
||
button.textContent = 'Changing...';
|
||
button.disabled = true;
|
||
|
||
console.log(`🎭 Making API call to /servers/${guildIdStr}/mood with mood: ${selectedMood}`);
|
||
const response = await apiCall(`/servers/${guildIdStr}/mood`, 'POST', { mood: selectedMood });
|
||
console.log(`🎭 API response:`, response);
|
||
|
||
if (response.status === 'ok') {
|
||
showNotification(`Server mood changed to ${selectedMood} ${MOOD_EMOJIS[selectedMood] || ''}`);
|
||
|
||
// Reset dropdown selection
|
||
moodSelect.value = '';
|
||
|
||
// Reload servers to show updated mood
|
||
loadServers();
|
||
} else {
|
||
showNotification(`Failed to change mood: ${response.message}`, 'error');
|
||
}
|
||
} catch (error) {
|
||
console.error(`🎭 Error setting mood:`, error);
|
||
showNotification(`Failed to change mood: ${error}`, 'error');
|
||
} finally {
|
||
// Restore button state
|
||
button.textContent = originalText;
|
||
button.disabled = false;
|
||
}
|
||
}
|
||
|
||
async function resetServerMood(guildId) {
|
||
console.log(`🎭 resetServerMood called with guildId: ${guildId} (type: ${typeof guildId})`);
|
||
|
||
// Ensure guildId is a string for consistency
|
||
const guildIdStr = String(guildId);
|
||
console.log(`🎭 Using guildId as string: ${guildIdStr}`);
|
||
|
||
const button = document.querySelector(`button[onclick="resetServerMood('${guildIdStr}')"]`);
|
||
const originalText = button ? button.textContent : 'Reset';
|
||
|
||
try {
|
||
// Show loading state
|
||
if (button) {
|
||
button.textContent = 'Resetting...';
|
||
button.disabled = true;
|
||
}
|
||
|
||
await apiCall(`/servers/${guildIdStr}/mood/reset`, 'POST');
|
||
showNotification(`Server mood reset to neutral`);
|
||
|
||
// Reload servers to show updated mood
|
||
loadServers();
|
||
} catch (error) {
|
||
showNotification(`Failed to reset mood: ${error}`, 'error');
|
||
} finally {
|
||
// Restore button state
|
||
if (button) {
|
||
button.textContent = originalText;
|
||
button.disabled = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
async function updateBedtimeRange(guildId) {
|
||
console.log(`⏰ updateBedtimeRange called with guildId: ${guildId}`);
|
||
|
||
// Ensure guildId is a string for consistency
|
||
const guildIdStr = String(guildId);
|
||
|
||
// Get the time values from the inputs
|
||
const startTimeInput = document.getElementById(`bedtime-start-${guildIdStr}`);
|
||
const endTimeInput = document.getElementById(`bedtime-end-${guildIdStr}`);
|
||
|
||
if (!startTimeInput || !endTimeInput) {
|
||
showNotification('Could not find bedtime time inputs', 'error');
|
||
return;
|
||
}
|
||
|
||
const startTime = startTimeInput.value; // Format: "HH:MM"
|
||
const endTime = endTimeInput.value; // Format: "HH:MM"
|
||
|
||
if (!startTime || !endTime) {
|
||
showNotification('Please enter both start and end times', 'error');
|
||
return;
|
||
}
|
||
|
||
// Parse the times
|
||
const [startHour, startMinute] = startTime.split(':').map(Number);
|
||
const [endHour, endMinute] = endTime.split(':').map(Number);
|
||
|
||
const button = document.querySelector(`button[onclick="updateBedtimeRange('${guildIdStr}')"]`);
|
||
const originalText = button ? button.textContent : 'Update Bedtime Range';
|
||
|
||
try {
|
||
// Show loading state
|
||
if (button) {
|
||
button.textContent = 'Updating...';
|
||
button.disabled = true;
|
||
}
|
||
|
||
// Send the update request
|
||
await apiCall(`/servers/${guildIdStr}/bedtime-range`, 'POST', {
|
||
bedtime_hour: startHour,
|
||
bedtime_minute: startMinute,
|
||
bedtime_hour_end: endHour,
|
||
bedtime_minute_end: endMinute
|
||
});
|
||
|
||
showNotification(`Bedtime range updated: ${startTime} - ${endTime}`);
|
||
|
||
// Reload servers to show updated configuration
|
||
loadServers();
|
||
|
||
} catch (error) {
|
||
console.error('Failed to update bedtime range:', error);
|
||
} finally {
|
||
// Restore button state
|
||
if (button) {
|
||
button.textContent = originalText;
|
||
button.disabled = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Mood Management
|
||
async function setMood() {
|
||
const mood = document.getElementById('mood').value;
|
||
try {
|
||
// 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) {
|
||
console.error('Failed to set mood:', error);
|
||
}
|
||
}
|
||
|
||
async function resetMood() {
|
||
try {
|
||
if (evilMode) {
|
||
await apiCall('/evil-mode/mood', 'POST', { mood: 'evil_neutral' });
|
||
showNotification('Evil mood reset to evil_neutral');
|
||
currentMood = 'evil_neutral';
|
||
document.getElementById('mood').value = 'evil_neutral';
|
||
} else {
|
||
await apiCall('/mood/reset', 'POST');
|
||
showNotification('Mood reset to neutral');
|
||
currentMood = 'neutral';
|
||
document.getElementById('mood').value = 'neutral';
|
||
}
|
||
} catch (error) {
|
||
console.error('Failed to reset mood:', error);
|
||
}
|
||
}
|
||
|
||
async function calmMiku() {
|
||
try {
|
||
if (evilMode) {
|
||
await apiCall('/evil-mode/mood', 'POST', { mood: 'evil_neutral' });
|
||
showNotification('Evil Miku has been calmed down');
|
||
currentMood = 'evil_neutral';
|
||
document.getElementById('mood').value = 'evil_neutral';
|
||
} else {
|
||
await apiCall('/mood/calm', 'POST');
|
||
showNotification('Miku has been calmed down');
|
||
}
|
||
} catch (error) {
|
||
console.error('Failed to calm Miku:', error);
|
||
}
|
||
}
|
||
|
||
// ===== Language Mode Functions =====
|
||
async function refreshLanguageStatus() {
|
||
try {
|
||
const result = await apiCall('/language');
|
||
document.getElementById('current-language-display').textContent =
|
||
result.language_mode === 'japanese' ? '日本語 (Japanese)' : 'English';
|
||
document.getElementById('status-language').textContent =
|
||
result.language_mode === 'japanese' ? '日本語 (Japanese)' : 'English';
|
||
document.getElementById('status-model').textContent = result.current_model;
|
||
|
||
console.log('Language status:', result);
|
||
} catch (error) {
|
||
console.error('Failed to get language status:', error);
|
||
showNotification('Failed to load language status', 'error');
|
||
}
|
||
}
|
||
|
||
async function toggleLanguageMode() {
|
||
try {
|
||
const result = await apiCall('/language/toggle', 'POST');
|
||
|
||
// Update UI
|
||
document.getElementById('current-language-display').textContent =
|
||
result.language_mode === 'japanese' ? '日本語 (Japanese)' : 'English';
|
||
document.getElementById('status-language').textContent =
|
||
result.language_mode === 'japanese' ? '日本語 (Japanese)' : 'English';
|
||
document.getElementById('status-model').textContent = result.model_now_using;
|
||
|
||
// Show notification
|
||
showNotification(result.message, 'success');
|
||
console.log('Language toggled:', result);
|
||
} catch (error) {
|
||
console.error('Failed to toggle language mode:', error);
|
||
showNotification('Failed to toggle language mode', 'error');
|
||
}
|
||
}
|