diff --git a/app/routers/agent.py b/app/routers/agent.py index 5136411..16b454f 100644 --- a/app/routers/agent.py +++ b/app/routers/agent.py @@ -850,6 +850,7 @@ async def update_provider_config(request: Request): model=(body.get("model") or "").strip() or None, api_key=body.get("api_key"), api_base=(body.get("api_base") or "").strip() or None, + clear_keys=(provider == "offline"), ) llm = LLMClient() return { diff --git a/app/services/llm_config.py b/app/services/llm_config.py index 9a2dbb4..1f249c4 100644 --- a/app/services/llm_config.py +++ b/app/services/llm_config.py @@ -80,7 +80,8 @@ def get_llm_config() -> dict: def set_llm_config(*, provider: str | None = None, model: str | None = None, - api_key: str | None = None, api_base: str | None = None) -> dict: + api_key: str | None = None, api_base: str | None = None, + clear_keys: bool = False) -> dict: """Upsert the runtime LLM config row (id=1) and return the new effective config. An empty `api_key`/`api_base` keeps the stored value (so an admin can tweak @@ -103,6 +104,12 @@ def set_llm_config(*, provider: str | None = None, model: str | None = None, cfg["last_error"] = "" if api_base is not None and api_base.strip(): cfg["api_base"] = api_base.strip() + if clear_keys: + cfg["api_key"] = "" + cfg["api_base"] = "" + cfg["verified"] = 0 + cfg["verified_model"] = "" + cfg["last_error"] = "" with get_conn() as conn: conn.execute( diff --git a/app/templates/settings.html b/app/templates/settings.html index fdf619b..f5f1324 100644 --- a/app/templates/settings.html +++ b/app/templates/settings.html @@ -600,6 +600,7 @@ 🔌 Tester la connexion Test… +
@@ -1107,6 +1108,8 @@ document.addEventListener('alpine:init', function() { finally { f.testing = false; } }, async deleteUserKey(id) { + var pname = id.charAt(0).toUpperCase() + id.slice(1); + if (!confirm('Supprimer la clé API pour ' + pname + ' ?\nLe fournisseur ne sera plus disponible dans le panneau Agent.')) return; var f = this.keyForm(id); f.deleting = true; f.msg = ''; f.ok = false; try { @@ -1185,6 +1188,31 @@ document.addEventListener('alpine:init', function() { } catch(e) { this.llmMsg = 'Erreur réseau'; } finally { this.llmSaving = false; } }, + async resetGlobalLlm() { + if (!confirm("Réinitialiser le fournisseur par défaut à « hors-ligne » ?\nTous les utilisateurs perdront l'accès au fournisseur IA actuel.")) return; + this.llmSaving = true; + this.llmMsg = ''; this.llmMsgOk = false; + try { + var r = await this.adminFetch('/api/agent/providers', { + method: 'PATCH', + headers: {'Content-Type':'application/json'}, + body: JSON.stringify({provider: 'offline', model: '', api_key: '', api_base: ''}) + }); + var d = await r.json(); + if (r.ok) { + this.llmForm = {provider: 'offline', model: '', api_key: '', api_base: ''}; + this.llmHasKey = false; + this.llmDefaultProvider = 'offline'; + this.llmProviderModels = []; + this.llmMsgOk = true; + this.llmMsg = 'Fournisseur réinitialisé : mode hors-ligne actif.'; + this.syncLlmStatus(); + } else { + this.llmMsg = d.detail || 'Erreur lors de la réinitialisation'; + } + } catch(e) { this.llmMsg = 'Erreur réseau'; } + finally { this.llmSaving = false; } + }, async testLlm() { if (!this.llmForm.provider) return; this.llmTesting = true;