feat(M9): synthèse IA — protocole, providers OpenAI/litellm, factory, tests

Synthèse optionnelle via SDK openai (client injectable, prompt système
FR, max 800 car., timeout 30 s, temp 0.3). Mode dégradé strict :
generate() ne lève jamais, retourne None si clé absente/timeout/erreur.
Provider litellm optionnel (extra ai-litellm) réutilisant le prompt
OpenAI. Factory get_synthesis_provider() selon AISettings. 23 tests
sans réseau, couverture synthesis/ 93%.

Co-authored-by: opencode/coder <coder@agents.invalid>
Co-authored-by: opencode/test-engineer <test-engineer@agents.invalid>
This commit is contained in:
2026-09-07 17:07:05 +02:00
parent 4d11ec9b22
commit 92833060e2
7 changed files with 845 additions and 1 deletions

View File

@@ -0,0 +1,45 @@
"""Factory de sélection du fournisseur de synthèse IA."""
from __future__ import annotations
import logging
from pronote_sync.config.settings import AISettings
from pronote_sync.synthesis.openai import OpenAISynthesisProvider
from pronote_sync.synthesis.provider import SynthesisProvider
logger = logging.getLogger(__name__)
__all__ = ["get_synthesis_provider", "SynthesisProvider", "OpenAISynthesisProvider"]
def get_synthesis_provider(settings: AISettings) -> SynthesisProvider | None:
"""Sélectionne le fournisseur de synthèse IA selon la configuration.
Retourne ``None`` lorsque la synthèse IA est désactivée ou qu'aucune clé
API n'est configurée. Pour le provider ``litellm``, le paquet ``litellm``
(extra ``ai-litellm``) est requis : s'il est absent, un avertissement est
journalisé et ``None`` est retourné.
:param settings: Paramètres IA.
:return: Le fournisseur configuré, ou ``None`` si désactivé ou sans clé API.
:rtype: SynthesisProvider | None
"""
if not settings.enabled:
return None
if not settings.api_key:
return None
api_key = settings.api_key.get_secret_value()
base_url = settings.base_url
model = settings.model or "gpt-4o-mini"
if settings.provider == "litellm":
try:
from pronote_sync.synthesis.litellm import LiteLLMSynthesisProvider
except ImportError:
logger.warning("Extra 'ai-litellm' requis pour le provider litellm")
return None
return LiteLLMSynthesisProvider(api_key=api_key, base_url=base_url, model=model)
return OpenAISynthesisProvider(api_key=api_key, base_url=base_url, model=model)