Update AI models to use Mistral by default for better performance

Update backend AI agent to support Mistral API alongside OpenAI and Replit integrations. Default filter model changed to 'mistral-small-latest' and synthesis model to 'mistral-large-latest'. Frontend transparency page updated to reflect these changes and new configuration variables.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 923ae0e3-a363-4db8-b04a-e8baca2a1330
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Event-Id: ec257d30-4a6a-4c7b-85f5-c18945dba29f
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8af7d2ec-2cc3-4ece-8af3-9f071488d072/923ae0e3-a363-4db8-b04a-e8baca2a1330/qrVKaka
Replit-Helium-Checkpoint-Created: true
This commit is contained in:
pironantoine
2026-04-04 06:33:43 +00:00
parent b604e21f70
commit bbf5fd1c3a
2 changed files with 23 additions and 13 deletions
+19 -9
View File
@@ -1,6 +1,6 @@
"""
Agent IA pour le filtrage éthique et la synthèse démocratique.
Utilise les Intégrations IA de Replit (OpenAI proxy).
Supporte Mistral AI, OpenAI, et les intégrations Replit AI.
"""
import json
import os
@@ -10,25 +10,35 @@ from legal_framework import LEGAL_FILTER_PROMPT, SYNTHESIS_PROMPT
logger = logging.getLogger(__name__)
MISTRAL_BASE_URL = "https://api.mistral.ai/v1"
_client: OpenAI | None = None
def get_client() -> OpenAI:
"""
Supporte deux modes :
- Replit AI Integration : AI_INTEGRATIONS_OPENAI_BASE_URL + AI_INTEGRATIONS_OPENAI_API_KEY
- Auto-hébergement standard : OPENAI_API_KEY (+ OPENAI_BASE_URL optionnel pour proxy)
Supporte trois modes (par ordre de priorité) :
1. Replit AI Integration : AI_INTEGRATIONS_OPENAI_BASE_URL + AI_INTEGRATIONS_OPENAI_API_KEY
2. Mistral AI : MISTRAL_API_KEY (+ MISTRAL_BASE_URL optionnel)
3. OpenAI standard : OPENAI_API_KEY (+ OPENAI_BASE_URL optionnel)
"""
global _client
if _client is None:
replit_base = os.environ.get("AI_INTEGRATIONS_OPENAI_BASE_URL")
replit_key = os.environ.get("AI_INTEGRATIONS_OPENAI_API_KEY")
mistral_key = os.environ.get("MISTRAL_API_KEY")
mistral_base = os.environ.get("MISTRAL_BASE_URL", MISTRAL_BASE_URL)
std_key = os.environ.get("OPENAI_API_KEY")
std_base = os.environ.get("OPENAI_BASE_URL")
if replit_base and replit_key:
logger.info("Utilisation de l'intégration Replit AI")
_client = OpenAI(base_url=replit_base, api_key=replit_key)
elif mistral_key:
logger.info("Utilisation de l'API Mistral AI (%s)", mistral_base)
_client = OpenAI(base_url=mistral_base, api_key=mistral_key)
elif std_key:
logger.info("Utilisation de l'API OpenAI")
kwargs = {"api_key": std_key}
if std_base:
kwargs["base_url"] = std_base
@@ -36,7 +46,7 @@ def get_client() -> OpenAI:
else:
raise RuntimeError(
"Aucune clé IA configurée. "
"Définissez OPENAI_API_KEY dans le fichier .env "
"Définissez MISTRAL_API_KEY ou OPENAI_API_KEY dans le fichier .env, "
"ou configurez les intégrations Replit AI."
)
return _client
@@ -49,10 +59,10 @@ def filter_idea(content: str) -> dict:
"""
try:
client = get_client()
filter_model = os.environ.get("OPENAI_FILTER_MODEL", "gpt-4o-mini")
filter_model = os.environ.get("FILTER_MODEL", os.environ.get("OPENAI_FILTER_MODEL", "mistral-small-latest"))
response = client.chat.completions.create(
model=filter_model,
max_completion_tokens=300,
max_tokens=300,
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": LEGAL_FILTER_PROMPT},
@@ -112,11 +122,11 @@ def synthesize_ideas(ideas: list[str]) -> str:
)
try:
client = get_client()
synthesis_model = os.environ.get("OPENAI_SYNTHESIS_MODEL", "gpt-4o")
synthesis_model = os.environ.get("SYNTHESIS_MODEL", os.environ.get("OPENAI_SYNTHESIS_MODEL", "mistral-large-latest"))
ideas_text = "\n".join(f"{i + 1}. {idea}" for i, idea in enumerate(ideas))
response = client.chat.completions.create(
model=synthesis_model,
max_completion_tokens=1200,
max_tokens=1200,
messages=[
{"role": "system", "content": SYNTHESIS_PROMPT},
{
@@ -81,7 +81,7 @@ export default function Transparence() {
<div className="bg-muted/40 border border-border/50 p-5 space-y-2">
<p className="font-mono text-xs font-semibold uppercase tracking-widest text-primary">Modèle utilisé</p>
<p className="text-foreground/90 text-sm leading-relaxed">
OpenAI GPT-4o mini par défaut (configurable via la variable d'environnement <code className="bg-muted px-1 py-0.5 rounded text-xs">OPENAI_FILTER_MODEL</code>). Le modèle est interrogé via l'API OpenAI — aucun fine-tuning ni entraînement n'est effectué sur les contributions des utilisateurs.
Mistral Small par défaut (configurable via la variable d'environnement <code className="bg-muted px-1 py-0.5 rounded text-xs">FILTER_MODEL</code>). Le modèle est interrogé via l'API Mistral AI — aucun fine-tuning ni entraînement n'est effectué sur les contributions des utilisateurs.
</p>
</div>
@@ -153,7 +153,7 @@ export default function Transparence() {
<div className="bg-muted/40 border border-border/50 p-5 space-y-2">
<p className="font-mono text-xs font-semibold uppercase tracking-widest text-primary">Modèle utilisé</p>
<p className="text-foreground/90 text-sm leading-relaxed">
OpenAI GPT-4o par défaut (configurable via <code className="bg-muted px-1 py-0.5 rounded text-xs">OPENAI_SYNTHESIS_MODEL</code>). Un modèle plus puissant est utilisé ici pour produire un résumé de meilleure qualité.
Mistral Large par défaut (configurable via <code className="bg-muted px-1 py-0.5 rounded text-xs">SYNTHESIS_MODEL</code>). Un modèle plus puissant est utilisé ici pour produire un résumé de meilleure qualité.
</p>
</div>
@@ -272,8 +272,8 @@ export default function Transparence() {
{ label: "Backend", val: "Python / Flask" },
{ label: "Base de données", val: "PostgreSQL" },
{ label: "Frontend", val: "React + Vite" },
{ label: "IA de modération", val: "OpenAI GPT-4o mini (défaut)" },
{ label: "IA de synthèse", val: "OpenAI GPT-4o (défaut)" },
{ label: "IA de modération", val: "Mistral small (défaut) configurable via FILTER_MODEL" },
{ label: "IA de synthèse", val: "Mistral large (défaut) configurable via SYNTHESIS_MODEL" },
{ label: "Données personnelles", val: "Aucune (pseudonyme facultatif uniquement)" },
{ label: "Trackers / publicité", val: "Aucun" },
{ label: "Inscription requise", val: "Non" },