Update political idea platform to use Python Flask backend
Replace the existing Node.js API server with a Python Flask application, implementing robust AI-driven content filtering based on international human rights law and enhancing security measures. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 923ae0e3-a363-4db8-b04a-e8baca2a1330 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 30f4e946-427f-4b27-989d-531b9116d12f Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8af7d2ec-2cc3-4ece-8af3-9f071488d072/923ae0e3-a363-4db8-b04a-e8baca2a1330/AWHAa3Z Replit-Helium-Checkpoint-Created: true
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
"""
|
||||
Agent IA pour le filtrage éthique et la synthèse démocratique.
|
||||
Utilise les Intégrations IA de Replit (OpenAI proxy).
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
from openai import OpenAI, BadRequestError
|
||||
from legal_framework import LEGAL_FILTER_PROMPT, SYNTHESIS_PROMPT
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_client: OpenAI | None = None
|
||||
|
||||
|
||||
def get_client() -> OpenAI:
|
||||
global _client
|
||||
if _client is None:
|
||||
base_url = os.environ.get("AI_INTEGRATIONS_OPENAI_BASE_URL")
|
||||
api_key = os.environ.get("AI_INTEGRATIONS_OPENAI_API_KEY")
|
||||
if not base_url or not api_key:
|
||||
raise RuntimeError(
|
||||
"AI_INTEGRATIONS_OPENAI_BASE_URL et AI_INTEGRATIONS_OPENAI_API_KEY "
|
||||
"sont requis. Configurez les intégrations Replit AI."
|
||||
)
|
||||
_client = OpenAI(base_url=base_url, api_key=api_key)
|
||||
return _client
|
||||
|
||||
|
||||
def filter_idea(content: str) -> dict:
|
||||
"""
|
||||
Filtre une idée selon le cadre légal international des droits humains.
|
||||
Retourne : {"accepted": bool, "reason"?: str, "legal_basis"?: str}
|
||||
"""
|
||||
try:
|
||||
client = get_client()
|
||||
response = client.chat.completions.create(
|
||||
model="gpt-5-mini",
|
||||
max_completion_tokens=300,
|
||||
response_format={"type": "json_object"},
|
||||
messages=[
|
||||
{"role": "system", "content": LEGAL_FILTER_PROMPT},
|
||||
{"role": "user", "content": f'Idée soumise : "{content}"'},
|
||||
],
|
||||
)
|
||||
raw = (
|
||||
response.choices[0].message.content
|
||||
or '{"accepted": false, "reason": "Contenu non conforme aux principes démocratiques."}'
|
||||
)
|
||||
raw = raw.strip()
|
||||
if raw.startswith("```"):
|
||||
raw = raw.split("```")[1]
|
||||
if raw.startswith("json"):
|
||||
raw = raw[4:]
|
||||
raw = raw.strip()
|
||||
start = raw.find("{")
|
||||
end = raw.rfind("}") + 1
|
||||
if start != -1 and end > start:
|
||||
raw = raw[start:end]
|
||||
result = json.loads(raw)
|
||||
return result
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("Impossible de parser la réponse JSON du filtre, raw=%r", raw if 'raw' in dir() else 'N/A')
|
||||
return {"accepted": False, "reason": "Erreur interne de filtrage"}
|
||||
except BadRequestError as e:
|
||||
if "content_filter" in str(e) or "content management policy" in str(e):
|
||||
logger.warning("Contenu bloqué par le filtre de sécurité du proxy IA — rejet automatique")
|
||||
return {
|
||||
"accepted": False,
|
||||
"reason": (
|
||||
"Ce contenu a été automatiquement bloqué car il contient des propos "
|
||||
"haineux ou violents graves, contraires à la dignité humaine."
|
||||
),
|
||||
"legal_basis": (
|
||||
"DUDH Art. 1 (dignité humaine), DUDH Art. 20 (interdiction de la haine), "
|
||||
"PIDCP Art. 20, CEDH Art. 17 (abus de droit)"
|
||||
),
|
||||
}
|
||||
logger.exception("Erreur API lors du filtrage")
|
||||
return {"accepted": False, "reason": "Service temporairement indisponible"}
|
||||
except Exception:
|
||||
logger.exception("Erreur lors du filtrage de l'idée")
|
||||
return {"accepted": False, "reason": "Service temporairement indisponible"}
|
||||
|
||||
|
||||
def synthesize_ideas(ideas: list[str]) -> str:
|
||||
"""
|
||||
Synthétise une liste d'idées acceptées en un texte collectif
|
||||
ancré dans les valeurs démocratiques et les droits humains.
|
||||
"""
|
||||
if not ideas:
|
||||
return (
|
||||
"Aucune idée n'a encore été soumise. "
|
||||
"Soyez le premier à partager votre vision pour une société meilleure, "
|
||||
"fondée sur la Déclaration universelle des droits de l'homme."
|
||||
)
|
||||
try:
|
||||
client = get_client()
|
||||
ideas_text = "\n".join(f"{i + 1}. {idea}" for i, idea in enumerate(ideas))
|
||||
response = client.chat.completions.create(
|
||||
model="gpt-5.2",
|
||||
max_completion_tokens=1200,
|
||||
messages=[
|
||||
{"role": "system", "content": SYNTHESIS_PROMPT},
|
||||
{
|
||||
"role": "user",
|
||||
"content": (
|
||||
f"Voici les {len(ideas)} idée(s) citoyenne(s) validées :\n\n"
|
||||
f"{ideas_text}\n\n"
|
||||
"Rédige La Voix du Peuple."
|
||||
),
|
||||
},
|
||||
],
|
||||
)
|
||||
return response.choices[0].message.content or "Synthèse en cours..."
|
||||
except Exception:
|
||||
logger.exception("Erreur lors de la synthèse des idées")
|
||||
return "La synthèse est temporairement indisponible. Vos idées ont bien été enregistrées."
|
||||
Reference in New Issue
Block a user