refactor: standardize raw fetch() calls to use apiCall() wrapper

Convert 47 raw fetch+response.json+error-handling patterns to use the
centralized apiCall() utility. The 11 remaining raw fetch() calls are
FormData uploads or SSE streaming that require direct fetch access.
This commit is contained in:
2026-03-01 00:14:08 +02:00
parent 820a226dd9
commit 5bdd907730

View File

@@ -2023,8 +2023,7 @@ async function apiCall(endpoint, method = 'GET', data = null) {
async function loadServers() { async function loadServers() {
try { try {
console.log('🎭 Loading servers...'); console.log('🎭 Loading servers...');
const response = await fetch('/servers'); const data = await apiCall('/servers');
const data = await response.json();
console.log('🎭 Servers response:', data); console.log('🎭 Servers response:', data);
if (data.servers) { if (data.servers) {
@@ -2124,10 +2123,9 @@ function displayServers() {
async function loadProfilePictureMetadata() { async function loadProfilePictureMetadata() {
try { try {
const response = await fetch('/profile-picture/metadata'); const result = await apiCall('/profile-picture/metadata');
const result = await response.json();
if (response.ok && result.status === 'ok' && result.metadata) { if (result.status === 'ok' && result.metadata) {
const metadataDiv = document.getElementById('pfp-metadata'); const metadataDiv = document.getElementById('pfp-metadata');
const metadataContent = document.getElementById('pfp-metadata-content'); const metadataContent = document.getElementById('pfp-metadata-content');
@@ -2182,14 +2180,12 @@ async function populateServerDropdowns() {
async function refreshFigurineSubscribers() { async function refreshFigurineSubscribers() {
try { try {
console.log('🔄 Figurines: Fetching subscribers...'); console.log('🔄 Figurines: Fetching subscribers...');
const res = await fetch('/figurines/subscribers'); const data = await apiCall('/figurines/subscribers');
const data = await res.json();
console.log('📋 Figurines: Received subscribers:', data); console.log('📋 Figurines: Received subscribers:', data);
displayFigurineSubscribers(data.subscribers || []); displayFigurineSubscribers(data.subscribers || []);
showNotification('Subscribers refreshed'); showNotification('Subscribers refreshed');
} catch (e) { } catch (e) {
console.error('❌ Figurines: Failed to fetch subscribers:', e); console.error('❌ Figurines: Failed to fetch subscribers:', e);
showNotification('Failed to load subscribers', 'error');
} }
} }
@@ -2238,8 +2234,7 @@ async function addFigurineSubscriber() {
async function removeFigurineSubscriber(uid) { async function removeFigurineSubscriber(uid) {
try { try {
console.log(`🗑️ Figurines: Removing subscriber ${uid}...`); console.log(`🗑️ Figurines: Removing subscriber ${uid}...`);
const res = await fetch(`/figurines/subscribers/${uid}`, { method: 'DELETE' }); const data = await apiCall(`/figurines/subscribers/${uid}`, 'DELETE');
const data = await res.json();
console.log('🗑️ Figurines: Remove subscriber response:', data); console.log('🗑️ Figurines: Remove subscriber response:', data);
if (data.status === 'ok') { if (data.status === 'ok') {
showNotification('Subscriber removed'); showNotification('Subscriber removed');
@@ -2249,7 +2244,6 @@ async function removeFigurineSubscriber(uid) {
} }
} catch (e) { } catch (e) {
console.error('❌ Figurines: Failed to remove subscriber:', e); console.error('❌ Figurines: Failed to remove subscriber:', e);
showNotification('Failed to remove subscriber', 'error');
} }
} }
@@ -2425,8 +2419,7 @@ async function repairConfig() {
async function populateMoodDropdowns() { async function populateMoodDropdowns() {
try { try {
console.log('🎭 Loading available moods...'); console.log('🎭 Loading available moods...');
const response = await fetch('/moods/available'); const data = await apiCall('/moods/available');
const data = await response.json();
console.log('🎭 Available moods response:', data); console.log('🎭 Available moods response:', data);
if (data.moods) { if (data.moods) {
@@ -2597,25 +2590,13 @@ async function updateBedtimeRange(guildId) {
} }
// Send the update request // Send the update request
const response = await fetch(`/servers/${guildIdStr}/bedtime-range`, { await apiCall(`/servers/${guildIdStr}/bedtime-range`, 'POST', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
bedtime_hour: startHour, bedtime_hour: startHour,
bedtime_minute: startMinute, bedtime_minute: startMinute,
bedtime_hour_end: endHour, bedtime_hour_end: endHour,
bedtime_minute_end: endMinute bedtime_minute_end: endMinute
})
}); });
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `HTTP ${response.status}`);
}
const result = await response.json();
showNotification(`Bedtime range updated: ${startTime} - ${endTime}`); showNotification(`Bedtime range updated: ${startTime} - ${endTime}`);
// Reload servers to show updated configuration // Reload servers to show updated configuration
@@ -2623,7 +2604,6 @@ async function updateBedtimeRange(guildId) {
} catch (error) { } catch (error) {
console.error('Failed to update bedtime range:', error); console.error('Failed to update bedtime range:', error);
showNotification(error.message || 'Failed to update bedtime range', 'error');
} finally { } finally {
// Restore button state // Restore button state
if (button) { if (button) {
@@ -2815,12 +2795,9 @@ let selectedGPU = 'nvidia'; // 'nvidia' or 'amd'
async function checkGPUStatus() { async function checkGPUStatus() {
try { try {
const response = await fetch('/gpu-status'); const data = await apiCall('/gpu-status');
if (response.ok) {
const data = await response.json();
selectedGPU = data.gpu || 'nvidia'; selectedGPU = data.gpu || 'nvidia';
updateGPUUI(); updateGPUUI();
}
} catch (error) { } catch (error) {
console.error('Failed to check GPU status:', error); console.error('Failed to check GPU status:', error);
} }
@@ -2868,12 +2845,9 @@ let bipolarMode = false;
async function checkBipolarModeStatus() { async function checkBipolarModeStatus() {
try { try {
const response = await fetch('/bipolar-mode'); const data = await apiCall('/bipolar-mode');
if (response.ok) {
const data = await response.json();
bipolarMode = data.bipolar_mode; bipolarMode = data.bipolar_mode;
updateBipolarModeUI(); updateBipolarModeUI();
}
} catch (error) { } catch (error) {
console.error('Failed to check bipolar mode status:', error); console.error('Failed to check bipolar mode status:', error);
} }
@@ -3106,10 +3080,7 @@ async function loadScoreboard() {
async function loadActiveArguments() { async function loadActiveArguments() {
try { try {
const response = await fetch('/bipolar-mode/arguments'); const data = await apiCall('/bipolar-mode/arguments');
if (!response.ok) return;
const data = await response.json();
const container = document.getElementById('active-arguments'); const container = document.getElementById('active-arguments');
const list = document.getElementById('active-arguments-list'); const list = document.getElementById('active-arguments-list');
@@ -3155,21 +3126,10 @@ async function triggerAutonomous(actionType) {
endpoint += `?guild_id=${selectedServer}`; endpoint += `?guild_id=${selectedServer}`;
} }
const response = await fetch(endpoint, { const result = await apiCall(endpoint, 'POST');
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const result = await response.json();
if (response.ok) {
showNotification(result.message || 'Action triggered successfully'); showNotification(result.message || 'Action triggered successfully');
} else {
throw new Error(result.message || 'Failed to trigger action');
}
} catch (error) { } catch (error) {
console.error('Failed to trigger autonomous action:', error); console.error('Failed to trigger autonomous action:', error);
showNotification(error.message || 'Failed to trigger action', 'error');
} }
} }
@@ -3215,23 +3175,12 @@ async function triggerEngageUser() {
endpoint += `?${params.toString()}`; endpoint += `?${params.toString()}`;
} }
const response = await fetch(endpoint, { const result = await apiCall(endpoint, 'POST');
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const result = await response.json();
if (response.ok) {
showNotification(result.message || 'Engagement triggered successfully'); showNotification(result.message || 'Engagement triggered successfully');
// Optionally collapse the submenu after successful trigger // Optionally collapse the submenu after successful trigger
// toggleEngageSubmenu(); // toggleEngageSubmenu();
} else {
throw new Error(result.message || 'Failed to trigger engagement');
}
} catch (error) { } catch (error) {
console.error('Failed to trigger user engagement:', error); console.error('Failed to trigger user engagement:', error);
showNotification(error.message || 'Failed to trigger engagement', 'error');
} }
} }
@@ -3287,21 +3236,10 @@ async function triggerShareTweet() {
endpoint += `?${params.toString()}`; endpoint += `?${params.toString()}`;
} }
const response = await fetch(endpoint, { const result = await apiCall(endpoint, 'POST');
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const result = await response.json();
if (response.ok) {
showNotification(result.message || 'Tweet share triggered successfully'); showNotification(result.message || 'Tweet share triggered successfully');
} else {
throw new Error(result.message || 'Failed to trigger tweet share');
}
} catch (error) { } catch (error) {
console.error('Failed to trigger tweet share:', error); console.error('Failed to trigger tweet share:', error);
showNotification(error.message || 'Failed to trigger tweet share', 'error');
} }
} }
@@ -3326,13 +3264,8 @@ async function changeProfilePicture() {
const url = params.toString() ? `${endpoint}?${params.toString()}` : endpoint; const url = params.toString() ? `${endpoint}?${params.toString()}` : endpoint;
const response = await fetch(url, { const result = await apiCall(url, 'POST');
method: 'POST'
});
const result = await response.json();
if (response.ok && result.status === 'ok') {
statusDiv.textContent = `${result.message}`; statusDiv.textContent = `${result.message}`;
statusDiv.style.color = 'green'; statusDiv.style.color = 'green';
@@ -3343,14 +3276,10 @@ async function changeProfilePicture() {
} }
showNotification('Profile picture changed successfully!'); showNotification('Profile picture changed successfully!');
} else {
throw new Error(result.message || 'Failed to change profile picture');
}
} catch (error) { } catch (error) {
console.error('Failed to change profile picture:', error); console.error('Failed to change profile picture:', error);
statusDiv.textContent = `❌ Error: ${error.message}`; statusDiv.textContent = `❌ Error: ${error.message}`;
statusDiv.style.color = 'red'; statusDiv.style.color = 'red';
showNotification(error.message || 'Failed to change profile picture', 'error');
} }
} }
@@ -3431,26 +3360,17 @@ async function restoreFallbackPfp() {
statusDiv.style.color = '#61dafb'; statusDiv.style.color = '#61dafb';
try { try {
const response = await fetch('/profile-picture/restore-fallback', { const result = await apiCall('/profile-picture/restore-fallback', 'POST');
method: 'POST'
});
const result = await response.json();
if (response.ok && result.status === 'ok') {
statusDiv.textContent = `${result.message}`; statusDiv.textContent = `${result.message}`;
statusDiv.style.color = 'green'; statusDiv.style.color = 'green';
metadataDiv.style.display = 'none'; metadataDiv.style.display = 'none';
showNotification('Original avatar restored successfully!'); showNotification('Original avatar restored successfully!');
} else {
throw new Error(result.message || 'Failed to restore fallback avatar');
}
} catch (error) { } catch (error) {
console.error('Failed to restore fallback avatar:', error); console.error('Failed to restore fallback avatar:', error);
statusDiv.textContent = `❌ Error: ${error.message}`; statusDiv.textContent = `❌ Error: ${error.message}`;
statusDiv.style.color = 'red'; statusDiv.style.color = 'red';
showNotification(error.message || 'Failed to restore fallback avatar', 'error');
} }
} }
@@ -3502,13 +3422,8 @@ async function resetRoleColor() {
statusDiv.style.color = '#61dafb'; statusDiv.style.color = '#61dafb';
try { try {
const response = await fetch('/role-color/reset-fallback', { const result = await apiCall('/role-color/reset-fallback', 'POST');
method: 'POST'
});
const result = await response.json();
if (response.ok && result.status === 'ok') {
statusDiv.textContent = `${result.message}`; statusDiv.textContent = `${result.message}`;
statusDiv.style.color = 'green'; statusDiv.style.color = 'green';
@@ -3516,14 +3431,10 @@ async function resetRoleColor() {
document.getElementById('role-color-hex').value = '#86cecb'; document.getElementById('role-color-hex').value = '#86cecb';
showNotification('Role color reset to fallback #86cecb'); showNotification('Role color reset to fallback #86cecb');
} else {
throw new Error(result.message || 'Failed to reset role color');
}
} catch (error) { } catch (error) {
console.error('Failed to reset role color:', error); console.error('Failed to reset role color:', error);
statusDiv.textContent = `❌ Error: ${error.message}`; statusDiv.textContent = `❌ Error: ${error.message}`;
statusDiv.style.color = 'red'; statusDiv.style.color = 'red';
showNotification(error.message || 'Failed to reset role color', 'error');
} }
} }
@@ -3588,7 +3499,7 @@ async function sendCustomPrompt() {
} }
try { try {
let endpoint, requestData, response; let endpoint;
if (targetType === 'dm') { if (targetType === 'dm') {
// DM target // DM target
@@ -3597,16 +3508,7 @@ async function sendCustomPrompt() {
showNotification('Please enter a user ID for DM', 'error'); showNotification('Please enter a user ID for DM', 'error');
return; return;
} }
endpoint = `/dm/${userId}/custom`; endpoint = `/dm/${userId}/custom`;
requestData = { prompt: prompt };
response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData)
});
} else { } else {
// Server target // Server target
const selectedServer = document.getElementById('custom-prompt-server-select').value; const selectedServer = document.getElementById('custom-prompt-server-select').value;
@@ -3617,19 +3519,10 @@ async function sendCustomPrompt() {
// Don't use parseInt() - Discord IDs are too large for JS integers // Don't use parseInt() - Discord IDs are too large for JS integers
endpoint += `?guild_id=${selectedServer}`; endpoint += `?guild_id=${selectedServer}`;
} }
requestData = { prompt: prompt };
response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestData)
});
} }
const result = await response.json(); const result = await apiCall(endpoint, 'POST', { prompt: prompt });
if (response.ok) {
showNotification(result.message || 'Custom prompt sent successfully'); showNotification(result.message || 'Custom prompt sent successfully');
document.getElementById('customPrompt').value = ''; document.getElementById('customPrompt').value = '';
document.getElementById('customPromptAttachment').value = ''; // Clear file input document.getElementById('customPromptAttachment').value = ''; // Clear file input
@@ -3638,12 +3531,8 @@ async function sendCustomPrompt() {
} }
document.getElementById('customStatus').textContent = '✅ Custom prompt sent successfully!'; document.getElementById('customStatus').textContent = '✅ Custom prompt sent successfully!';
document.getElementById('customStatus').style.color = 'green'; document.getElementById('customStatus').style.color = 'green';
} else {
throw new Error(result.message || 'Failed to send custom prompt');
}
} catch (error) { } catch (error) {
console.error('Failed to send custom prompt:', error); console.error('Failed to send custom prompt:', error);
showNotification(error.message || 'Failed to send custom prompt', 'error');
document.getElementById('customStatus').textContent = '❌ Failed to send custom prompt'; document.getElementById('customStatus').textContent = '❌ Failed to send custom prompt';
document.getElementById('customStatus').style.color = 'red'; document.getElementById('customStatus').style.color = 'red';
} }
@@ -3689,21 +3578,10 @@ async function sendBedtime() {
console.log('🛏️ Final endpoint:', endpoint); console.log('🛏️ Final endpoint:', endpoint);
const response = await fetch(endpoint, { const result = await apiCall(endpoint, 'POST');
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
const result = await response.json();
if (response.ok) {
showNotification(result.message || 'Bedtime reminder sent successfully'); showNotification(result.message || 'Bedtime reminder sent successfully');
} else {
throw new Error(result.message || 'Failed to send bedtime reminder');
}
} catch (error) { } catch (error) {
console.error('Failed to send bedtime reminder:', error); console.error('Failed to send bedtime reminder:', error);
showNotification(error.message || 'Failed to send bedtime reminder', 'error');
} }
} }
@@ -3892,10 +3770,8 @@ async function checkImageSystemStatus() {
const statusDisplay = document.getElementById('image-status-display'); const statusDisplay = document.getElementById('image-status-display');
statusDisplay.innerHTML = '🔄 Checking system status...'; statusDisplay.innerHTML = '🔄 Checking system status...';
const response = await fetch('/image/status'); const result = await apiCall('/image/status');
const result = await response.json();
if (response.ok) {
const workflowStatus = result.workflow_template_exists ? '✅ Found' : '❌ Missing'; const workflowStatus = result.workflow_template_exists ? '✅ Found' : '❌ Missing';
const comfyuiStatus = result.comfyui_running ? '✅ Running' : '❌ Not running'; const comfyuiStatus = result.comfyui_running ? '✅ Running' : '❌ Not running';
@@ -3908,9 +3784,6 @@ ${result.comfyui_running ? `• Detected ComfyUI URL: ${result.comfyui_url}` : '
<strong>Overall Status:</strong> ${result.ready ? '✅ Ready for image generation' : '⚠️ Setup required'} <strong>Overall Status:</strong> ${result.ready ? '✅ Ready for image generation' : '⚠️ Setup required'}
${!result.workflow_template_exists ? '⚠️ Place Miku_BasicWorkflow.json in bot directory\n' : ''}${!result.comfyui_running ? '⚠️ Start ComfyUI server on localhost:8188 (bot will auto-detect correct URL)\n' : ''}`; ${!result.workflow_template_exists ? '⚠️ Place Miku_BasicWorkflow.json in bot directory\n' : ''}${!result.comfyui_running ? '⚠️ Start ComfyUI server on localhost:8188 (bot will auto-detect correct URL)\n' : ''}`;
} else {
statusDisplay.innerHTML = `❌ Error checking status: ${result.message}`;
}
} catch (error) { } catch (error) {
console.error('Failed to check image system status:', error); console.error('Failed to check image system status:', error);
document.getElementById('image-status-display').innerHTML = `❌ Error: ${error.message}`; document.getElementById('image-status-display').innerHTML = `❌ Error: ${error.message}`;
@@ -3931,15 +3804,8 @@ async function testImageDetection() {
resultsDiv.innerHTML = '🔍 Testing detection...'; resultsDiv.innerHTML = '🔍 Testing detection...';
resultsDiv.style.color = '#4CAF50'; resultsDiv.style.color = '#4CAF50';
const response = await fetch('/image/test-detection', { const result = await apiCall('/image/test-detection', 'POST', { message: message });
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: message })
});
const result = await response.json();
if (response.ok) {
const detectionIcon = result.is_image_request ? '✅' : '❌'; const detectionIcon = result.is_image_request ? '✅' : '❌';
const detectionText = result.is_image_request ? 'WILL trigger image generation' : 'will NOT trigger image generation'; const detectionText = result.is_image_request ? 'WILL trigger image generation' : 'will NOT trigger image generation';
@@ -3949,10 +3815,6 @@ ${result.is_image_request ? `<br><strong>Extracted Prompt:</strong> "${result.ex
<br><strong>Original Message:</strong> "${result.original_message}"`; <br><strong>Original Message:</strong> "${result.original_message}"`;
resultsDiv.style.color = result.is_image_request ? '#4CAF50' : '#ff9800'; resultsDiv.style.color = result.is_image_request ? '#4CAF50' : '#ff9800';
} else {
resultsDiv.innerHTML = `❌ Detection test failed: ${result.message}`;
resultsDiv.style.color = 'red';
}
} catch (error) { } catch (error) {
console.error('Failed to test image detection:', error); console.error('Failed to test image detection:', error);
resultsDiv.innerHTML = `❌ Error: ${error.message}`; resultsDiv.innerHTML = `❌ Error: ${error.message}`;
@@ -3978,15 +3840,8 @@ async function generateManualImage() {
statusDiv.innerHTML = '🎨 Generating image... This may take a few minutes.'; statusDiv.innerHTML = '🎨 Generating image... This may take a few minutes.';
statusDiv.style.color = '#4CAF50'; statusDiv.style.color = '#4CAF50';
const response = await fetch('/image/generate', { const result = await apiCall('/image/generate', 'POST', { prompt: prompt });
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: prompt })
});
const result = await response.json();
if (response.ok && result.status === 'ok') {
statusDiv.innerHTML = `✅ Image generated successfully!`; statusDiv.innerHTML = `✅ Image generated successfully!`;
statusDiv.style.color = '#4CAF50'; statusDiv.style.color = '#4CAF50';
@@ -4030,10 +3885,6 @@ async function generateManualImage() {
} }
document.getElementById('manual-image-prompt').value = ''; document.getElementById('manual-image-prompt').value = '';
} else {
statusDiv.innerHTML = `❌ Failed to generate image: ${result.message || 'Unknown error'}`;
statusDiv.style.color = 'red';
}
} catch (error) { } catch (error) {
console.error('Failed to generate image:', error); console.error('Failed to generate image:', error);
statusDiv.innerHTML = `❌ Error: ${error.message}`; statusDiv.innerHTML = `❌ Error: ${error.message}`;
@@ -4175,17 +4026,10 @@ function toggleCustomPrompt() {
// DM Logs Functions // DM Logs Functions
async function loadDMUsers() { async function loadDMUsers() {
try { try {
const response = await fetch('/dms/users'); const result = await apiCall('/dms/users');
const result = await response.json();
if (response.ok) {
displayDMUsers(result.users); displayDMUsers(result.users);
} else {
throw new Error(result.message || 'Failed to load DM users');
}
} catch (error) { } catch (error) {
console.error('Failed to load DM users:', error); console.error('Failed to load DM users:', error);
showNotification(error.message || 'Failed to load DM users', 'error');
} }
} }
@@ -4306,13 +4150,11 @@ function toggleCustomPrompt() {
console.log(`🔍 Original userId: ${userId} (type: ${typeof userId})`); console.log(`🔍 Original userId: ${userId} (type: ${typeof userId})`);
console.log(`🔍 userIdStr: ${userIdStr} (type: ${typeof userIdStr})`); console.log(`🔍 userIdStr: ${userIdStr} (type: ${typeof userIdStr})`);
const response = await fetch(`/dms/users/${userIdStr}/conversations?limit=100`); const result = await apiCall(`/dms/users/${userIdStr}/conversations?limit=100`);
const result = await response.json();
console.log('📡 API Response:', result); console.log('📡 API Response:', result);
console.log('📡 API URL called:', `/dms/users/${userIdStr}/conversations?limit=100`); console.log('📡 API URL called:', `/dms/users/${userIdStr}/conversations?limit=100`);
if (response.ok) {
if (result.conversations && result.conversations.length > 0) { if (result.conversations && result.conversations.length > 0) {
console.log(`✅ Found ${result.conversations.length} conversations`); console.log(`✅ Found ${result.conversations.length} conversations`);
displayUserConversations(userIdStr, result.conversations); displayUserConversations(userIdStr, result.conversations);
@@ -4322,12 +4164,8 @@ function toggleCustomPrompt() {
// Go back to user list // Go back to user list
loadDMUsers(); loadDMUsers();
} }
} else {
throw new Error(result.message || 'Failed to load conversations');
}
} catch (error) { } catch (error) {
console.error('Failed to load user conversations:', error); console.error('Failed to load user conversations:', error);
showNotification(error.message || 'Failed to load conversations', 'error');
} }
} }
@@ -4419,18 +4257,11 @@ function toggleCustomPrompt() {
try { try {
// Ensure userId is always treated as a string // Ensure userId is always treated as a string
const userIdStr = String(userId); const userIdStr = String(userId);
const response = await fetch(`/dms/users/${userIdStr}/export?format=txt`); await apiCall(`/dms/users/${userIdStr}/export?format=txt`);
const result = await response.json();
if (response.ok) {
showNotification(`DM export completed for user ${userIdStr}`); showNotification(`DM export completed for user ${userIdStr}`);
// You could trigger a download here if the file is accessible // You could trigger a download here if the file is accessible
} else {
throw new Error(result.message || 'Failed to export DMs');
}
} catch (error) { } catch (error) {
console.error('Failed to export user DMs:', error); console.error('Failed to export user DMs:', error);
showNotification(error.message || 'Failed to export DMs', 'error');
} }
} }
@@ -4443,18 +4274,11 @@ function toggleCustomPrompt() {
} }
try { try {
const response = await fetch(`/dms/users/${userIdStr}`, { method: 'DELETE' }); await apiCall(`/dms/users/${userIdStr}`, 'DELETE');
const result = await response.json();
if (response.ok) {
showNotification(`Deleted DM logs for user ${userIdStr}`); showNotification(`Deleted DM logs for user ${userIdStr}`);
loadDMUsers(); // Refresh the list loadDMUsers(); // Refresh the list
} else {
throw new Error(result.message || 'Failed to delete DM logs');
}
} catch (error) { } catch (error) {
console.error('Failed to delete user DMs:', error); console.error('Failed to delete user DMs:', error);
showNotification(error.message || 'Failed to delete DM logs', 'error');
} }
} }
@@ -4468,18 +4292,11 @@ function toggleCustomPrompt() {
} }
try { try {
const response = await fetch(`/dms/users/${userIdStr}/block`, { method: 'POST' }); await apiCall(`/dms/users/${userIdStr}/block`, 'POST');
const result = await response.json();
if (response.ok) {
showNotification(`${username} has been blocked from sending DMs`); showNotification(`${username} has been blocked from sending DMs`);
loadDMUsers(); // Refresh the list loadDMUsers(); // Refresh the list
} else {
throw new Error(result.message || 'Failed to block user');
}
} catch (error) { } catch (error) {
console.error('Failed to block user:', error); console.error('Failed to block user:', error);
showNotification(error.message || 'Failed to block user', 'error');
} }
} }
@@ -4487,18 +4304,11 @@ function toggleCustomPrompt() {
const userIdStr = String(userId); const userIdStr = String(userId);
try { try {
const response = await fetch(`/dms/users/${userIdStr}/unblock`, { method: 'POST' }); await apiCall(`/dms/users/${userIdStr}/unblock`, 'POST');
const result = await response.json();
if (response.ok) {
showNotification(`${username} has been unblocked`); showNotification(`${username} has been unblocked`);
loadBlockedUsers(); // Refresh blocked users list loadBlockedUsers(); // Refresh blocked users list
} else {
throw new Error(result.message || 'Failed to unblock user');
}
} catch (error) { } catch (error) {
console.error('Failed to unblock user:', error); console.error('Failed to unblock user:', error);
showNotification(error.message || 'Failed to unblock user', 'error');
} }
} }
@@ -4510,20 +4320,13 @@ function toggleCustomPrompt() {
} }
try { try {
const response = await fetch(`/dms/users/${userIdStr}/conversations/delete-all`, { method: 'POST' }); await apiCall(`/dms/users/${userIdStr}/conversations/delete-all`, 'POST');
const result = await response.json();
if (response.ok) {
showNotification(`Bulk deletion queued for ${username} (deleting all Miku messages from Discord and logs)`); showNotification(`Bulk deletion queued for ${username} (deleting all Miku messages from Discord and logs)`);
setTimeout(() => { setTimeout(() => {
loadDMUsers(); // Refresh after a delay to allow deletion to process loadDMUsers(); // Refresh after a delay to allow deletion to process
}, 2000); }, 2000);
} else {
throw new Error(result.message || 'Failed to delete conversations');
}
} catch (error) { } catch (error) {
console.error('Failed to delete conversations:', error); console.error('Failed to delete conversations:', error);
showNotification(error.message || 'Failed to delete conversations', 'error');
} }
} }
@@ -4541,18 +4344,11 @@ function toggleCustomPrompt() {
} }
try { try {
const response = await fetch(`/dms/users/${userIdStr}/delete-completely`, { method: 'POST' }); await apiCall(`/dms/users/${userIdStr}/delete-completely`, 'POST');
const result = await response.json();
if (response.ok) {
showNotification(`${username} has been completely deleted from the system`); showNotification(`${username} has been completely deleted from the system`);
loadDMUsers(); // Refresh the list loadDMUsers(); // Refresh the list
} else {
throw new Error(result.message || 'Failed to delete user completely');
}
} catch (error) { } catch (error) {
console.error('Failed to delete user completely:', error); console.error('Failed to delete user completely:', error);
showNotification(error.message || 'Failed to delete user completely', 'error');
} }
} }
@@ -4564,20 +4360,13 @@ function toggleCustomPrompt() {
} }
try { try {
const response = await fetch(`/dms/users/${userIdStr}/conversations/${conversationId}/delete`, { method: 'POST' }); await apiCall(`/dms/users/${userIdStr}/conversations/${conversationId}/delete`, 'POST');
const result = await response.json();
if (response.ok) {
showNotification('Miku message deletion queued (deleting from both Discord and logs)'); showNotification('Miku message deletion queued (deleting from both Discord and logs)');
setTimeout(() => { setTimeout(() => {
viewUserConversations(userId); // Refresh after a short delay to allow deletion to process viewUserConversations(userId); // Refresh after a short delay to allow deletion to process
}, 1000); }, 1000);
} else {
throw new Error(result.message || 'Failed to delete message');
}
} catch (error) { } catch (error) {
console.error('Failed to delete conversation:', error); console.error('Failed to delete conversation:', error);
showNotification(error.message || 'Failed to delete message', 'error');
} }
} }
@@ -4591,21 +4380,15 @@ function toggleCustomPrompt() {
try { try {
showNotification(`Analyzing ${username}'s interactions...`, 'info'); showNotification(`Analyzing ${username}'s interactions...`, 'info');
const response = await fetch(`/dms/users/${userIdStr}/analyze`, { method: 'POST' }); const result = await apiCall(`/dms/users/${userIdStr}/analyze`, 'POST');
const result = await response.json();
if (response.ok) {
if (result.reported) { if (result.reported) {
showNotification(`✅ Analysis complete! Report sent to bot owner for ${username}`); showNotification(`✅ Analysis complete! Report sent to bot owner for ${username}`);
} else { } else {
showNotification(`📊 Analysis complete for ${username} (not enough messages or already reported today)`); showNotification(`📊 Analysis complete for ${username} (not enough messages or already reported today)`);
} }
} else {
throw new Error(result.message || 'Failed to analyze user');
}
} catch (error) { } catch (error) {
console.error('Failed to analyze user:', error); console.error('Failed to analyze user:', error);
showNotification(error.message || 'Failed to analyze user', 'error');
} }
} }
@@ -4617,17 +4400,10 @@ function toggleCustomPrompt() {
try { try {
showNotification('Starting DM interaction analysis...', 'info'); showNotification('Starting DM interaction analysis...', 'info');
const response = await fetch('/dms/analysis/run', { method: 'POST' }); await apiCall('/dms/analysis/run', 'POST');
const result = await response.json();
if (response.ok) {
showNotification('✅ DM analysis completed! Check bot owner\'s DMs for any reports.'); showNotification('✅ DM analysis completed! Check bot owner\'s DMs for any reports.');
} else {
throw new Error(result.message || 'Failed to run analysis');
}
} catch (error) { } catch (error) {
console.error('Failed to run DM analysis:', error); console.error('Failed to run DM analysis:', error);
showNotification(error.message || 'Failed to run DM analysis', 'error');
} }
} }
@@ -4635,17 +4411,10 @@ function toggleCustomPrompt() {
try { try {
showNotification('Loading analysis reports...', 'info'); showNotification('Loading analysis reports...', 'info');
const response = await fetch('/dms/analysis/reports?limit=50'); const result = await apiCall('/dms/analysis/reports?limit=50');
const result = await response.json();
if (response.ok) {
displayAnalysisReports(result.reports); displayAnalysisReports(result.reports);
} else {
throw new Error(result.message || 'Failed to load reports');
}
} catch (error) { } catch (error) {
console.error('Failed to load reports:', error); console.error('Failed to load reports:', error);
showNotification(error.message || 'Failed to load reports', 'error');
} }
} }
@@ -4736,20 +4505,13 @@ function toggleCustomPrompt() {
async function loadBlockedUsers() { async function loadBlockedUsers() {
try { try {
const response = await fetch('/dms/blocked-users'); const result = await apiCall('/dms/blocked-users');
const result = await response.json();
if (response.ok) {
// Hide DM users list and show blocked users section // Hide DM users list and show blocked users section
document.getElementById('dm-users-list').style.display = 'none'; document.getElementById('dm-users-list').style.display = 'none';
document.getElementById('blocked-users-section').style.display = 'block'; document.getElementById('blocked-users-section').style.display = 'block';
displayBlockedUsers(result.blocked_users); displayBlockedUsers(result.blocked_users);
} else {
throw new Error(result.message || 'Failed to load blocked users');
}
} catch (error) { } catch (error) {
console.error('Failed to load blocked users:', error); console.error('Failed to load blocked users:', error);
showNotification(error.message || 'Failed to load blocked users', 'error');
} }
} }
@@ -4790,12 +4552,10 @@ function toggleCustomPrompt() {
async function exportAllDMs() { async function exportAllDMs() {
try { try {
const response = await fetch('/dms/users'); const result = await apiCall('/dms/users');
const result = await response.json();
if (response.ok && result.users) {
let exportCount = 0; let exportCount = 0;
for (const user of result.users) { for (const user of (result.users || [])) {
try { try {
await exportUserDMs(user.user_id); await exportUserDMs(user.user_id);
exportCount++; exportCount++;
@@ -4804,12 +4564,8 @@ function toggleCustomPrompt() {
} }
} }
showNotification(`Exported DMs for ${exportCount} users`); showNotification(`Exported DMs for ${exportCount} users`);
} else {
throw new Error(result.message || 'Failed to load DM users for export');
}
} catch (error) { } catch (error) {
console.error('Failed to export all DMs:', error); console.error('Failed to export all DMs:', error);
showNotification(error.message || 'Failed to export all DMs', 'error');
} }
} }
@@ -4824,8 +4580,7 @@ async function loadAutonomousStats() {
} }
try { try {
const response = await fetch('/autonomous/stats'); const data = await apiCall('/autonomous/stats');
const data = await response.json();
if (!data.servers || !data.servers[selectedGuildId]) { if (!data.servers || !data.servers[selectedGuildId]) {
document.getElementById('autonomous-stats-display').innerHTML = '<p style="color: #ff5555;">Server not found or not initialized.</p>'; document.getElementById('autonomous-stats-display').innerHTML = '<p style="color: #ff5555;">Server not found or not initialized.</p>';
@@ -4836,7 +4591,6 @@ async function loadAutonomousStats() {
displayAutonomousStats(serverData); displayAutonomousStats(serverData);
} catch (error) { } catch (error) {
console.error('Failed to load autonomous stats:', error); console.error('Failed to load autonomous stats:', error);
showNotification('Failed to load autonomous stats', 'error');
} }
} }
@@ -5040,8 +4794,7 @@ function toggleChatImageUpload() {
// Load voice debug mode setting from server // Load voice debug mode setting from server
async function loadVoiceDebugMode() { async function loadVoiceDebugMode() {
try { try {
const response = await fetch('/voice/debug-mode'); const data = await apiCall('/voice/debug-mode');
const data = await response.json();
const checkbox = document.getElementById('voice-debug-mode'); const checkbox = document.getElementById('voice-debug-mode');
if (checkbox && data.debug_mode !== undefined) { if (checkbox && data.debug_mode !== undefined) {
checkbox.checked = data.debug_mode; checkbox.checked = data.debug_mode;
@@ -5526,8 +5279,7 @@ function updateVoiceCallHistoryDisplay() {
async function refreshMemoryStats() { async function refreshMemoryStats() {
try { try {
// Fetch Cat status // Fetch Cat status
const statusRes = await fetch('/memory/status'); const statusData = await apiCall('/memory/status');
const statusData = await statusRes.json();
const indicator = document.getElementById('cat-status-indicator'); const indicator = document.getElementById('cat-status-indicator');
const toggleBtn = document.getElementById('cat-toggle-btn'); const toggleBtn = document.getElementById('cat-toggle-btn');
@@ -5547,8 +5299,7 @@ async function refreshMemoryStats() {
toggleBtn.style.borderColor = statusData.enabled ? '#4a9a4a' : '#9a4a4a'; toggleBtn.style.borderColor = statusData.enabled ? '#4a9a4a' : '#9a4a4a';
// Fetch memory stats // Fetch memory stats
const statsRes = await fetch('/memory/stats'); const statsData = await apiCall('/memory/stats');
const statsData = await statsRes.json();
if (statsData.success && statsData.collections) { if (statsData.success && statsData.collections) {
const collections = {}; const collections = {};
@@ -5570,8 +5321,7 @@ async function refreshMemoryStats() {
async function toggleCatIntegration() { async function toggleCatIntegration() {
try { try {
const statusRes = await fetch('/memory/status'); const statusData = await apiCall('/memory/status');
const statusData = await statusRes.json();
const newState = !statusData.enabled; const newState = !statusData.enabled;
const formData = new FormData(); const formData = new FormData();
@@ -5599,8 +5349,7 @@ async function triggerConsolidation() {
resultDiv.style.display = 'none'; resultDiv.style.display = 'none';
try { try {
const res = await fetch('/memory/consolidate', { method: 'POST' }); const data = await apiCall('/memory/consolidate', 'POST');
const data = await res.json();
if (data.success) { if (data.success) {
status.textContent = '✅ Consolidation complete!'; status.textContent = '✅ Consolidation complete!';
@@ -5627,8 +5376,7 @@ async function loadFacts() {
listDiv.innerHTML = '<div style="text-align: center; color: #888; padding: 1rem;">Loading facts...</div>'; listDiv.innerHTML = '<div style="text-align: center; color: #888; padding: 1rem;">Loading facts...</div>';
try { try {
const res = await fetch('/memory/facts'); const data = await apiCall('/memory/facts');
const data = await res.json();
if (!data.success || data.count === 0) { if (!data.success || data.count === 0) {
listDiv.innerHTML = '<div style="text-align: center; color: #666; padding: 2rem;">No declarative facts stored yet.</div>'; listDiv.innerHTML = '<div style="text-align: center; color: #666; padding: 2rem;">No declarative facts stored yet.</div>';
@@ -5670,8 +5418,7 @@ async function loadEpisodicMemories() {
listDiv.innerHTML = '<div style="text-align: center; color: #888; padding: 1rem;">Loading memories...</div>'; listDiv.innerHTML = '<div style="text-align: center; color: #888; padding: 1rem;">Loading memories...</div>';
try { try {
const res = await fetch('/memory/episodic'); const data = await apiCall('/memory/episodic');
const data = await res.json();
if (!data.success || data.count === 0) { if (!data.success || data.count === 0) {
listDiv.innerHTML = '<div style="text-align: center; color: #666; padding: 2rem;">No episodic memories stored yet.</div>'; listDiv.innerHTML = '<div style="text-align: center; color: #666; padding: 2rem;">No episodic memories stored yet.</div>';
@@ -5712,8 +5459,7 @@ async function deleteMemoryPoint(collection, pointId, btnElement) {
if (!confirm(`Delete this ${collection} memory point?`)) return; if (!confirm(`Delete this ${collection} memory point?`)) return;
try { try {
const res = await fetch(`/memory/point/${collection}/${pointId}`, { method: 'DELETE' }); const data = await apiCall(`/memory/point/${collection}/${pointId}`, 'DELETE');
const data = await res.json();
if (data.success) { if (data.success) {
// Remove the row from the UI // Remove the row from the UI
@@ -5725,7 +5471,7 @@ async function deleteMemoryPoint(collection, pointId, btnElement) {
showNotification('Failed to delete: ' + (data.error || 'Unknown error'), 'error'); showNotification('Failed to delete: ' + (data.error || 'Unknown error'), 'error');
} }
} catch (err) { } catch (err) {
showNotification('Error: ' + err.message, 'error'); console.error('Failed to delete memory point:', err);
} }
} }
@@ -5780,12 +5526,7 @@ async function executeDeleteAllMemories() {
btn.textContent = '⏳ Deleting...'; btn.textContent = '⏳ Deleting...';
try { try {
const res = await fetch('/memory/delete', { const data = await apiCall('/memory/delete', 'POST', { confirmation: input });
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ confirmation: input })
});
const data = await res.json();
if (data.success) { if (data.success) {
showNotification('All memories have been permanently deleted', 'success'); showNotification('All memories have been permanently deleted', 'success');
@@ -5795,7 +5536,7 @@ async function executeDeleteAllMemories() {
showNotification('Deletion failed: ' + (data.error || 'Unknown error'), 'error'); showNotification('Deletion failed: ' + (data.error || 'Unknown error'), 'error');
} }
} catch (err) { } catch (err) {
showNotification('Error: ' + err.message, 'error'); console.error('Failed to delete all memories:', err);
} finally { } finally {
btn.disabled = false; btn.disabled = false;
btn.textContent = '🗑️ Permanently Delete All Memories'; btn.textContent = '🗑️ Permanently Delete All Memories';
@@ -5864,17 +5605,11 @@ async function saveMemoryEdit() {
saveBtn.textContent = 'Saving...'; saveBtn.textContent = 'Saving...';
try { try {
const res = await fetch(`/memory/point/${collection}/${pointId}`, { const data = await apiCall(`/memory/point/${collection}/${pointId}`, 'PUT', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: content, content: content,
metadata: { source: source || 'manual_edit' } metadata: { source: source || 'manual_edit' }
})
}); });
const data = await res.json();
if (data.success) { if (data.success) {
showNotification('Memory updated successfully', 'success'); showNotification('Memory updated successfully', 'success');
closeEditMemoryModal(); closeEditMemoryModal();
@@ -5888,7 +5623,7 @@ async function saveMemoryEdit() {
showNotification('Failed to update: ' + (data.error || 'Unknown error'), 'error'); showNotification('Failed to update: ' + (data.error || 'Unknown error'), 'error');
} }
} catch (err) { } catch (err) {
showNotification('Error: ' + err.message, 'error'); console.error('Failed to save memory edit:', err);
} finally { } finally {
saveBtn.disabled = false; saveBtn.disabled = false;
saveBtn.textContent = 'Save Changes'; saveBtn.textContent = 'Save Changes';
@@ -5941,20 +5676,14 @@ async function saveNewMemory() {
createBtn.textContent = 'Creating...'; createBtn.textContent = 'Creating...';
try { try {
const res = await fetch('/memory/create', { const data = await apiCall('/memory/create', 'POST', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
collection: collection, collection: collection,
content: content, content: content,
user_id: userId || null, user_id: userId || null,
source: source || 'manual', source: source || 'manual',
metadata: {} metadata: {}
})
}); });
const data = await res.json();
if (data.success) { if (data.success) {
showNotification(`${collection === 'declarative' ? 'Fact' : 'Memory'} created successfully`, 'success'); showNotification(`${collection === 'declarative' ? 'Fact' : 'Memory'} created successfully`, 'success');
closeCreateMemoryModal(); closeCreateMemoryModal();
@@ -5969,7 +5698,7 @@ async function saveNewMemory() {
showNotification('Failed to create: ' + (data.error || 'Unknown error'), 'error'); showNotification('Failed to create: ' + (data.error || 'Unknown error'), 'error');
} }
} catch (err) { } catch (err) {
showNotification('Error: ' + err.message, 'error'); console.error('Failed to save new memory:', err);
} finally { } finally {
createBtn.disabled = false; createBtn.disabled = false;
createBtn.textContent = 'Create Memory'; createBtn.textContent = 'Create Memory';