Améliorations sur l'utilisation de l'IA pour l'exploitation des PDF, que ce soit la partie cloud ou la partie ollama + montée en version
All checks were successful
Build & Push Images / build (brain) (push) Successful in 1m43s
Build & Push Images / build (core) (push) Successful in 1m51s
Build & Push Images / build-switcher (push) Successful in 26s
Build & Push Images / build (web) (push) Successful in 1m46s

This commit is contained in:
2026-06-11 01:31:24 +02:00
parent cff2ceb0b9
commit a1f3b9b796
21 changed files with 287 additions and 48 deletions

View File

@@ -20,7 +20,7 @@ import httpx
from app.core.config import Settings
from app.domain.models import ChatMessage
from app.domain.ports import LLMProviderError
from app.domain.ports import LLMGenerationTimeout, LLMProviderError
logger = logging.getLogger(__name__)
@@ -95,7 +95,7 @@ class GeminiLLMProvider:
try:
return await asyncio.wait_for(_collect(), timeout=self._timeout)
except asyncio.TimeoutError as exc:
raise LLMProviderError(
raise LLMGenerationTimeout(
f"Erreur Gemini : génération non terminée en {self._timeout}s. Réduisez la "
"taille des morceaux d'import ou augmentez le timeout."
) from exc
@@ -130,6 +130,10 @@ class GeminiLLMProvider:
}
if temperature is not None:
body["temperature"] = temperature
# Mode JSON natif (supporté par l'endpoint OpenAI-compatible de Gemini) :
# supprime fences ```json et JSON invalide, principale cause de morceaux ignorés.
if output_format == "json":
body["response_format"] = {"type": "json_object"}
async with httpx.AsyncClient(timeout=self._timeout) as client:
try:

View File

@@ -20,7 +20,7 @@ import httpx
from app.core.config import Settings
from app.domain.models import ChatMessage
from app.domain.ports import LLMProviderError
from app.domain.ports import LLMGenerationTimeout, LLMProviderError
logger = logging.getLogger(__name__)
@@ -101,7 +101,7 @@ class MistralLLMProvider:
try:
return await asyncio.wait_for(_collect(), timeout=self._timeout)
except asyncio.TimeoutError as exc:
raise LLMProviderError(
raise LLMGenerationTimeout(
f"Erreur Mistral : génération non terminée en {self._timeout}s. Réduisez la "
"taille des morceaux d'import, augmentez le timeout, ou changez de modèle."
) from exc
@@ -136,6 +136,11 @@ class MistralLLMProvider:
}
if temperature is not None:
body["temperature"] = temperature
# Mode JSON natif : TOUS les modèles Mistral le supportent → plus de fences
# ```json ni de JSON invalide (retours à la ligne bruts dans les chaînes),
# principale cause de morceaux d'import ignorés.
if output_format == "json":
body["response_format"] = {"type": "json_object"}
async with httpx.AsyncClient(timeout=self._timeout) as client:
try:

View File

@@ -11,7 +11,7 @@ import httpx
from app.core.config import Settings
from app.domain.models import ChatMessage
from app.domain.ports import LLMProviderError
from app.domain.ports import LLMGenerationTimeout, LLMProviderError
class OllamaLLMProvider:
@@ -71,6 +71,22 @@ class OllamaLLMProvider:
raise LLMProviderError(
f"Ollama HTTP {response.status_code} : {err_msg.strip()[:500]}"
)
except httpx.ConnectTimeout as exc:
# Serveur injoignable : erreur d'infrastructure, pas de lenteur.
raise LLMProviderError(
f"Erreur lors de l'appel à Ollama : {exc}"
) from exc
except httpx.TimeoutException as exc:
# `stream: False` → le read-timeout court jusqu'à la réponse COMPLÈTE,
# donc le dépasser = génération trop lente pour la sortie demandée
# (fréquent : modèle local modeste + gros morceau d'import à réécrire).
# Type dédié → pas de retry à l'identique ; l'import re-découpe le
# morceau en deux moitiés (sortie 2× plus courte) à la place.
raise LLMGenerationTimeout(
f"Erreur Ollama : génération non terminée en {self._timeout}s. Réduisez "
"la taille des morceaux d'import, augmentez le timeout, ou utilisez un "
"modèle plus rapide."
) from exc
except httpx.HTTPError as exc:
raise LLMProviderError(
f"Erreur lors de l'appel à Ollama : {exc}"

View File

@@ -22,7 +22,7 @@ from app.core.config import Settings
from app.domain.models import ChatMessage
logger = logging.getLogger(__name__)
from app.domain.ports import LLMProviderError
from app.domain.ports import LLMGenerationTimeout, LLMProviderError
_API_URL = "https://openrouter.ai/api/v1/chat/completions"
@@ -113,7 +113,7 @@ class OpenRouterLLMProvider:
try:
return await asyncio.wait_for(_collect(), timeout=self._timeout)
except asyncio.TimeoutError as exc:
raise LLMProviderError(
raise LLMGenerationTimeout(
f"Erreur {provider} : génération non terminée en {self._timeout}s. Réduisez la "
"taille des morceaux d'import, augmentez le timeout, ou changez de modèle."
) from exc