gaya2604's picture
Update executives/api.py
c02ba89 verified
Raw
History Blame Contribute Delete
6.37 kB
from fastapi import FastAPI, Form, Response, BackgroundTasks
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
import requests
import datetime
import hashlib
import os
app = FastAPI(title="NEXUS COMMAND CENTER")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
TWILIO_ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID", "AC3f5f0eb3da2c3f839fb021ac203ad781")
TWILIO_AUTH_TOKEN = os.getenv("TWILIO_AUTH_TOKEN", "88e8a43f9abb88f9abdbf7867c80ab30")
TWILIO_WHATSAPP_NUMBER = "whatsapp:+14155238886"
tickets_db = {}
compteur_ticket = 1
class DispatchOrdre(BaseModel):
service: str
class DemandeWeb(BaseModel):
description: str
def analyser_et_repondre_ia(texte_message: str, numero_expediteur: str, ticket_id: int):
"""Fonction exécutée en arrière-plan : interroge Ollama et met à jour le Dashboard"""
try:
url_ollama = "http://127.0.0.1:11434/api/generate"
payload = {
"model": "gemma4:e4b",
"prompt": f"Tu es le dispatcher d'urgence NEXUS. Analyse ce message et réponds en incluant le service d'urgence le plus approprié (POLICE, POMPIERS, ou SAMU) : {texte_message}",
"stream": False
}
reponse_ollama = requests.post(url_ollama, json=payload, timeout=180)
analyse_ia = reponse_ollama.json().get("response", "Erreur IA")
domaine_ia = "INCONNU"
texte_maj = analyse_ia.upper()
if "POLICE" in texte_maj: domaine_ia = "POLICE"
elif "POMPIERS" in texte_maj: domaine_ia = "POMPIERS"
elif "SAMU" in texte_maj: domaine_ia = "SAMU"
tickets_db[ticket_id]["domaine_ia"] = domaine_ia
tickets_db[ticket_id]["score"] = 8 if domaine_ia != "INCONNU" else 5
tickets_db[ticket_id]["status"] = "EN ATTENTE DISPATCH"
except Exception as e:
analyse_ia = f"⚠️ Échec du traitement local : {str(e)}"
tickets_db[ticket_id]["domaine_ia"] = "ERREUR IA"
url_twilio = f"https://api.twilio.com/2010-04-01/Accounts/{TWILIO_ACCOUNT_SID}/Messages.json"
donnees_whatsapp = {
"From": TWILIO_WHATSAPP_NUMBER,
"To": numero_expediteur,
"Body": f"🧠 [NEXUS PRIME - ANALYSE IA]\n\n{analyse_ia}"
}
requests.post(url_twilio, data=donnees_whatsapp, auth=(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN))
@app.post("/api/twilio")
async def twilio_webhook(background_tasks: BackgroundTasks, Body: str = Form(...), From: str = Form(...)):
"""Route Webhook : Répond immédiatement, sauvegarde le ticket et lance l'IA"""
global compteur_ticket
msg_hash = hashlib.md5(f"{From}:{Body}".encode()).hexdigest()
if any(t.get("hash") == msg_hash for t in tickets_db.values()):
return Response(content="<Response/>", media_type="application/xml")
ticket_id = compteur_ticket
compteur_ticket += 1
tickets_db[ticket_id] = {
"id": ticket_id,
"heure": datetime.datetime.now().strftime("%H:%M:%S"),
"telephone": From,
"message": Body,
"domaine_ia": "Analyse en cours... ⏳",
"score": 0,
"status": "NOUVEAU",
"hash": msg_hash
}
background_tasks.add_task(analyser_et_repondre_ia, Body, From, ticket_id)
reponse_twiml = f"""<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>NEXUS a bien reçu votre signalement (Dossier #{ticket_id}). Analyse IA en cours... ⏳</Message>
</Response>
"""
return Response(content=reponse_twiml, media_type="application/xml")
@app.get("/api/tickets")
def get_tickets():
"""Route pour que le Dashboard HTML récupère la liste des urgences"""
return sorted(list(tickets_db.values()), key=lambda x: x["id"], reverse=True)
@app.post("/api/tickets/{ticket_id}/dispatch")
def dispatch_ticket(ticket_id: int, ordre: DispatchOrdre):
"""Route appelée par le bouton du Dashboard pour envoyer les secours"""
if ticket_id not in tickets_db:
return {"error": "Ticket introuvable"}
ticket = tickets_db[ticket_id]
service_cible = ordre.service
ticket["status"] = f"TRANSFÉRÉ -> {service_cible}"
message_citoyen = f"✅ NEXUS INFO : Votre urgence a été transmise aux {service_cible}. Les secours sont en route."
url_twilio = f"https://api.twilio.com/2010-04-01/Accounts/{TWILIO_ACCOUNT_SID}/Messages.json"
donnees = {"From": TWILIO_WHATSAPP_NUMBER, "To": ticket["telephone"], "Body": message_citoyen}
requests.post(url_twilio, data=donnees, auth=(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN))
return {"status": "success", "ticket": ticket}
@app.post("/api/evaluer")
def evaluer_ticket_web(demande: DemandeWeb):
"""Route réelle : interroge l'IA locale (Ollama) en direct pour le site web"""
try:
url_ollama = "http://127.0.0.1:11434/api/generate"
payload = {
"model": "gemma4:e4b",
"prompt": f"Tu es le dispatcher d'urgence NEXUS. Analyse ce message et réponds en incluant le service d'urgence le plus approprié (POLICE, POMPIERS, ou SAMU) : {demande.description}",
"stream": False
}
reponse_ollama = requests.post(url_ollama, json=payload, timeout=180)
analyse_ia = reponse_ollama.json().get("response", "INCONNU").upper()
domaine = "INCONNU"
score = 5
friction = "COMPLET"
question = ""
if "POLICE" in analyse_ia:
domaine = "POLICE"
score = 8
elif "POMPIERS" in analyse_ia:
domaine = "POMPIERS"
score = 9
elif "SAMU" in analyse_ia:
domaine = "SAMU"
score = 10
else:
friction = "INCOMPLET"
score = 3
question = "L'analyse IA nécessite plus de contexte. Pouvez-vous préciser la nature exacte de l'urgence ?"
return {
"domaine": domaine,
"score": score,
"friction": friction,
"question_ia": question
}
except Exception as e:
return {
"domaine": "ERREUR",
"score": 0,
"friction": "ERREUR SERVEUR",
"question_ia": f"Impossible de joindre le modèle IA local : {str(e)}"
}