From bbf5fd1c3a4b756148f6665aec628e15331bdde6 Mon Sep 17 00:00:00 2001 From: pironantoine <57062554-pironantoine@users.noreply.replit.com> Date: Sat, 4 Apr 2026 06:33:43 +0000 Subject: [PATCH] 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 --- artifacts/flask-api/ai_agent.py | 28 +++++++++++++------ .../voix-du-peuple/src/pages/transparence.tsx | 8 +++--- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/artifacts/flask-api/ai_agent.py b/artifacts/flask-api/ai_agent.py index 4401ef2..9c48a6f 100644 --- a/artifacts/flask-api/ai_agent.py +++ b/artifacts/flask-api/ai_agent.py @@ -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}, { diff --git a/artifacts/voix-du-peuple/src/pages/transparence.tsx b/artifacts/voix-du-peuple/src/pages/transparence.tsx index b97ddc8..d3fd2bf 100644 --- a/artifacts/voix-du-peuple/src/pages/transparence.tsx +++ b/artifacts/voix-du-peuple/src/pages/transparence.tsx @@ -81,7 +81,7 @@ export default function Transparence() {

Modèle utilisé

- OpenAI GPT-4o mini par défaut (configurable via la variable d'environnement OPENAI_FILTER_MODEL). 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 FILTER_MODEL). Le modèle est interrogé via l'API Mistral AI — aucun fine-tuning ni entraînement n'est effectué sur les contributions des utilisateurs.

@@ -153,7 +153,7 @@ export default function Transparence() {

Modèle utilisé

- OpenAI GPT-4o par défaut (configurable via OPENAI_SYNTHESIS_MODEL). Un modèle plus puissant est utilisé ici pour produire un résumé de meilleure qualité. + Mistral Large par défaut (configurable via SYNTHESIS_MODEL). Un modèle plus puissant est utilisé ici pour produire un résumé de meilleure qualité.

@@ -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" },