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:
pironantoine
2026-04-03 16:58:47 +00:00
parent f9c4073d21
commit ae970b2a32
13 changed files with 1534 additions and 32 deletions
+118
View File
@@ -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."