@@ -5829,6 +5829,8 @@ async function loadAdminIA() {
58295829 const r2 = await apiFetch('/api/v1/admin/config/ia');
58305830 if (!r2 || !r2.ok) return;
58315831 const d2 = await r2.json();
5832+ // v2.0.5 — cache global pour que adminShowIaConfig puisse récupérer default_model
5833+ window._iaProvidersCache = d2.all_providers || [];
58325834 const provBox = document.getElementById('admin-ia-providers');
58335835 if (!provBox || !d2.all_providers) return;
58345836 provBox.innerHTML = d2.all_providers.map(p => {
@@ -5851,30 +5853,58 @@ function adminShowIaConfig(providerId, providerLabel) {
58515853 if (!panel) return;
58525854 panel.style.display = 'block';
58535855 panel.scrollIntoView({behavior:'smooth', block:'nearest'});
5856+
5857+ // v2.0.5 — Récupérer le modèle par défaut du fournisseur depuis la config exposée
5858+ let defaultModel = '';
5859+ try {
5860+ const all = window._iaProvidersCache || [];
5861+ const meta = all.find(p => p.id === providerId);
5862+ if (meta && meta.default_model) defaultModel = meta.default_model;
5863+ } catch(e) {}
5864+
5865+ const isLocal = providerId === 'ollama' || providerId === 'openai_compat';
58545866 panel.innerHTML =
58555867 '<div style="font-family:var(--mono);font-size:11px;font-weight:700;margin-bottom:10px">⚙ Configurer : ' + providerLabel + '</div>' +
5856- '<p style="font-family:var(--mono);font-size:10px;color:var(--muted);margin-bottom:10px">' +
5857- 'Pour activer ce fournisseur, définir les variables d\'environnement suivantes avant de démarrer SCRIBE :' +
5858- '</p>' +
5859- '<div style="background:var(--surface3);border-radius:4px;padding:10px;font-family:var(--mono);font-size:10px;line-height:2">' +
5860- '<div>export <strong>SCRIBE_IA_PROVIDER</strong>=' + providerId + '</div>' +
5861- '<div>export <strong>SCRIBE_IA_KEY</strong>=<em>votre-clé-api</em></div>' +
5862- '<div>export <strong>SCRIBE_IA_MODEL</strong>=<em>nom-du-modèle (optionnel)</em></div>' +
5863- '</div>' +
5864- '<div id="ia-config-key-section" style="margin-top:12px">' +
5865- '<label style="font-family:var(--mono);font-size:9px;color:var(--muted);letter-spacing:1px;display:block;margin-bottom:4px">CLÉ API (sauvegardée en variable d\'env temporaire)</label>' +
5866- '<div style="display:flex;gap:8px">' +
5867- '<input type="password" id="ia-config-key-input" placeholder="sk-... ou clé API" style="flex:1;font-family:var(--mono);font-size:10px;padding:6px 8px;background:var(--surface2);border:1px solid var(--border2);border-radius:4px;color:var(--text)">' +
5868- '<button onclick="adminSaveIaKey("' + providerId + '")" style="font-family:var(--mono);font-size:10px;padding:6px 14px;background:#003189;color:#fff;border:none;border-radius:4px;cursor:pointer">Tester</button>' +
5868+ '<div id="ia-config-key-section">' +
5869+ '<label style="font-family:var(--mono);font-size:9px;color:var(--muted);letter-spacing:1px;display:block;margin-bottom:4px">' +
5870+ 'CLÉ API' + (isLocal ? ' (optionnelle pour fournisseur local)' : ' (obligatoire)') + '</label>' +
5871+ '<input type="password" id="ia-config-key-input" placeholder="sk-... ou clé API" autocomplete="off" ' +
5872+ 'style="width:100%;font-family:var(--mono);font-size:10px;padding:6px 8px;background:var(--surface2);' +
5873+ 'border:1px solid var(--border2);border-radius:4px;color:var(--text);box-sizing:border-box;margin-bottom:10px">' +
5874+ '<label style="font-family:var(--mono);font-size:9px;color:var(--muted);letter-spacing:1px;display:block;margin-bottom:4px">' +
5875+ 'MODÈLE (optionnel — laisser vide pour le défaut)</label>' +
5876+ '<input type="text" id="ia-config-model-input" placeholder="' + (defaultModel || 'défaut') + '" ' +
5877+ 'style="width:100%;font-family:var(--mono);font-size:10px;padding:6px 8px;background:var(--surface2);' +
5878+ 'border:1px solid var(--border2);border-radius:4px;color:var(--text);box-sizing:border-box;margin-bottom:10px">' +
5879+ (isLocal ?
5880+ '<label style="font-family:var(--mono);font-size:9px;color:var(--muted);letter-spacing:1px;display:block;margin-bottom:4px">' +
5881+ 'URL DU SERVEUR LOCAL (optionnel)</label>' +
5882+ '<input type="text" id="ia-config-url-input" placeholder="http://localhost:11434/v1/chat/completions" ' +
5883+ 'style="width:100%;font-family:var(--mono);font-size:10px;padding:6px 8px;background:var(--surface2);' +
5884+ 'border:1px solid var(--border2);border-radius:4px;color:var(--text);box-sizing:border-box;margin-bottom:10px">'
5885+ : '') +
5886+ '<div style="display:flex;gap:8px;margin-top:6px;flex-wrap:wrap">' +
5887+ '<button onclick="adminTestIaKey("' + providerId + '")" ' +
5888+ 'style="font-family:var(--mono);font-size:10px;padding:8px 14px;background:transparent;color:var(--text);' +
5889+ 'border:1px solid var(--border2);border-radius:4px;cursor:pointer">🧪 Tester la clé</button>' +
5890+ '<button onclick="adminSaveIaConfig("' + providerId + '")" ' +
5891+ 'style="font-family:var(--mono);font-size:10px;padding:8px 18px;background:#003189;color:#fff;' +
5892+ 'border:none;border-radius:4px;cursor:pointer;font-weight:700">💾 Enregistrer & activer</button>' +
5893+ '<button onclick="adminResetIaConfig()" ' +
5894+ 'style="font-family:var(--mono);font-size:10px;padding:8px 14px;background:transparent;color:#f87171;' +
5895+ 'border:1px solid #f87171;border-radius:4px;cursor:pointer;margin-left:auto" ' +
5896+ 'title="Supprime la clé sauvegardée et revient aux variables d\'environnement">' +
5897+ '🗑 Supprimer la config sauvegardée</button>' +
58695898 '</div>' +
5870- '<div id="ia-config-result" style="font-family:var(--mono);font-size:10px;margin-top:6px "></div>' +
5899+ '<div id="ia-config-result" style="font-family:var(--mono);font-size:10px;margin-top:10px "></div>' +
58715900 '</div>';
58725901}
58735902
5874- async function adminSaveIaKey(providerId) {
5903+ // v2.0.5 — Tester sans enregistrer (renommé pour clarté)
5904+ async function adminTestIaKey(providerId) {
58755905 const key = document.getElementById('ia-config-key-input')?.value?.trim();
58765906 const res = document.getElementById('ia-config-result');
5877- if (!key) { if(res) { res.style.color='#fbbf24'; res.textContent='⚠ Saisir une clé API'; } return; }
5907+ if (!key) { if(res) { res.style.color='#fbbf24'; res.textContent='⚠ Saisir une clé API à tester '; } return; }
58785908 if(res) { res.style.color='var(--muted)'; res.textContent='⏳ Test de connexion…'; }
58795909 try {
58805910 const r = await apiFetch('/api/v1/admin/config/ia/test', {
@@ -5884,13 +5914,73 @@ async function adminSaveIaKey(providerId) {
58845914 });
58855915 const d = await r.json();
58865916 if (d.ok) {
5887- if(res) { res.style.color='#4ade80'; res.textContent='✓ Connexion OK — ' + (d.message||''); }
5917+ if(res) { res.style.color='#4ade80'; res.textContent='✓ Connexion OK — ' + (d.message||'') + ' · La clé n\'est PAS encore enregistrée, cliquez sur 💾 Enregistrer pour l\'activer'; }
5918+ } else {
5919+ if(res) { res.style.color='#f87171'; res.textContent='✗ ' + (d.detail||d.message||'Erreur'); }
5920+ }
5921+ } catch(e) { if(res) { res.style.color='#f87171'; res.textContent='Erreur réseau : ' + e.message; } }
5922+ }
5923+
5924+ // v2.0.5 — Enregistrer la config IA (avec persistance + reload à chaud)
5925+ async function adminSaveIaConfig(providerId) {
5926+ const key = document.getElementById('ia-config-key-input')?.value?.trim() || '';
5927+ const model = document.getElementById('ia-config-model-input')?.value?.trim() || '';
5928+ const url = document.getElementById('ia-config-url-input')?.value?.trim() || '';
5929+ const res = document.getElementById('ia-config-result');
5930+
5931+ const isLocal = providerId === 'ollama' || providerId === 'openai_compat';
5932+ if (!isLocal && !key) {
5933+ if(res) { res.style.color='#fbbf24'; res.textContent='⚠ Clé API obligatoire pour ce fournisseur'; }
5934+ return;
5935+ }
5936+
5937+ if(res) { res.style.color='var(--muted)'; res.textContent='⏳ Enregistrement…'; }
5938+ try {
5939+ const r = await apiFetch('/api/v1/admin/config/ia', {
5940+ method: 'POST',
5941+ headers: {'Content-Type':'application/json'},
5942+ body: JSON.stringify({provider: providerId, api_key: key, model: model, base_url: url})
5943+ });
5944+ const d = await r.json();
5945+ if (d.ok) {
5946+ if(res) {
5947+ res.style.color='#4ade80';
5948+ res.textContent='✓ ' + (d.message || 'Config IA enregistrée et activée');
5949+ }
5950+ // Vider le champ clé pour pas qu'elle traîne en clair dans le DOM
5951+ const keyInput = document.getElementById('ia-config-key-input');
5952+ if (keyInput) keyInput.value = '';
5953+ // Refresh du panneau actif après 800ms
5954+ setTimeout(() => loadAdminIA(), 800);
5955+ } else {
5956+ if(res) { res.style.color='#f87171'; res.textContent='✗ ' + (d.detail||d.message||'Erreur enregistrement'); }
5957+ }
5958+ } catch(e) { if(res) { res.style.color='#f87171'; res.textContent='Erreur réseau : ' + e.message; } }
5959+ }
5960+
5961+ // v2.0.5 — Supprimer la config IA persistée
5962+ async function adminResetIaConfig() {
5963+ if (!confirm('Supprimer la configuration IA enregistrée ?\n\nL\'instance reviendra aux valeurs des variables d\'environnement (ou aux valeurs par défaut).')) return;
5964+ const res = document.getElementById('ia-config-result');
5965+ if(res) { res.style.color='var(--muted)'; res.textContent='⏳ Suppression…'; }
5966+ try {
5967+ const r = await apiFetch('/api/v1/admin/config/ia', {method: 'DELETE'});
5968+ const d = await r.json();
5969+ if (d.ok) {
5970+ if(res) { res.style.color='#4ade80'; res.textContent='✓ ' + (d.message || 'Config supprimée'); }
5971+ setTimeout(() => loadAdminIA(), 800);
58885972 } else {
58895973 if(res) { res.style.color='#f87171'; res.textContent='✗ ' + (d.detail||d.message||'Erreur'); }
58905974 }
58915975 } catch(e) { if(res) { res.style.color='#f87171'; res.textContent='Erreur réseau : ' + e.message; } }
58925976}
58935977
5978+ // v2.0.5 — Stub conservé pour compatibilité descendante (au cas où des handlers
5979+ // onclick="adminSaveIaKey(...)" subsistent dans du DOM ancien). Redirige vers test.
5980+ async function adminSaveIaKey(providerId) {
5981+ return adminTestIaKey(providerId);
5982+ }
5983+
58945984async function loadAdminRouting() {
58955985 const box = document.getElementById('admin-routing-info');
58965986 if (!box) return;
0 commit comments