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:
@@ -1,6 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
Agent IA pour le filtrage éthique et la synthèse démocratique.
|
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 json
|
||||||
import os
|
import os
|
||||||
@@ -10,25 +10,35 @@ from legal_framework import LEGAL_FILTER_PROMPT, SYNTHESIS_PROMPT
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
MISTRAL_BASE_URL = "https://api.mistral.ai/v1"
|
||||||
|
|
||||||
_client: OpenAI | None = None
|
_client: OpenAI | None = None
|
||||||
|
|
||||||
|
|
||||||
def get_client() -> OpenAI:
|
def get_client() -> OpenAI:
|
||||||
"""
|
"""
|
||||||
Supporte deux modes :
|
Supporte trois modes (par ordre de priorité) :
|
||||||
- Replit AI Integration : AI_INTEGRATIONS_OPENAI_BASE_URL + AI_INTEGRATIONS_OPENAI_API_KEY
|
1. 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)
|
2. Mistral AI : MISTRAL_API_KEY (+ MISTRAL_BASE_URL optionnel)
|
||||||
|
3. OpenAI standard : OPENAI_API_KEY (+ OPENAI_BASE_URL optionnel)
|
||||||
"""
|
"""
|
||||||
global _client
|
global _client
|
||||||
if _client is None:
|
if _client is None:
|
||||||
replit_base = os.environ.get("AI_INTEGRATIONS_OPENAI_BASE_URL")
|
replit_base = os.environ.get("AI_INTEGRATIONS_OPENAI_BASE_URL")
|
||||||
replit_key = os.environ.get("AI_INTEGRATIONS_OPENAI_API_KEY")
|
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_key = os.environ.get("OPENAI_API_KEY")
|
||||||
std_base = os.environ.get("OPENAI_BASE_URL")
|
std_base = os.environ.get("OPENAI_BASE_URL")
|
||||||
|
|
||||||
if replit_base and replit_key:
|
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)
|
_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:
|
elif std_key:
|
||||||
|
logger.info("Utilisation de l'API OpenAI")
|
||||||
kwargs = {"api_key": std_key}
|
kwargs = {"api_key": std_key}
|
||||||
if std_base:
|
if std_base:
|
||||||
kwargs["base_url"] = std_base
|
kwargs["base_url"] = std_base
|
||||||
@@ -36,7 +46,7 @@ def get_client() -> OpenAI:
|
|||||||
else:
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Aucune clé IA configurée. "
|
"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."
|
"ou configurez les intégrations Replit AI."
|
||||||
)
|
)
|
||||||
return _client
|
return _client
|
||||||
@@ -49,10 +59,10 @@ def filter_idea(content: str) -> dict:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
client = get_client()
|
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(
|
response = client.chat.completions.create(
|
||||||
model=filter_model,
|
model=filter_model,
|
||||||
max_completion_tokens=300,
|
max_tokens=300,
|
||||||
response_format={"type": "json_object"},
|
response_format={"type": "json_object"},
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "system", "content": LEGAL_FILTER_PROMPT},
|
{"role": "system", "content": LEGAL_FILTER_PROMPT},
|
||||||
@@ -112,11 +122,11 @@ def synthesize_ideas(ideas: list[str]) -> str:
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
client = get_client()
|
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))
|
ideas_text = "\n".join(f"{i + 1}. {idea}" for i, idea in enumerate(ideas))
|
||||||
response = client.chat.completions.create(
|
response = client.chat.completions.create(
|
||||||
model=synthesis_model,
|
model=synthesis_model,
|
||||||
max_completion_tokens=1200,
|
max_tokens=1200,
|
||||||
messages=[
|
messages=[
|
||||||
{"role": "system", "content": SYNTHESIS_PROMPT},
|
{"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">
|
<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="font-mono text-xs font-semibold uppercase tracking-widest text-primary">Modèle utilisé</p>
|
||||||
<p className="text-foreground/90 text-sm leading-relaxed">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ export default function Transparence() {
|
|||||||
<div className="bg-muted/40 border border-border/50 p-5 space-y-2">
|
<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="font-mono text-xs font-semibold uppercase tracking-widest text-primary">Modèle utilisé</p>
|
||||||
<p className="text-foreground/90 text-sm leading-relaxed">
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -272,8 +272,8 @@ export default function Transparence() {
|
|||||||
{ label: "Backend", val: "Python / Flask" },
|
{ label: "Backend", val: "Python / Flask" },
|
||||||
{ label: "Base de données", val: "PostgreSQL" },
|
{ label: "Base de données", val: "PostgreSQL" },
|
||||||
{ label: "Frontend", val: "React + Vite" },
|
{ label: "Frontend", val: "React + Vite" },
|
||||||
{ label: "IA de modération", val: "OpenAI GPT-4o mini (défaut)" },
|
{ label: "IA de modération", val: "Mistral small (défaut) — configurable via FILTER_MODEL" },
|
||||||
{ label: "IA de synthèse", val: "OpenAI GPT-4o (défaut)" },
|
{ label: "IA de synthèse", val: "Mistral large (défaut) — configurable via SYNTHESIS_MODEL" },
|
||||||
{ label: "Données personnelles", val: "Aucune (pseudonyme facultatif uniquement)" },
|
{ label: "Données personnelles", val: "Aucune (pseudonyme facultatif uniquement)" },
|
||||||
{ label: "Trackers / publicité", val: "Aucun" },
|
{ label: "Trackers / publicité", val: "Aucun" },
|
||||||
{ label: "Inscription requise", val: "Non" },
|
{ label: "Inscription requise", val: "Non" },
|
||||||
|
|||||||
Reference in New Issue
Block a user