ghygyyggy

This commit is contained in:
Slipstream 2025-05-03 18:25:24 -06:00
parent 16ae8e0841
commit 3c4c776e54
Signed by: slipstream
GPG Key ID: 13E498CE010AC6FD
3 changed files with 227 additions and 533 deletions

View File

@ -443,6 +443,89 @@ async def sync_guild_commands(
detail=f"Error syncing commands: {str(e)}"
)
@router.post("/guilds/{guild_id}/test-welcome", status_code=status.HTTP_200_OK)
async def test_welcome_message(
guild_id: int,
_user: dict = Depends(get_dashboard_user),
_admin: bool = Depends(verify_dashboard_guild_admin)
):
"""Test the welcome message for a guild."""
try:
# Get welcome settings
welcome_channel_id_str = await settings_manager.get_setting(guild_id, 'welcome_channel_id')
welcome_message_template = await settings_manager.get_setting(guild_id, 'welcome_message', default="Welcome {user} to {server}!")
# Check if welcome channel is set
if not welcome_channel_id_str or welcome_channel_id_str == "__NONE__":
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Welcome channel not configured"
)
# In a real implementation, this would send a test message to the welcome channel
# For now, we'll just return a success message with the formatted message
formatted_message = welcome_message_template.format(
user="@TestUser",
username="TestUser",
server=f"Server {guild_id}"
)
return {
"message": "Test welcome message sent",
"channel_id": welcome_channel_id_str,
"formatted_message": formatted_message
}
except HTTPException:
# Re-raise HTTP exceptions
raise
except Exception as e:
log.error(f"Error testing welcome message for guild {guild_id}: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Error testing welcome message: {str(e)}"
)
@router.post("/guilds/{guild_id}/test-goodbye", status_code=status.HTTP_200_OK)
async def test_goodbye_message(
guild_id: int,
_user: dict = Depends(get_dashboard_user),
_admin: bool = Depends(verify_dashboard_guild_admin)
):
"""Test the goodbye message for a guild."""
try:
# Get goodbye settings
goodbye_channel_id_str = await settings_manager.get_setting(guild_id, 'goodbye_channel_id')
goodbye_message_template = await settings_manager.get_setting(guild_id, 'goodbye_message', default="{username} has left the server.")
# Check if goodbye channel is set
if not goodbye_channel_id_str or goodbye_channel_id_str == "__NONE__":
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Goodbye channel not configured"
)
# In a real implementation, this would send a test message to the goodbye channel
# For now, we'll just return a success message with the formatted message
formatted_message = goodbye_message_template.format(
username="TestUser",
server=f"Server {guild_id}"
)
return {
"message": "Test goodbye message sent",
"channel_id": goodbye_channel_id_str,
"formatted_message": formatted_message
}
except HTTPException:
# Re-raise HTTP exceptions
raise
except Exception as e:
log.error(f"Error testing goodbye message for guild {guild_id}: {e}")
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail=f"Error testing goodbye message: {str(e)}"
)
# --- Global Settings Endpoints ---
@router.get("/settings", response_model=GlobalSettings)

View File

