From 5bdd907730b58ae8d7895e707eb45c82152e23da Mon Sep 17 00:00:00 2001 From: koko210Serve Date: Sun, 1 Mar 2026 00:14:08 +0200 Subject: [PATCH] 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. --- bot/static/index.html | 579 +++++++++++------------------------------- 1 file changed, 154 insertions(+), 425 deletions(-) diff --git a/bot/static/index.html b/bot/static/index.html index 0dd15e1..a49eae6 100644 --- a/bot/static/index.html +++ b/bot/static/index.html @@ -2023,8 +2023,7 @@ async function apiCall(endpoint, method = 'GET', data = null) { async function loadServers() { try { console.log('🎭 Loading servers...'); - const response = await fetch('/servers'); - const data = await response.json(); + const data = await apiCall('/servers'); console.log('🎭 Servers response:', data); if (data.servers) { @@ -2124,10 +2123,9 @@ function displayServers() { async function loadProfilePictureMetadata() { try { - const response = await fetch('/profile-picture/metadata'); - const result = await response.json(); + const result = await apiCall('/profile-picture/metadata'); - if (response.ok && result.status === 'ok' && result.metadata) { + if (result.status === 'ok' && result.metadata) { const metadataDiv = document.getElementById('pfp-metadata'); const metadataContent = document.getElementById('pfp-metadata-content'); @@ -2182,14 +2180,12 @@ async function populateServerDropdowns() { async function refreshFigurineSubscribers() { try { console.log('🔄 Figurines: Fetching subscribers...'); - const res = await fetch('/figurines/subscribers'); - const data = await res.json(); + 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); - showNotification('Failed to load subscribers', 'error'); } } @@ -2238,8 +2234,7 @@ async function addFigurineSubscriber() { async function removeFigurineSubscriber(uid) { try { console.log(`🗑️ Figurines: Removing subscriber ${uid}...`); - const res = await fetch(`/figurines/subscribers/${uid}`, { method: 'DELETE' }); - const data = await res.json(); + const data = await apiCall(`/figurines/subscribers/${uid}`, 'DELETE'); console.log('🗑️ Figurines: Remove subscriber response:', data); if (data.status === 'ok') { showNotification('Subscriber removed'); @@ -2249,7 +2244,6 @@ async function removeFigurineSubscriber(uid) { } } catch (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() { try { console.log('🎭 Loading available moods...'); - const response = await fetch('/moods/available'); - const data = await response.json(); + const data = await apiCall('/moods/available'); console.log('🎭 Available moods response:', data); if (data.moods) { @@ -2597,25 +2590,13 @@ async function updateBedtimeRange(guildId) { } // Send the update request - const response = await fetch(`/servers/${guildIdStr}/bedtime-range`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - bedtime_hour: startHour, - bedtime_minute: startMinute, - bedtime_hour_end: endHour, - bedtime_minute_end: endMinute - }) + await apiCall(`/servers/${guildIdStr}/bedtime-range`, 'POST', { + bedtime_hour: startHour, + bedtime_minute: startMinute, + bedtime_hour_end: endHour, + 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}`); // Reload servers to show updated configuration @@ -2623,7 +2604,6 @@ async function updateBedtimeRange(guildId) { } catch (error) { console.error('Failed to update bedtime range:', error); - showNotification(error.message || 'Failed to update bedtime range', 'error'); } finally { // Restore button state if (button) { @@ -2815,12 +2795,9 @@ let selectedGPU = 'nvidia'; // 'nvidia' or 'amd' async function checkGPUStatus() { try { - const response = await fetch('/gpu-status'); - if (response.ok) { - const data = await response.json(); - selectedGPU = data.gpu || 'nvidia'; - updateGPUUI(); - } + const data = await apiCall('/gpu-status'); + selectedGPU = data.gpu || 'nvidia'; + updateGPUUI(); } catch (error) { console.error('Failed to check GPU status:', error); } @@ -2868,12 +2845,9 @@ let bipolarMode = false; async function checkBipolarModeStatus() { try { - const response = await fetch('/bipolar-mode'); - if (response.ok) { - const data = await response.json(); - bipolarMode = data.bipolar_mode; - updateBipolarModeUI(); - } + const data = await apiCall('/bipolar-mode'); + bipolarMode = data.bipolar_mode; + updateBipolarModeUI(); } catch (error) { console.error('Failed to check bipolar mode status:', error); } @@ -3106,10 +3080,7 @@ async function loadScoreboard() { async function loadActiveArguments() { try { - const response = await fetch('/bipolar-mode/arguments'); - if (!response.ok) return; - - const data = await response.json(); + const data = await apiCall('/bipolar-mode/arguments'); const container = document.getElementById('active-arguments'); const list = document.getElementById('active-arguments-list'); @@ -3155,21 +3126,10 @@ async function triggerAutonomous(actionType) { endpoint += `?guild_id=${selectedServer}`; } - const response = await fetch(endpoint, { - method: 'POST', - headers: { 'Content-Type': 'application/json' } - }); - - const result = await response.json(); - - if (response.ok) { - showNotification(result.message || 'Action triggered successfully'); - } else { - throw new Error(result.message || 'Failed to trigger action'); - } + const result = await apiCall(endpoint, 'POST'); + showNotification(result.message || 'Action triggered successfully'); } catch (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()}`; } - const response = await fetch(endpoint, { - method: 'POST', - headers: { 'Content-Type': 'application/json' } - }); - - const result = await response.json(); - - if (response.ok) { - showNotification(result.message || 'Engagement triggered successfully'); - // Optionally collapse the submenu after successful trigger - // toggleEngageSubmenu(); - } else { - throw new Error(result.message || 'Failed to trigger engagement'); - } + const result = await apiCall(endpoint, 'POST'); + showNotification(result.message || 'Engagement triggered successfully'); + // Optionally collapse the submenu after successful trigger + // toggleEngageSubmenu(); } catch (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()}`; } - const response = await fetch(endpoint, { - method: 'POST', - headers: { 'Content-Type': 'application/json' } - }); - - const result = await response.json(); - - if (response.ok) { - showNotification(result.message || 'Tweet share triggered successfully'); - } else { - throw new Error(result.message || 'Failed to trigger tweet share'); - } + const result = await apiCall(endpoint, 'POST'); + showNotification(result.message || 'Tweet share triggered successfully'); } catch (error) { console.error('Failed to trigger tweet share:', error); - showNotification(error.message || 'Failed to trigger tweet share', 'error'); } } @@ -3326,31 +3264,22 @@ async function changeProfilePicture() { const url = params.toString() ? `${endpoint}?${params.toString()}` : endpoint; - const response = await fetch(url, { - method: 'POST' - }); + const result = await apiCall(url, 'POST'); - const result = await response.json(); + statusDiv.textContent = `✅ ${result.message}`; + statusDiv.style.color = 'green'; - if (response.ok && result.status === 'ok') { - statusDiv.textContent = `✅ ${result.message}`; - statusDiv.style.color = 'green'; - - // Display metadata if available - if (result.metadata) { - metadataContent.textContent = JSON.stringify(result.metadata, null, 2); - metadataDiv.style.display = 'block'; - } - - showNotification('Profile picture changed successfully!'); - } else { - throw new Error(result.message || 'Failed to change profile picture'); + // Display metadata if available + if (result.metadata) { + metadataContent.textContent = JSON.stringify(result.metadata, null, 2); + metadataDiv.style.display = 'block'; } + + showNotification('Profile picture changed successfully!'); } catch (error) { console.error('Failed to change profile picture:', error); statusDiv.textContent = `❌ Error: ${error.message}`; statusDiv.style.color = 'red'; - showNotification(error.message || 'Failed to change profile picture', 'error'); } } @@ -3431,26 +3360,17 @@ async function restoreFallbackPfp() { statusDiv.style.color = '#61dafb'; try { - const response = await fetch('/profile-picture/restore-fallback', { - method: 'POST' - }); + const result = await apiCall('/profile-picture/restore-fallback', 'POST'); - const result = await response.json(); + statusDiv.textContent = `✅ ${result.message}`; + statusDiv.style.color = 'green'; + metadataDiv.style.display = 'none'; - if (response.ok && result.status === 'ok') { - statusDiv.textContent = `✅ ${result.message}`; - statusDiv.style.color = 'green'; - metadataDiv.style.display = 'none'; - - showNotification('Original avatar restored successfully!'); - } else { - throw new Error(result.message || 'Failed to restore fallback avatar'); - } + showNotification('Original avatar restored successfully!'); } catch (error) { console.error('Failed to restore fallback avatar:', error); statusDiv.textContent = `❌ Error: ${error.message}`; statusDiv.style.color = 'red'; - showNotification(error.message || 'Failed to restore fallback avatar', 'error'); } } @@ -3502,28 +3422,19 @@ async function resetRoleColor() { statusDiv.style.color = '#61dafb'; try { - const response = await fetch('/role-color/reset-fallback', { - method: 'POST' - }); + const result = await apiCall('/role-color/reset-fallback', 'POST'); - const result = await response.json(); + statusDiv.textContent = `✅ ${result.message}`; + statusDiv.style.color = 'green'; - if (response.ok && result.status === 'ok') { - statusDiv.textContent = `✅ ${result.message}`; - statusDiv.style.color = 'green'; - - // Update the input to show fallback color - document.getElementById('role-color-hex').value = '#86cecb'; - - showNotification('Role color reset to fallback #86cecb'); - } else { - throw new Error(result.message || 'Failed to reset role color'); - } + // Update the input to show fallback color + document.getElementById('role-color-hex').value = '#86cecb'; + + showNotification('Role color reset to fallback #86cecb'); } catch (error) { console.error('Failed to reset role color:', error); statusDiv.textContent = `❌ Error: ${error.message}`; statusDiv.style.color = 'red'; - showNotification(error.message || 'Failed to reset role color', 'error'); } } @@ -3588,7 +3499,7 @@ async function sendCustomPrompt() { } try { - let endpoint, requestData, response; + let endpoint; if (targetType === 'dm') { // DM target @@ -3597,16 +3508,7 @@ async function sendCustomPrompt() { showNotification('Please enter a user ID for DM', 'error'); return; } - endpoint = `/dm/${userId}/custom`; - requestData = { prompt: prompt }; - - response = await fetch(endpoint, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(requestData) - }); - } else { // Server target const selectedServer = document.getElementById('custom-prompt-server-select').value; @@ -3617,33 +3519,20 @@ async function sendCustomPrompt() { // Don't use parseInt() - Discord IDs are too large for JS integers 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'); - document.getElementById('customPrompt').value = ''; - document.getElementById('customPromptAttachment').value = ''; // Clear file input - if (targetType === 'dm') { - document.getElementById('custom-prompt-user-id').value = ''; - } - document.getElementById('customStatus').textContent = '✅ Custom prompt sent successfully!'; - document.getElementById('customStatus').style.color = 'green'; - } else { - throw new Error(result.message || 'Failed to send custom prompt'); + showNotification(result.message || 'Custom prompt sent successfully'); + document.getElementById('customPrompt').value = ''; + document.getElementById('customPromptAttachment').value = ''; // Clear file input + if (targetType === 'dm') { + document.getElementById('custom-prompt-user-id').value = ''; } + document.getElementById('customStatus').textContent = '✅ Custom prompt sent successfully!'; + document.getElementById('customStatus').style.color = 'green'; } catch (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').style.color = 'red'; } @@ -3689,21 +3578,10 @@ async function sendBedtime() { console.log('🛏️ Final endpoint:', endpoint); - const response = await fetch(endpoint, { - method: 'POST', - headers: { 'Content-Type': 'application/json' } - }); - - const result = await response.json(); - - if (response.ok) { - showNotification(result.message || 'Bedtime reminder sent successfully'); - } else { - throw new Error(result.message || 'Failed to send bedtime reminder'); - } + const result = await apiCall(endpoint, 'POST'); + showNotification(result.message || 'Bedtime reminder sent successfully'); } catch (error) { console.error('Failed to send bedtime reminder:', error); - showNotification(error.message || 'Failed to send bedtime reminder', 'error'); } } @@ -3892,14 +3770,12 @@ async function checkImageSystemStatus() { const statusDisplay = document.getElementById('image-status-display'); statusDisplay.innerHTML = '🔄 Checking system status...'; - const response = await fetch('/image/status'); - const result = await response.json(); + const result = await apiCall('/image/status'); - if (response.ok) { - const workflowStatus = result.workflow_template_exists ? '✅ Found' : '❌ Missing'; - const comfyuiStatus = result.comfyui_running ? '✅ Running' : '❌ Not running'; - - statusDisplay.innerHTML = ` + const workflowStatus = result.workflow_template_exists ? '✅ Found' : '❌ Missing'; + const comfyuiStatus = result.comfyui_running ? '✅ Running' : '❌ Not running'; + + statusDisplay.innerHTML = ` System Status: • Workflow Template (Miku_BasicWorkflow.json): ${workflowStatus} • ComfyUI Server: ${comfyuiStatus} @@ -3908,9 +3784,6 @@ ${result.comfyui_running ? `• Detected ComfyUI URL: ${result.comfyui_url}` : ' Overall Status: ${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' : ''}`; - } else { - statusDisplay.innerHTML = `❌ Error checking status: ${result.message}`; - } } catch (error) { console.error('Failed to check image system status:', error); document.getElementById('image-status-display').innerHTML = `❌ Error: ${error.message}`; @@ -3931,28 +3804,17 @@ async function testImageDetection() { resultsDiv.innerHTML = '🔍 Testing detection...'; resultsDiv.style.color = '#4CAF50'; - const response = await fetch('/image/test-detection', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ message: message }) - }); + const result = await apiCall('/image/test-detection', 'POST', { message: message }); - const result = await response.json(); + const detectionIcon = result.is_image_request ? '✅' : '❌'; + const detectionText = result.is_image_request ? 'WILL trigger image generation' : 'will NOT trigger image generation'; - if (response.ok) { - const detectionIcon = result.is_image_request ? '✅' : '❌'; - const detectionText = result.is_image_request ? 'WILL trigger image generation' : 'will NOT trigger image generation'; - - resultsDiv.innerHTML = ` + resultsDiv.innerHTML = ` Detection Result: ${detectionIcon} This message ${detectionText} ${result.is_image_request ? `
Extracted Prompt: "${result.extracted_prompt}"` : ''}
Original Message: "${result.original_message}"`; - - resultsDiv.style.color = result.is_image_request ? '#4CAF50' : '#ff9800'; - } else { - resultsDiv.innerHTML = `❌ Detection test failed: ${result.message}`; - resultsDiv.style.color = 'red'; - } + + resultsDiv.style.color = result.is_image_request ? '#4CAF50' : '#ff9800'; } catch (error) { console.error('Failed to test image detection:', error); resultsDiv.innerHTML = `❌ Error: ${error.message}`; @@ -3978,20 +3840,13 @@ async function generateManualImage() { statusDiv.innerHTML = '🎨 Generating image... This may take a few minutes.'; statusDiv.style.color = '#4CAF50'; - const response = await fetch('/image/generate', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ prompt: prompt }) - }); + const result = await apiCall('/image/generate', 'POST', { prompt: prompt }); - const result = await response.json(); + statusDiv.innerHTML = `✅ Image generated successfully!`; + statusDiv.style.color = '#4CAF50'; - if (response.ok && result.status === 'ok') { - statusDiv.innerHTML = `✅ Image generated successfully!`; - statusDiv.style.color = '#4CAF50'; - - // Display the generated image - if (result.image_path) { + // Display the generated image + if (result.image_path) { const filename = result.image_path.split('/').pop(); const imageUrl = `/image/view/${encodeURIComponent(filename)}`; @@ -4030,10 +3885,6 @@ async function generateManualImage() { } document.getElementById('manual-image-prompt').value = ''; - } else { - statusDiv.innerHTML = `❌ Failed to generate image: ${result.message || 'Unknown error'}`; - statusDiv.style.color = 'red'; - } } catch (error) { console.error('Failed to generate image:', error); statusDiv.innerHTML = `❌ Error: ${error.message}`; @@ -4175,17 +4026,10 @@ function toggleCustomPrompt() { // DM Logs Functions async function loadDMUsers() { try { - const response = await fetch('/dms/users'); - const result = await response.json(); - - if (response.ok) { - displayDMUsers(result.users); - } else { - throw new Error(result.message || 'Failed to load DM users'); - } + const result = await apiCall('/dms/users'); + displayDMUsers(result.users); } catch (error) { console.error('Failed to load DM users:', error); - showNotification(error.message || 'Failed to load DM users', 'error'); } } @@ -4306,28 +4150,22 @@ function toggleCustomPrompt() { console.log(`🔍 Original userId: ${userId} (type: ${typeof userId})`); console.log(`🔍 userIdStr: ${userIdStr} (type: ${typeof userIdStr})`); - const response = await fetch(`/dms/users/${userIdStr}/conversations?limit=100`); - const result = await response.json(); + const result = await apiCall(`/dms/users/${userIdStr}/conversations?limit=100`); console.log('📡 API Response:', result); console.log('📡 API URL called:', `/dms/users/${userIdStr}/conversations?limit=100`); - if (response.ok) { - if (result.conversations && result.conversations.length > 0) { - console.log(`✅ Found ${result.conversations.length} conversations`); - displayUserConversations(userIdStr, result.conversations); - } else { - console.log('⚠️ No conversations found in response'); - showNotification('No conversations found for this user', 'info'); - // Go back to user list - loadDMUsers(); - } + if (result.conversations && result.conversations.length > 0) { + console.log(`✅ Found ${result.conversations.length} conversations`); + displayUserConversations(userIdStr, result.conversations); } else { - throw new Error(result.message || 'Failed to load conversations'); + console.log('⚠️ No conversations found in response'); + showNotification('No conversations found for this user', 'info'); + // Go back to user list + loadDMUsers(); } } catch (error) { console.error('Failed to load user conversations:', error); - showNotification(error.message || 'Failed to load conversations', 'error'); } } @@ -4419,18 +4257,11 @@ function toggleCustomPrompt() { try { // Ensure userId is always treated as a string const userIdStr = String(userId); - const response = await fetch(`/dms/users/${userIdStr}/export?format=txt`); - const result = await response.json(); - - if (response.ok) { - showNotification(`DM export completed for user ${userIdStr}`); - // You could trigger a download here if the file is accessible - } else { - throw new Error(result.message || 'Failed to export DMs'); - } + await apiCall(`/dms/users/${userIdStr}/export?format=txt`); + showNotification(`DM export completed for user ${userIdStr}`); + // You could trigger a download here if the file is accessible } catch (error) { console.error('Failed to export user DMs:', error); - showNotification(error.message || 'Failed to export DMs', 'error'); } } @@ -4443,18 +4274,11 @@ function toggleCustomPrompt() { } try { - const response = await fetch(`/dms/users/${userIdStr}`, { method: 'DELETE' }); - const result = await response.json(); - - if (response.ok) { - showNotification(`Deleted DM logs for user ${userIdStr}`); - loadDMUsers(); // Refresh the list - } else { - throw new Error(result.message || 'Failed to delete DM logs'); - } + await apiCall(`/dms/users/${userIdStr}`, 'DELETE'); + showNotification(`Deleted DM logs for user ${userIdStr}`); + loadDMUsers(); // Refresh the list } catch (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 { - const response = await fetch(`/dms/users/${userIdStr}/block`, { method: 'POST' }); - const result = await response.json(); - - if (response.ok) { - showNotification(`${username} has been blocked from sending DMs`); - loadDMUsers(); // Refresh the list - } else { - throw new Error(result.message || 'Failed to block user'); - } + await apiCall(`/dms/users/${userIdStr}/block`, 'POST'); + showNotification(`${username} has been blocked from sending DMs`); + loadDMUsers(); // Refresh the list } catch (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); try { - const response = await fetch(`/dms/users/${userIdStr}/unblock`, { method: 'POST' }); - const result = await response.json(); - - if (response.ok) { - showNotification(`${username} has been unblocked`); - loadBlockedUsers(); // Refresh blocked users list - } else { - throw new Error(result.message || 'Failed to unblock user'); - } + await apiCall(`/dms/users/${userIdStr}/unblock`, 'POST'); + showNotification(`${username} has been unblocked`); + loadBlockedUsers(); // Refresh blocked users list } catch (error) { console.error('Failed to unblock user:', error); - showNotification(error.message || 'Failed to unblock user', 'error'); } } @@ -4510,20 +4320,13 @@ function toggleCustomPrompt() { } try { - const response = await fetch(`/dms/users/${userIdStr}/conversations/delete-all`, { method: 'POST' }); - const result = await response.json(); - - if (response.ok) { - showNotification(`Bulk deletion queued for ${username} (deleting all Miku messages from Discord and logs)`); - setTimeout(() => { - loadDMUsers(); // Refresh after a delay to allow deletion to process - }, 2000); - } else { - throw new Error(result.message || 'Failed to delete conversations'); - } + await apiCall(`/dms/users/${userIdStr}/conversations/delete-all`, 'POST'); + showNotification(`Bulk deletion queued for ${username} (deleting all Miku messages from Discord and logs)`); + setTimeout(() => { + loadDMUsers(); // Refresh after a delay to allow deletion to process + }, 2000); } catch (error) { console.error('Failed to delete conversations:', error); - showNotification(error.message || 'Failed to delete conversations', 'error'); } } @@ -4541,18 +4344,11 @@ function toggleCustomPrompt() { } try { - const response = await fetch(`/dms/users/${userIdStr}/delete-completely`, { method: 'POST' }); - const result = await response.json(); - - if (response.ok) { - showNotification(`${username} has been completely deleted from the system`); - loadDMUsers(); // Refresh the list - } else { - throw new Error(result.message || 'Failed to delete user completely'); - } + await apiCall(`/dms/users/${userIdStr}/delete-completely`, 'POST'); + showNotification(`${username} has been completely deleted from the system`); + loadDMUsers(); // Refresh the list } catch (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 { - const response = await fetch(`/dms/users/${userIdStr}/conversations/${conversationId}/delete`, { method: 'POST' }); - const result = await response.json(); - - if (response.ok) { - showNotification('Miku message deletion queued (deleting from both Discord and logs)'); - setTimeout(() => { - viewUserConversations(userId); // Refresh after a short delay to allow deletion to process - }, 1000); - } else { - throw new Error(result.message || 'Failed to delete message'); - } + await apiCall(`/dms/users/${userIdStr}/conversations/${conversationId}/delete`, 'POST'); + showNotification('Miku message deletion queued (deleting from both Discord and logs)'); + setTimeout(() => { + viewUserConversations(userId); // Refresh after a short delay to allow deletion to process + }, 1000); } catch (error) { console.error('Failed to delete conversation:', error); - showNotification(error.message || 'Failed to delete message', 'error'); } } @@ -4591,21 +4380,15 @@ function toggleCustomPrompt() { try { showNotification(`Analyzing ${username}'s interactions...`, 'info'); - const response = await fetch(`/dms/users/${userIdStr}/analyze`, { method: 'POST' }); - const result = await response.json(); + const result = await apiCall(`/dms/users/${userIdStr}/analyze`, 'POST'); - if (response.ok) { - if (result.reported) { - showNotification(`✅ Analysis complete! Report sent to bot owner for ${username}`); - } else { - showNotification(`📊 Analysis complete for ${username} (not enough messages or already reported today)`); - } + if (result.reported) { + showNotification(`✅ Analysis complete! Report sent to bot owner for ${username}`); } else { - throw new Error(result.message || 'Failed to analyze user'); + showNotification(`📊 Analysis complete for ${username} (not enough messages or already reported today)`); } } catch (error) { console.error('Failed to analyze user:', error); - showNotification(error.message || 'Failed to analyze user', 'error'); } } @@ -4617,17 +4400,10 @@ function toggleCustomPrompt() { try { showNotification('Starting DM interaction analysis...', 'info'); - const response = await fetch('/dms/analysis/run', { method: 'POST' }); - const result = await response.json(); - - if (response.ok) { - showNotification('✅ DM analysis completed! Check bot owner\'s DMs for any reports.'); - } else { - throw new Error(result.message || 'Failed to run analysis'); - } + await apiCall('/dms/analysis/run', 'POST'); + showNotification('✅ DM analysis completed! Check bot owner\'s DMs for any reports.'); } catch (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 { showNotification('Loading analysis reports...', 'info'); - const response = await fetch('/dms/analysis/reports?limit=50'); - const result = await response.json(); - - if (response.ok) { - displayAnalysisReports(result.reports); - } else { - throw new Error(result.message || 'Failed to load reports'); - } + const result = await apiCall('/dms/analysis/reports?limit=50'); + displayAnalysisReports(result.reports); } catch (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() { try { - const response = await fetch('/dms/blocked-users'); - const result = await response.json(); - - if (response.ok) { - // Hide DM users list and show blocked users section - document.getElementById('dm-users-list').style.display = 'none'; - document.getElementById('blocked-users-section').style.display = 'block'; - displayBlockedUsers(result.blocked_users); - } else { - throw new Error(result.message || 'Failed to load blocked users'); - } + const result = await apiCall('/dms/blocked-users'); + // Hide DM users list and show blocked users section + document.getElementById('dm-users-list').style.display = 'none'; + document.getElementById('blocked-users-section').style.display = 'block'; + displayBlockedUsers(result.blocked_users); } catch (error) { console.error('Failed to load blocked users:', error); - showNotification(error.message || 'Failed to load blocked users', 'error'); } } @@ -4790,26 +4552,20 @@ function toggleCustomPrompt() { async function exportAllDMs() { try { - const response = await fetch('/dms/users'); - const result = await response.json(); + const result = await apiCall('/dms/users'); - if (response.ok && result.users) { - let exportCount = 0; - for (const user of result.users) { - try { - await exportUserDMs(user.user_id); - exportCount++; - } catch (e) { - console.error(`Failed to export DMs for user ${user.user_id}:`, e); - } + let exportCount = 0; + for (const user of (result.users || [])) { + try { + await exportUserDMs(user.user_id); + exportCount++; + } catch (e) { + console.error(`Failed to export DMs for user ${user.user_id}:`, e); } - showNotification(`Exported DMs for ${exportCount} users`); - } else { - throw new Error(result.message || 'Failed to load DM users for export'); } + showNotification(`Exported DMs for ${exportCount} users`); } catch (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 { - const response = await fetch('/autonomous/stats'); - const data = await response.json(); + const data = await apiCall('/autonomous/stats'); if (!data.servers || !data.servers[selectedGuildId]) { document.getElementById('autonomous-stats-display').innerHTML = '

Server not found or not initialized.

'; @@ -4836,7 +4591,6 @@ async function loadAutonomousStats() { displayAutonomousStats(serverData); } catch (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 async function loadVoiceDebugMode() { try { - const response = await fetch('/voice/debug-mode'); - const data = await response.json(); + const data = await apiCall('/voice/debug-mode'); const checkbox = document.getElementById('voice-debug-mode'); if (checkbox && data.debug_mode !== undefined) { checkbox.checked = data.debug_mode; @@ -5526,8 +5279,7 @@ function updateVoiceCallHistoryDisplay() { async function refreshMemoryStats() { try { // Fetch Cat status - const statusRes = await fetch('/memory/status'); - const statusData = await statusRes.json(); + const statusData = await apiCall('/memory/status'); const indicator = document.getElementById('cat-status-indicator'); const toggleBtn = document.getElementById('cat-toggle-btn'); @@ -5547,8 +5299,7 @@ async function refreshMemoryStats() { toggleBtn.style.borderColor = statusData.enabled ? '#4a9a4a' : '#9a4a4a'; // Fetch memory stats - const statsRes = await fetch('/memory/stats'); - const statsData = await statsRes.json(); + const statsData = await apiCall('/memory/stats'); if (statsData.success && statsData.collections) { const collections = {}; @@ -5570,8 +5321,7 @@ async function refreshMemoryStats() { async function toggleCatIntegration() { try { - const statusRes = await fetch('/memory/status'); - const statusData = await statusRes.json(); + const statusData = await apiCall('/memory/status'); const newState = !statusData.enabled; const formData = new FormData(); @@ -5599,8 +5349,7 @@ async function triggerConsolidation() { resultDiv.style.display = 'none'; try { - const res = await fetch('/memory/consolidate', { method: 'POST' }); - const data = await res.json(); + const data = await apiCall('/memory/consolidate', 'POST'); if (data.success) { status.textContent = '✅ Consolidation complete!'; @@ -5627,8 +5376,7 @@ async function loadFacts() { listDiv.innerHTML = '
Loading facts...
'; try { - const res = await fetch('/memory/facts'); - const data = await res.json(); + const data = await apiCall('/memory/facts'); if (!data.success || data.count === 0) { listDiv.innerHTML = '
No declarative facts stored yet.
'; @@ -5670,8 +5418,7 @@ async function loadEpisodicMemories() { listDiv.innerHTML = '
Loading memories...
'; try { - const res = await fetch('/memory/episodic'); - const data = await res.json(); + const data = await apiCall('/memory/episodic'); if (!data.success || data.count === 0) { listDiv.innerHTML = '
No episodic memories stored yet.
'; @@ -5712,8 +5459,7 @@ async function deleteMemoryPoint(collection, pointId, btnElement) { if (!confirm(`Delete this ${collection} memory point?`)) return; try { - const res = await fetch(`/memory/point/${collection}/${pointId}`, { method: 'DELETE' }); - const data = await res.json(); + const data = await apiCall(`/memory/point/${collection}/${pointId}`, 'DELETE'); if (data.success) { // 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'); } } 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...'; try { - const res = await fetch('/memory/delete', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ confirmation: input }) - }); - const data = await res.json(); + const data = await apiCall('/memory/delete', 'POST', { confirmation: input }); if (data.success) { showNotification('All memories have been permanently deleted', 'success'); @@ -5795,7 +5536,7 @@ async function executeDeleteAllMemories() { showNotification('Deletion failed: ' + (data.error || 'Unknown error'), 'error'); } } catch (err) { - showNotification('Error: ' + err.message, 'error'); + console.error('Failed to delete all memories:', err); } finally { btn.disabled = false; btn.textContent = '🗑️ Permanently Delete All Memories'; @@ -5864,17 +5605,11 @@ async function saveMemoryEdit() { saveBtn.textContent = 'Saving...'; try { - const res = await fetch(`/memory/point/${collection}/${pointId}`, { - method: 'PUT', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - content: content, - metadata: { source: source || 'manual_edit' } - }) + const data = await apiCall(`/memory/point/${collection}/${pointId}`, 'PUT', { + content: content, + metadata: { source: source || 'manual_edit' } }); - const data = await res.json(); - if (data.success) { showNotification('Memory updated successfully', 'success'); closeEditMemoryModal(); @@ -5888,7 +5623,7 @@ async function saveMemoryEdit() { showNotification('Failed to update: ' + (data.error || 'Unknown error'), 'error'); } } catch (err) { - showNotification('Error: ' + err.message, 'error'); + console.error('Failed to save memory edit:', err); } finally { saveBtn.disabled = false; saveBtn.textContent = 'Save Changes'; @@ -5941,20 +5676,14 @@ async function saveNewMemory() { createBtn.textContent = 'Creating...'; try { - const res = await fetch('/memory/create', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - collection: collection, - content: content, - user_id: userId || null, - source: source || 'manual', - metadata: {} - }) + const data = await apiCall('/memory/create', 'POST', { + collection: collection, + content: content, + user_id: userId || null, + source: source || 'manual', + metadata: {} }); - const data = await res.json(); - if (data.success) { showNotification(`${collection === 'declarative' ? 'Fact' : 'Memory'} created successfully`, 'success'); closeCreateMemoryModal(); @@ -5969,7 +5698,7 @@ async function saveNewMemory() { showNotification('Failed to create: ' + (data.error || 'Unknown error'), 'error'); } } catch (err) { - showNotification('Error: ' + err.message, 'error'); + console.error('Failed to save new memory:', err); } finally { createBtn.disabled = false; createBtn.textContent = 'Create Memory';