Refactor SRP : decoupage de main.py (Brain) en routers et du SettingsComponent (web)
Brain : main.py (1496 l.) reduit a l'assemblage (~95 l.) ; un router par responsabilite (generation, chat, tables, imports, notebooks, settings, models), factories DI dans api/deps.py, DTOs chat + mapping anti-corruption separes, auto-pull embeddings deplace en infrastructure. Chemins HTTP inchanges. Web : SettingsComponent (729 l.) recentre sur le formulaire (~330 l.) ; sous-composants standalone updates-section (MAJ + licence Patreon + switch canal) et ollama-model-manager (liste/pull/suppression de modeles). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
51
brain/app/infrastructure/ollama_model_installer.py
Normal file
51
brain/app/infrastructure/ollama_model_installer.py
Normal file
@@ -0,0 +1,51 @@
|
||||
"""Auto-installation du modèle d'embeddings Ollama au démarrage du Brain.
|
||||
|
||||
Adapter d'infrastructure : parle directement à l'API HTTP d'Ollama. Best-effort
|
||||
(Ollama peut être absent / la connexion limitée) — n'empêche jamais le démarrage.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
|
||||
import httpx
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def ensure_ollama_embedding_model(base_url: str, model: str) -> None:
|
||||
"""Télécharge `model` sur le serveur Ollama s'il n'y est pas déjà.
|
||||
|
||||
Attend qu'Ollama soit joignable (ordre de démarrage des conteneurs), puis
|
||||
vérifie la présence du modèle avant de le tirer.
|
||||
"""
|
||||
for attempt in range(10):
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10) as client:
|
||||
tags = await client.get(f"{base_url}/api/tags")
|
||||
tags.raise_for_status()
|
||||
names = [m.get("name", "") for m in tags.json().get("models", [])]
|
||||
if any(n == model or n.startswith(model + ":") for n in names):
|
||||
logger.info("Modèle d'embedding '%s' déjà présent.", model)
|
||||
return
|
||||
break # Ollama joignable, modèle absent → on tire (ci-dessous)
|
||||
except httpx.HTTPError:
|
||||
await asyncio.sleep(min(5 * (attempt + 1), 30))
|
||||
else:
|
||||
logger.warning(
|
||||
"Ollama injoignable au démarrage — modèle d'embedding '%s' non auto-installé "
|
||||
"(il sera tirable manuellement : ollama pull %s).", model, model)
|
||||
return
|
||||
|
||||
logger.info("Téléchargement automatique du modèle d'embedding '%s'…", model)
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=None) as client:
|
||||
async with client.stream("POST", f"{base_url}/api/pull", json={"name": model}) as resp:
|
||||
resp.raise_for_status()
|
||||
async for _line in resp.aiter_lines():
|
||||
pass # on draine la progression NDJSON jusqu'à la fin
|
||||
logger.info("Modèle d'embedding '%s' prêt.", model)
|
||||
except httpx.HTTPError as exc:
|
||||
logger.warning(
|
||||
"Auto-installation du modèle d'embedding '%s' échouée : %s "
|
||||
"(tirage manuel possible : ollama pull %s).", model, exc, model)
|
||||
Reference in New Issue
Block a user