@ -38,13 +38,17 @@
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"></rect><line x1="8" y1="21" x2="16" y2="21"></line><line x1="12" y1="17" x2="12" y2="21"></line></svg>
Server Settings
</a>
<a href="#ai-settings" class="nav-item" data-section="ai-settings-section">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><path d="M12 2a10 10 0 1 0 10 10H12V2z"></path><path d="M20 12a8 8 0 1 0-16 0"></path><path d="M12 12v10"></path></svg>
AI Settings
<a href="#welcome-module" class="nav-item" data-section="welcome-module-section">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
Welcome/Leave
</a>
<a href="#conversations" class="nav-item" data-section="conversations-section">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
Conversations
<a href="#modules-settings" class="nav-item" data-section="modules-settings-section">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"></path><rect x="8" y="2" width="8" height="4" rx="1" ry="1"></rect></svg>
Modules
</a>
<a href="#permissions-settings" class="nav-item" data-section="permissions-settings-section">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="nav-icon"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"></path></svg>
Permissions
</a>
</div>
<div class="sidebar-footer">
@ -102,7 +106,18 @@
<p id="prefix-feedback" class="mt-2"></p>
</div>
</div>
</div>
</div>
<!-- Welcome/Leave Module Section -->
<div id="welcome-module-section" class="dashboard-section" style="display: none;">
<div class="card">
<div class="card-header">
<h2 class="card-title">Welcome & Leave Messages</h2>
</div>
</div>
<div id="welcome-settings-form" style="display: none;">
<div class="card">
<div class="card-header">
<h3 class="card-title">Welcome Messages</h3>
@ -124,6 +139,7 @@
<div class="btn-group">
<button id="save-welcome-button" class="btn btn-primary">Save Welcome Settings</button>
<button id="disable-welcome-button" class="btn btn-warning">Disable Welcome</button>
<button id="test-welcome-button" class="btn btn-secondary">Test Welcome Message</button>
</div>
<p id="welcome-feedback" class="mt-2"></p>
</div>
@ -149,10 +165,22 @@
<div class="btn-group">
<button id="save-goodbye-button" class="btn btn-primary">Save Goodbye Settings</button>
<button id="disable-goodbye-button" class="btn btn-warning">Disable Goodbye</button>
<button id="test-goodbye-button" class="btn btn-secondary">Test Goodbye Message</button>
</div>
<p id="goodbye-feedback" class="mt-2"></p>
</div>
</div>
</div>
<!-- Modules Settings Section -->
<div id="modules-settings-section" class="dashboard-section" style="display: none;">
<div class="card">
<div class="card-header">
<h2 class="card-title">Manage Bot Modules</h2>
</div>
</div>
<div id="modules-settings-form" style="display: none;">
<div class="card">
<div class="card-header">
<h3 class="card-title">Enabled Modules (Cogs)</h3>
@ -170,7 +198,18 @@
</div>
<p id="cogs-feedback" class="mt-2"></p>
</div>
</div>
</div>
<!-- Permissions Settings Section -->
<div id="permissions-settings-section" class="dashboard-section" style="display: none;">
<div class="card">
<div class="card-header">
<h2 class="card-title">Command Permissions</h2>
</div>
</div>
<div id="permissions-settings-form" style="display: none;">
<div class="card">
<div class="card-header">
<h3 class="card-title">Command Permissions</h3>
@ -202,262 +241,12 @@
</div>
</div>
<!-- AI Settings Section -->
<div id="ai-settings-section" class="dashboard-section" style="display: none;">
<div class="card">
<div class="card-header">
<h2 class="card-title">AI Settings</h2>
</div>
</div>
<div class="card">
<div class="card-header">
<h3 class="card-title">General AI Settings</h3>
</div>
<div class="form-group">
<label for="ai-model-select">AI Model:</label>
<select id="ai-model-select" class="w-full">
<option value="openai/gpt-3.5-turbo">GPT-3.5 Turbo</option>
<option value="openai/gpt-4">GPT-4</option>
<option value="anthropic/claude-3-opus">Claude 3 Opus</option>
<option value="anthropic/claude-3-sonnet">Claude 3 Sonnet</option>
<option value="google/gemini-2.5-flash-preview">Gemini 2.5 Flash</option>
<option value="google/gemini-2.5-pro-preview">Gemini 2.5 Pro</option>
<!-- More models will be populated dynamically if available -->
</select>
</div>
<div class="form-group">
<label for="ai-temperature">Temperature: <span id="temperature-value">0.7</span></label>
<input type="range" id="ai-temperature" min="0" max="2" step="0.1" value="0.7" class="w-full">
</div>
<div class="form-group">
<label for="ai-max-tokens">Max Tokens:</label>
<input type="number" id="ai-max-tokens" min="100" max="8000" step="100" value="1000" class="w-full">
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="ai-reasoning-enabled">
Enable Reasoning
</label>
</div>
<div class="form-group" id="reasoning-effort-group">
<label for="ai-reasoning-effort">Reasoning Effort:</label>
<select id="ai-reasoning-effort" class="w-full">
<option value="low">Low</option>
<option value="medium" selected>Medium</option>
<option value="high">High</option>
</select>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="ai-web-search-enabled">
Enable Web Search
</label>
</div>
<div class="btn-group">
<button id="save-ai-settings-button" class="btn btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>
Save AI Settings
</button>
<button id="reset-ai-settings-button" class="btn btn-warning">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path></svg>
Reset to Defaults
</button>
</div>
<p id="ai-settings-feedback" class="mt-2"></p>
</div>
<div class="card">
<div class="card-header">
<h3 class="card-title">Character Settings</h3>
</div>
<div class="form-group">
<label for="ai-character">Character Name:</label>
<input type="text" id="ai-character" placeholder="e.g., Kasane Teto" class="w-full">
</div>
<div class="form-group">
<label for="ai-character-info">Character Information:</label>
<textarea id="ai-character-info" rows="4" placeholder="Describe the character's personality, background, etc." class="w-full"></textarea>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="ai-character-breakdown">
Enable Character Breakdown
</label>
</div>
<div class="btn-group">
<button id="save-character-settings-button" class="btn btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>
Save Character Settings
</button>
<button id="clear-character-settings-button" class="btn btn-warning">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
Clear Character
</button>
</div>
<p id="character-settings-feedback" class="mt-2"></p>
</div>
<div class="card">
<div class="card-header">
<h3 class="card-title">System Prompt</h3>
</div>
<div class="form-group">
<textarea id="ai-system-prompt" rows="6" placeholder="Enter a system prompt to guide the AI's behavior..." class="w-full"></textarea>
</div>
<div class="btn-group">
<button id="save-system-prompt-button" class="btn btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>
Save System Prompt
</button>
<button id="reset-system-prompt-button" class="btn btn-warning">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path></svg>
Reset to Default
</button>
</div>
<p id="system-prompt-feedback" class="mt-2"></p>
</div>
<div class="card">
<div class="card-header">
<h3 class="card-title">Custom Instructions</h3>
</div>
<div class="form-group">
<textarea id="ai-custom-instructions" rows="6" placeholder="Enter custom instructions for the AI..." class="w-full"></textarea>
</div>
<div class="btn-group">
<button id="save-custom-instructions-button" class="btn btn-primary">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>
Save Custom Instructions
</button>
<button id="clear-custom-instructions-button" class="btn btn-warning">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path><line x1="10" y1="11" x2="10" y2="17"></line><line x1="14" y1="11" x2="14" y2="17"></line></svg>
Clear Instructions
</button>
</div>
<p id="custom-instructions-feedback" class="mt-2"></p>
</div>
</div>
<!-- Conversations Section -->
<div id="conversations-section" class="dashboard-section" style="display: none;">
<div class="card">
<div class="card-header">
<h2 class="card-title">AI Conversations</h2>
</div>
</div>
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h3 class="card-title mb-0">Your Conversations</h3>
<button id="new-conversation-button" class="btn btn-primary btn-sm">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-1"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
New Conversation
</button>
</div>
<div class="form-group mt-4">
<div class="search-container">
<input type="text" id="conversation-search" placeholder="Search conversations..." class="w-full">
</div>
</div>
<div class="conversations-list-container border rounded p-0 mb-4" style="max-height: 300px; overflow-y: auto;">
<div id="conversations-list">
<!-- Will be populated by JS -->
<div class="no-conversations p-4 text-center text-gray">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round" style="margin: 0 auto 1rem;"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg>
<p>No conversations found.</p>
<button id="start-conversation-button" class="btn btn-primary btn-sm mt-2">Start a new conversation</button>
</div>
</div>
</div>
</div>
<div id="conversation-detail" class="card" style="display: none;">
<div class="card-header d-flex justify-content-between align-items-center">
<h3 id="conversation-title" class="card-title mb-0">Conversation Title</h3>
<div class="conversation-actions">
<button id="rename-conversation-button" class="btn btn-secondary btn-sm">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
</button>
<button id="export-conversation-button" class="btn btn-secondary btn-sm">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>
</button>
<button id="delete-conversation-button" class="btn btn-danger btn-sm">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>
</button>
</div>
</div>
<div class="conversation-messages p-4" id="conversation-messages" style="max-height: 500px; overflow-y: auto;">
<!-- Will be populated by JS -->
<div class="loading-spinner-container">
<div class="loading-spinner"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modal for renaming conversations -->
<div id="rename-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Rename Conversation</h3>
<button class="modal-close">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="new-conversation-title">New Title:</label>
<input type="text" id="new-conversation-title" placeholder="Enter new title" class="w-full">
</div>
</div>
<div class="modal-footer">
<button id="cancel-rename-button" class="btn btn-secondary">Cancel</button>
<button id="confirm-rename-button" class="btn btn-primary">Rename</button>
</div>
</div>
</div>
<!-- Modal for creating new conversations -->
<div id="new-conversation-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Create New Conversation</h3>
<button class="modal-close">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label for="new-conversation-name">Conversation Title:</label>
<input type="text" id="new-conversation-name" placeholder="Enter conversation title" class="w-full">
</div>
</div>
<div class="modal-footer">
<button id="cancel-create-button" class="btn btn-secondary">Cancel</button>
<button id="create-conversation-button" class="btn btn-primary">Create</button>
</div>
</div>
</div>
<!-- Delete confirmation modal -->
<div id="delete-confirm-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Delete Conversation</h3>
<button class="modal-close">&times;</button>
</div>
<div class="modal-body">
<p>Are you sure you want to delete this conversation? This action cannot be undone.</p>
</div>
<div class="modal-footer">
<button id="cancel-delete-button" class="btn btn-secondary">Cancel</button>
<button id="confirm-delete-button" class="btn btn-danger">Delete</button>
</div>
</div>
</div>
<!-- JavaScript files -->
<script src="js/utils.js"></script>

