Live AI provider/model switching without restart
CI / Lint & Format (push) Failing after 8s
CI / Tests (push) Has been skipped
CI / Security Scan (push) Failing after 8s
CI / Docker Build (push) Has been skipped

Backend:
- RuntimeAIConfig singleton: mutable in-memory overrides for provider/model
- PATCH /admin/api/ai/config: change active provider/model on the fly
- GET /admin/api/ai/config: read current runtime state
- ai_vision.py: uses runtime_ai_config before falling back to settings
- health/status endpoints reflect runtime overrides

Frontend:
- 'Définir comme actif' button in AI config section
- Live feedback message on save
This commit is contained in:
2026-06-25 11:07:17 -04:00
parent 7dd26ea636
commit 92cf23dbb3
6 changed files with 216 additions and 14 deletions
+6 -5
View File
@@ -22,6 +22,7 @@ from google.genai import types
from app.config import settings
from app.services.storage_backend import get_storage_backend
from app.services.runtime_config import runtime_ai_config
logger = logging.getLogger(__name__)
@@ -128,7 +129,7 @@ async def _generate_gemini(
contents.append(types.Part.from_bytes(data=image_bytes, mime_type=media_type))
contents.append(prompt)
model = model_override or settings.GEMINI_MODEL
model = model_override or runtime_ai_config.model or settings.GEMINI_MODEL
async def _call():
return await asyncio.wait_for(
@@ -165,7 +166,7 @@ async def _generate_openrouter(
logger.warning("ai.openrouter.no_key")
return {"text": None, "usage": (None, None)}
model = model_override or settings.OPENROUTER_MODEL
model = model_override or runtime_ai_config.model or settings.OPENROUTER_MODEL
headers = {
"Authorization": f"Bearer {settings.OPENROUTER_API_KEY}",
@@ -233,7 +234,7 @@ async def _generate(
model_override: Optional[str] = None,
) -> dict:
"""Dispatcher vers le bon provider, avec override optionnel par client."""
provider = provider_override or settings.AI_PROVIDER.lower()
provider = provider_override or runtime_ai_config.provider or settings.AI_PROVIDER.lower()
logger.info("ai.generate", extra={"provider": provider})
if provider == "openrouter":
@@ -289,8 +290,8 @@ async def analyze_image(
if not settings.AI_ENABLED:
return {}
active_provider = provider_override or settings.AI_PROVIDER
active_model = model_override or (
active_provider = provider_override or runtime_ai_config.provider or settings.AI_PROVIDER
active_model = model_override or runtime_ai_config.model or (
settings.OPENROUTER_MODEL if active_provider == "openrouter"
else settings.GEMINI_MODEL
)