/** * JavaScript pour la gestion des clés API du chatbot */ // État global let currentProvider = null; let editMode = false; // Helper URLs const API_HELP_URLS = { 'gemini': 'https://aistudio.google.com/apikey', 'mistral': 'https://console.mistral.ai/api-keys/', 'openai': 'https://platform.openai.com/api-keys' }; // ========== Modal Management ========== function openAddKeyModal(provider = null) { const modal = document.getElementById('keyModal'); const title = document.getElementById('modalTitle'); const form = document.getElementById('keyForm'); const providerSelect = document.getElementById('provider'); const testResult = document.getElementById('testResult'); // Reset form form.reset(); testResult.style.display = 'none'; document.getElementById('keyAction').value = 'add'; editMode = false; // Important : activer le select AVANT de définir la valeur providerSelect.disabled = false; // Pre-select provider if provided if (provider) { providerSelect.value = provider; providerSelect.dispatchEvent(new Event('change')); // Trigger updateModelsList } title.textContent = 'Ajouter une clé API'; modal.classList.add('show'); } function editKey(provider) { currentProvider = provider; editMode = true; // Récupérer les infos de la clé fetch(`chatbot_api_ajax.php?action=get&provider=${provider}`) .then(response => response.json()) .then(data => { if (data.success) { const modal = document.getElementById('keyModal'); const title = document.getElementById('modalTitle'); const form = document.getElementById('keyForm'); const providerSelect = document.getElementById('provider'); const modelSelect = document.getElementById('model_default'); const testResult = document.getElementById('testResult'); testResult.style.display = 'none'; document.getElementById('keyAction').value = 'edit'; // Remplir le formulaire providerSelect.value = provider; providerSelect.disabled = true; updateModelsList(); // Attendre que la liste des modèles soit chargée setTimeout(() => { modelSelect.value = data.data.model_default; if (data.data.quota_max) { document.getElementById('set_quota').checked = true; document.getElementById('quota_max').value = data.data.quota_max; toggleQuotaInput(); } }, 100); title.textContent = `Modifier la clé ${provider}`; modal.classList.add('show'); } else { showToast(data.error || 'Erreur lors du chargement', 'error'); } }) .catch(error => { console.error('Error:', error); showToast('Erreur de connexion', 'error'); }); } function closeKeyModal() { const modal = document.getElementById('keyModal'); modal.classList.remove('show'); currentProvider = null; editMode = false; } // ========== Form Handling ========== function updateModelsList() { const provider = document.getElementById('provider').value; const modelSelect = document.getElementById('model_default'); const keyHelp = document.getElementById('keyHelp'); // Clear current options modelSelect.innerHTML = ''; if (!provider) { keyHelp.innerHTML = ''; return; } // Populate models for selected provider if (models[provider]) { models[provider].forEach(model => { const option = document.createElement('option'); option.value = model.model_id; option.textContent = model.display_name; if (model.recommended) { option.textContent += ' ⭐'; } modelSelect.appendChild(option); }); // Auto-select first recommended model const recommended = models[provider].find(m => m.recommended); if (recommended) { modelSelect.value = recommended.model_id; } } // Update help text if (API_HELP_URLS[provider]) { keyHelp.innerHTML = `💡 Obtenir une clé : ${API_HELP_URLS[provider]}`; } else { keyHelp.innerHTML = ''; } } function toggleQuotaInput() { const checkbox = document.getElementById('set_quota'); const quotaGroup = document.getElementById('quotaGroup'); quotaGroup.style.display = checkbox.checked ? 'block' : 'none'; } function toggleKeyVisibility() { const input = document.getElementById('api_key'); const button = event.target; if (input.type === 'password') { input.type = 'text'; button.textContent = '🙈'; } else { input.type = 'password'; button.textContent = '👁️'; } } // ========== Form Submission ========== document.getElementById('keyForm').addEventListener('submit', function(e) { e.preventDefault(); const formData = new FormData(this); formData.append('action', 'save'); // Show loading const submitBtn = this.querySelector('button[type="submit"]'); const originalText = submitBtn.innerHTML; submitBtn.innerHTML = '⏳ Enregistrement...'; submitBtn.disabled = true; fetch('chatbot_api_ajax.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { showToast(data.message || 'Clé enregistrée avec succès', 'success'); closeKeyModal(); // Reload page to show updated keys setTimeout(() => { window.location.reload(); }, 1000); } else { showToast(data.error || 'Erreur lors de l\'enregistrement', 'error'); } }) .catch(error => { console.error('Error:', error); showToast('Erreur de connexion', 'error'); }) .finally(() => { submitBtn.innerHTML = originalText; submitBtn.disabled = false; }); }); // ========== Test Connection ========== function testKeyBeforeSave() { const provider = document.getElementById('provider').value; const apiKey = document.getElementById('api_key').value; const model = document.getElementById('model_default').value; if (!provider || !apiKey || !model) { showToast('Veuillez remplir tous les champs obligatoires', 'error'); return; } testConnectionWithParams(provider, apiKey, model); } function testConnection(provider) { testConnectionWithParams(provider, null, null); } function testConnectionWithParams(provider, apiKey = null, model = null) { const testResult = document.getElementById('testResult'); testResult.style.display = 'block'; testResult.className = 'test-result'; testResult.innerHTML = '🔄 Test en cours...'; const formData = new FormData(); formData.append('action', 'test'); formData.append('provider', provider); if (apiKey) formData.append('api_key', apiKey); if (model) formData.append('model', model); fetch('chatbot_api_ajax.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { testResult.className = 'test-result success'; testResult.innerHTML = `✅ ${data.message}
Latence: ${data.latency_ms}ms`; } else { testResult.className = 'test-result error'; testResult.innerHTML = `❌ ${data.message}`; } }) .catch(error => { console.error('Error:', error); testResult.className = 'test-result error'; testResult.innerHTML = '❌ Erreur de connexion au serveur'; }); } // ========== Delete Key ========== function deleteKey(provider) { if (!confirm(`Êtes-vous sûr de vouloir supprimer la clé ${provider} ?\n\nCette action est irréversible.`)) { return; } const formData = new FormData(); formData.append('action', 'delete'); formData.append('provider', provider); fetch('chatbot_api_ajax.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { showToast('Clé supprimée avec succès', 'success'); setTimeout(() => { window.location.reload(); }, 1000); } else { showToast(data.error || 'Erreur lors de la suppression', 'error'); } }) .catch(error => { console.error('Error:', error); showToast('Erreur de connexion', 'error'); }); } // ========== Set Default Provider ========== function setAsDefault(provider, model) { const formData = new FormData(); formData.append('action', 'set_default'); formData.append('provider', provider); formData.append('model', model); fetch('chatbot_api_ajax.php', { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { if (data.success) { showToast(data.message || 'Provider par défaut mis à jour', 'success'); setTimeout(() => { window.location.reload(); }, 1000); } else { showToast(data.error || 'Erreur', 'error'); } }) .catch(error => { console.error('Error:', error); showToast('Erreur de connexion', 'error'); }); } // ========== Configure Ollama ========== function configureOllama() { const availableModels = models['ollama'] || []; if (availableModels.length === 0) { showToast('Aucun modèle Ollama disponible', 'error'); return; } // Créer une liste des modèles let modelOptions = ''; // Simple prompt const modelHtml = `