View File

@ -337,9 +337,6 @@ function initDropdowns() {
function loadDashboardData() {
// Load guilds for server select
loadGuilds();
// Load global settings
loadGlobalSettings();
}
/**
@ -431,6 +428,10 @@ function loadGuilds() {
*/
function loadGuildSettings(guildId) {
const settingsForm = document.getElementById('settings-form');
const welcomeSettingsForm = document.getElementById('welcome-settings-form');
const modulesSettingsForm = document.getElementById('modules-settings-form');
const permissionsSettingsForm = document.getElementById('permissions-settings-form');
if (!settingsForm) return;
// Show loading state
@ -440,7 +441,13 @@ function loadGuildSettings(guildId) {
loadingContainer.style.textAlign = 'center';
loadingContainer.style.padding = '2rem';
// Hide all forms
settingsForm.style.display = 'none';
if (welcomeSettingsForm) welcomeSettingsForm.style.display = 'none';
if (modulesSettingsForm) modulesSettingsForm.style.display = 'none';
if (permissionsSettingsForm) permissionsSettingsForm.style.display = 'none';
// Add loading indicator to server settings section
settingsForm.parentNode.insertBefore(loadingContainer, settingsForm);
// Fetch guild settings from API
@ -449,16 +456,22 @@ function loadGuildSettings(guildId) {
// Remove loading container
loadingContainer.remove();
// Show settings form
// Show all settings forms
settingsForm.style.display = 'block';
if (welcomeSettingsForm) welcomeSettingsForm.style.display = 'block';
if (modulesSettingsForm) modulesSettingsForm.style.display = 'block';
if (permissionsSettingsForm) permissionsSettingsForm.style.display = 'block';
// Populate form with settings
// Populate forms with settings
populateGuildSettings(settings);
// Load additional data
loadGuildChannels(guildId);
loadGuildRoles(guildId);
loadGuildCommands(guildId);
// Set up welcome/leave message test buttons
setupWelcomeLeaveTestButtons(guildId);
})
.catch(error => {
console.error('Error loading guild settings:', error);
@ -881,292 +894,101 @@ function removeCommandPermission(guildId, command, roleId) {
}
/**
* Load global AI settings
* Set up welcome/leave message test buttons
* @param {string} guildId - The guild ID
*/
function loadGlobalSettings() {
const aiSettingsSection = document.getElementById('ai-settings-section');
if (!aiSettingsSection) return;
function setupWelcomeLeaveTestButtons(guildId) {
// Welcome message test button
const testWelcomeButton = document.getElementById('test-welcome-button');
if (testWelcomeButton) {
testWelcomeButton.addEventListener('click', () => {
// Show loading state
testWelcomeButton.disabled = true;
testWelcomeButton.classList.add('btn-loading');
// Show loading state
const loadingContainer = document.createElement('div');
loadingContainer.className = 'loading-container';
loadingContainer.innerHTML = '<div class="loading-spinner"></div><p>Loading AI settings...</p>';
loadingContainer.style.textAlign = 'center';
loadingContainer.style.padding = '2rem';
// Send test request to API
API.post(`/dashboard/api/guilds/${guildId}/test-welcome`)
.then(response => {
console.log('Test welcome message response:', response);
aiSettingsSection.prepend(loadingContainer);
// Show success message with formatted message
Toast.success('Test welcome message sent!');
// Fetch global settings from API
API.get('/dashboard/api/settings')
.then(settings => {
// Remove loading container
loadingContainer.remove();
// Show formatted message in feedback area
const welcomeFeedback = document.getElementById('welcome-feedback');
if (welcomeFeedback) {
welcomeFeedback.innerHTML = `
<div class="mt-4 p-3 border rounded bg-light">
<strong>Test Message:</strong>
<p class="mb-0">${response.formatted_message}</p>
<small class="text-muted">Sent to channel ID: ${response.channel_id}</small>
</div>
`;
}
})
.catch(error => {
console.error('Error testing welcome message:', error);
console.log('Loaded AI settings:', settings);
// Populate AI model select
const modelSelect = document.getElementById('ai-model-select');
if (modelSelect && settings.model) {
modelSelect.value = settings.model;
}
// Populate temperature slider
const temperatureSlider = document.getElementById('ai-temperature');
const temperatureValue = document.getElementById('temperature-value');
if (temperatureSlider && temperatureValue) {
const temp = settings.temperature !== undefined ? settings.temperature : 0.7;
temperatureSlider.value = temp;
temperatureValue.textContent = temp;
// Add input event for live update
temperatureSlider.addEventListener('input', () => {
temperatureValue.textContent = temperatureSlider.value;
// Show error message
if (error.status === 400) {
Toast.error('Welcome channel not configured. Please set a welcome channel first.');
} else {
Toast.error('Failed to test welcome message. Please try again.');
}
})
.finally(() => {
// Remove loading state
testWelcomeButton.disabled = false;
testWelcomeButton.classList.remove('btn-loading');
});
}
// Populate max tokens
const maxTokensInput = document.getElementById('ai-max-tokens');
if (maxTokensInput) {
const maxTokens = settings.max_tokens !== undefined ? settings.max_tokens : 1000;
maxTokensInput.value = maxTokens;
}
// Populate character settings
const characterInput = document.getElementById('ai-character');
const characterInfoInput = document.getElementById('ai-character-info');
if (characterInput) {
characterInput.value = settings.character || '';
}
if (characterInfoInput) {
characterInfoInput.value = settings.character_info || '';
}
// Populate system prompt
const systemPromptInput = document.getElementById('ai-system-prompt');
if (systemPromptInput) {
systemPromptInput.value = settings.system_message || '';
}
// Populate custom instructions
const customInstructionsInput = document.getElementById('ai-custom-instructions');
if (customInstructionsInput) {
customInstructionsInput.value = settings.custom_instructions || '';
}
// Set up save buttons
setupAISettingsSaveButtons(settings);
})
.catch(error => {
console.error('Error loading global settings:', error);
loadingContainer.innerHTML = '<p class="text-danger">Error loading AI settings. Please try again.</p>';
Toast.error('Failed to load AI settings. Please try again.');
});
}
/**
* Set up AI settings save buttons
* @param {Object} initialSettings - The initial settings
*/
function setupAISettingsSaveButtons(initialSettings) {
// AI Settings save button
const saveAISettingsButton = document.getElementById('save-ai-settings-button');
if (saveAISettingsButton) {
saveAISettingsButton.addEventListener('click', () => {
const modelSelect = document.getElementById('ai-model-select');
const temperatureSlider = document.getElementById('ai-temperature');
const maxTokensInput = document.getElementById('ai-max-tokens');
const reasoningEnabled = document.getElementById('ai-reasoning-enabled');
const reasoningEffort = document.getElementById('ai-reasoning-effort');
const webSearchEnabled = document.getElementById('ai-web-search-enabled');
// Create settings object
const settings = {
...initialSettings, // Keep other settings
model: modelSelect ? modelSelect.value : initialSettings.model,
temperature: temperatureSlider ? parseFloat(temperatureSlider.value) : initialSettings.temperature,
max_tokens: maxTokensInput ? parseInt(maxTokensInput.value) : initialSettings.max_tokens
};
// Add optional settings if they exist
if (reasoningEnabled) {
settings.reasoning_enabled = reasoningEnabled.checked;
}
if (reasoningEffort) {
settings.reasoning_effort = reasoningEffort.value;
}
if (webSearchEnabled) {
settings.web_search_enabled = webSearchEnabled.checked;
}
// Save settings
saveSettings(settings, saveAISettingsButton, 'AI settings saved successfully');
});
}
// Character settings save button
const saveCharacterSettingsButton = document.getElementById('save-character-settings-button');
if (saveCharacterSettingsButton) {
saveCharacterSettingsButton.addEventListener('click', () => {
const characterInput = document.getElementById('ai-character');
const characterInfoInput = document.getElementById('ai-character-info');
const characterBreakdown = document.getElementById('ai-character-breakdown');
// Goodbye message test button
const testGoodbyeButton = document.getElementById('test-goodbye-button');
if (testGoodbyeButton) {
testGoodbyeButton.addEventListener('click', () => {
// Show loading state
testGoodbyeButton.disabled = true;
testGoodbyeButton.classList.add('btn-loading');
// Create settings object
const settings = {
...initialSettings, // Keep other settings
character: characterInput ? characterInput.value : initialSettings.character,
character_info: characterInfoInput ? characterInfoInput.value : initialSettings.character_info
};
// Send test request to API
API.post(`/dashboard/api/guilds/${guildId}/test-goodbye`)
.then(response => {
console.log('Test goodbye message response:', response);
// Add optional settings if they exist
if (characterBreakdown) {
settings.character_breakdown = characterBreakdown.checked;
}
// Show success message with formatted message
Toast.success('Test goodbye message sent!');
// Save settings
saveSettings(settings, saveCharacterSettingsButton, 'Character settings saved successfully');
});
}
// Show formatted message in feedback area
const goodbyeFeedback = document.getElementById('goodbye-feedback');
if (goodbyeFeedback) {
goodbyeFeedback.innerHTML = `
<div class="mt-4 p-3 border rounded bg-light">
<strong>Test Message:</strong>
<p class="mb-0">${response.formatted_message}</p>
<small class="text-muted">Sent to channel ID: ${response.channel_id}</small>
</div>
`;
}
})
.catch(error => {
console.error('Error testing goodbye message:', error);
// System prompt save button
const saveSystemPromptButton = document.getElementById('save-system-prompt-button');
if (saveSystemPromptButton) {
saveSystemPromptButton.addEventListener('click', () => {
const systemPromptInput = document.getElementById('ai-system-prompt');
// Create settings object
const settings = {
...initialSettings, // Keep other settings
system_message: systemPromptInput ? systemPromptInput.value : initialSettings.system_message
};
// Save settings
saveSettings(settings, saveSystemPromptButton, 'System prompt saved successfully');
});
}
// Custom instructions save button
const saveCustomInstructionsButton = document.getElementById('save-custom-instructions-button');
if (saveCustomInstructionsButton) {
saveCustomInstructionsButton.addEventListener('click', () => {
const customInstructionsInput = document.getElementById('ai-custom-instructions');
// Create settings object
const settings = {
...initialSettings, // Keep other settings
custom_instructions: customInstructionsInput ? customInstructionsInput.value : initialSettings.custom_instructions
};
// Save settings
saveSettings(settings, saveCustomInstructionsButton, 'Custom instructions saved successfully');
});
}
// Clear buttons
const clearCharacterSettingsButton = document.getElementById('clear-character-settings-button');
if (clearCharacterSettingsButton) {
clearCharacterSettingsButton.addEventListener('click', () => {
const characterInput = document.getElementById('ai-character');
const characterInfoInput = document.getElementById('ai-character-info');
if (characterInput) characterInput.value = '';
if (characterInfoInput) characterInfoInput.value = '';
// Create settings object
const settings = {
...initialSettings, // Keep other settings
character: '',
character_info: ''
};
// Save settings
saveSettings(settings, clearCharacterSettingsButton, 'Character settings cleared');
});
}
const clearCustomInstructionsButton = document.getElementById('clear-custom-instructions-button');
if (clearCustomInstructionsButton) {
clearCustomInstructionsButton.addEventListener('click', () => {
const customInstructionsInput = document.getElementById('ai-custom-instructions');
if (customInstructionsInput) customInstructionsInput.value = '';
// Create settings object
const settings = {
...initialSettings, // Keep other settings
custom_instructions: ''
};
// Save settings
saveSettings(settings, clearCustomInstructionsButton, 'Custom instructions cleared');
});
}
// Reset buttons
const resetAISettingsButton = document.getElementById('reset-ai-settings-button');
if (resetAISettingsButton) {
resetAISettingsButton.addEventListener('click', () => {
const modelSelect = document.getElementById('ai-model-select');
const temperatureSlider = document.getElementById('ai-temperature');
const temperatureValue = document.getElementById('temperature-value');
const maxTokensInput = document.getElementById('ai-max-tokens');
if (modelSelect) modelSelect.value = 'openai/gpt-3.5-turbo';
if (temperatureSlider) temperatureSlider.value = 0.7;
if (temperatureValue) temperatureValue.textContent = 0.7;
if (maxTokensInput) maxTokensInput.value = 1000;
// Create settings object
const settings = {
...initialSettings, // Keep other settings
model: 'openai/gpt-3.5-turbo',
temperature: 0.7,
max_tokens: 1000
};
// Save settings
saveSettings(settings, resetAISettingsButton, 'AI settings reset to defaults');
});
}
const resetSystemPromptButton = document.getElementById('reset-system-prompt-button');
if (resetSystemPromptButton) {
resetSystemPromptButton.addEventListener('click', () => {
const systemPromptInput = document.getElementById('ai-system-prompt');
if (systemPromptInput) systemPromptInput.value = '';
// Create settings object
const settings = {
...initialSettings, // Keep other settings
system_message: ''
};
// Save settings
saveSettings(settings, resetSystemPromptButton, 'System prompt reset to default');
// Show error message
if (error.status === 400) {
Toast.error('Goodbye channel not configured. Please set a goodbye channel first.');
} else {
Toast.error('Failed to test goodbye message. Please try again.');
}
})
.finally(() => {
// Remove loading state
testGoodbyeButton.disabled = false;
testGoodbyeButton.classList.remove('btn-loading');
});
});
}
}
/**
* Save settings to the API
* @param {Object} settings - The settings to save
* @param {HTMLElement} button - The button that triggered the save
* @param {string} successMessage - The message to show on success
*/
function saveSettings(settings, button, successMessage) {
// Save settings to API
API.post('/dashboard/api/settings', { settings }, button)
.then(response => {
console.log('Settings saved:', response);
Toast.success(successMessage);
})
.catch(error => {
console.error('Error saving settings:', error);
Toast.error('Failed to save settings. Please try again.');
});
}