ChatCraft / backend /lobby /safe_name.py
gabraken's picture
feat: add new units/buildings/map assets, admin routes, and frontend build
dd96d2f
"""
Validation du pseudo joueur via Mistral : détection d'insultes / noms inappropriés.
Si le nom est jugé insultant, il est remplacé par un nom aléatoire inoffensif.
"""
from __future__ import annotations
import json
import logging
import random
from config import MISTRAL_API_KEY, MISTRAL_CHAT_MODEL
log = logging.getLogger(__name__)
_FALLBACK_NAMES = [
"Player",
"Guest",
"Strategist",
"Commander",
"Pilot",
"Scout",
"Rookie",
]
_PROMPT = """Tu dois juger si un pseudo de joueur pour un jeu en ligne est insultant, vulgaire, discriminatoire ou inapproprié pour un public familial.
Réponds UNIQUEMENT avec un JSON valide, sans texte avant ni après, avec exactement ces deux champs :
- "is_insulting": true si le pseudo est inapproprié (insulte, gros mot, contenu choquant), false sinon.
- "replacement": si is_insulting est true, un pseudo de remplacement court, sympa et inoffensif (ex: "Chevalier", "Pilote"); sinon la chaîne vide "".
Pseudo à évaluer : "{name}"
"""
async def sanitize_player_name(name: str) -> str:
"""
Vérifie le nom via Mistral. Si insultant, retourne un remplacement ; sinon retourne le nom tel quel.
En cas d'absence de clé API ou d'erreur, retourne le nom original.
"""
name = (name or "").strip() or "Player"
if not MISTRAL_API_KEY:
return name
try:
from mistralai import Mistral
client = Mistral(api_key=MISTRAL_API_KEY)
response = await client.chat.complete_async(
model=MISTRAL_CHAT_MODEL,
messages=[{"role": "user", "content": _PROMPT.format(name=name)}],
response_format={"type": "json_object"},
)
content = response.choices[0].message.content
if isinstance(content, str):
raw = content.strip()
elif content:
first = content[0]
raw = (getattr(first, "text", None) or str(first)).strip()
else:
raw = ""
# Extraire un éventuel bloc JSON
if "```" in raw:
raw = raw.split("```")[1]
if raw.startswith("json"):
raw = raw[4:]
data = json.loads(raw)
if data.get("is_insulting") and data.get("replacement"):
replacement = str(data["replacement"]).strip() or random.choice(_FALLBACK_NAMES)
log.info("Safe name: %r replaced by %r", name, replacement)
return replacement[:50]
return name[:50]
except Exception as e:
log.warning("Safe name check failed for %r: %s", name, e)
return name[:50]