Choisir le modèle Ollama par défaut :

${modelOptions}
`; // Utiliser une confirm box simple pour l'instant // (dans une vraie app, utiliser le modal existant) const modal = document.getElementById('keyModal'); const modalContent = modal.querySelector('.modal-content'); const originalContent = modalContent.innerHTML; modalContent.innerHTML = `

Choisir le modèle Ollama à utiliser par défaut :

`; modal.classList.add('show'); } function saveOllamaConfig() { const select = document.getElementById('ollama-model-select'); const model = select.value; if (!model) { showToast('Veuillez sélectionner un modèle', 'error'); return; } setAsDefault('ollama', model); } // ========== Toast Notifications ========== function showToast(message, type = 'info') { const container = document.getElementById('toast-container'); const toast = document.createElement('div'); toast.className = `toast ${type}`; const icons = { 'success': '✅', 'error': '❌', 'warning': '⚠️', 'info': 'ℹ️' }; toast.innerHTML = ` ${icons[type] || icons.info} ${message} `; container.appendChild(toast); // Auto-remove after 4 seconds setTimeout(() => { toast.style.opacity = '0'; toast.style.transform = 'translateX(100%)'; setTimeout(() => toast.remove(), 300); }, 4000); } // ========== Close modal on outside click ========== document.getElementById('keyModal').addEventListener('click', function(e) { if (e.target === this) { closeKeyModal(); } }); // ========== Keyboard shortcuts ========== document.addEventListener('keydown', function(e) { // ESC to close modal if (e.key === 'Escape') { const modal = document.getElementById('keyModal'); if (modal.classList.contains('show')) { closeKeyModal(); } } }); // ========== Initialize ========== console.log('✅ Chatbot Settings JS loaded'); console.log('Available models:', models);