thibautmodrin's picture
add input classic
b8d5190
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
import asyncio
from datetime import datetime, timedelta
import httpx
import os
import logging
import json
# Logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("main")
app = FastAPI(
title="Vitizen WebSocket API",
description="API WebSocket pour l'assistant viticole",
version="1.0.0"
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Restrict in production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
LANGSERVE_URL = os.getenv("LANGSERVE_URL", "https://thibautmodrin-vitizen-chat.hf.space/chat/invoke")
@app.get("/", response_class=HTMLResponse)
async def home():
return """
<html><body><h1>Bienvenue sur l'API WebSocket Vitizen</h1></body></html>
"""
@app.websocket("/ws/chat")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
logger.info("✅ Nouvelle connexion WebSocket établie")
last_call_time = datetime.utcnow() - timedelta(seconds=5)
async with httpx.AsyncClient(timeout=30) as client:
try:
while True:
data = await websocket.receive_json()
question = data.get("message", "").strip()
if not question:
await websocket.send_text("[Erreur] Le message est vide.")
continue
logger.info(f"💬 Message reçu: {question[:100]}...")
now = datetime.utcnow()
delta = (now - last_call_time).total_seconds()
if delta < 2:
wait_time = round(2 - delta, 2)
await websocket.send_text(f"⏳ Merci d'attendre {wait_time}s.")
continue
last_call_time = now
logger.info(f"📤 Envoi à LangServe: {LANGSERVE_URL}")
try:
response = await client.post(
LANGSERVE_URL,
json={"input": question}, # ✅ FORMAT CORRECT
headers={"User-Agent": "vitizen-client/1.0"},
timeout=30
)
response.raise_for_status()
logger.info(f"✅ Statut HTTP: {response.status_code}")
try:
json_data = response.json()
logger.info(f"🔍 Contenu JSON: {json_data}")
answer = json_data.get("output", "[Erreur: réponse vide]")
except Exception as e:
answer = f"[Erreur] Exception JSON: {str(e)}"
except httpx.HTTPStatusError as e:
answer = f"[Erreur] HTTP {e.response.status_code} - {e.response.reason_phrase}"
except httpx.RequestError as e:
answer = f"[Erreur] Échec réseau: {e.__class__.__name__} - {str(e)}"
except Exception as e:
answer = f"[Erreur] Exception durant la requête: {str(e)}"
try:
await websocket.send_text(answer)
logger.info("📨 Réponse envoyée")
except RuntimeError as e:
logger.warning(f"⛔ Connexion fermée avant l'envoi de la réponse: {str(e)}")
break
except WebSocketDisconnect:
logger.info("🔌 Connexion WebSocket fermée par le client")
except Exception as e:
logger.error(f"[Erreur] Exception inattendue: {str(e)}")
try:
await websocket.send_text(f"[Erreur] {str(e)}")
except:
pass
@app.get("/health")
async def health_check():
return {
"status": "ok",
"langserve_url": LANGSERVE_URL,
"version": "1.0.0"
}
if __name__ == "__main__":
import uvicorn
logger.info("🚀 Lancement du serveur sur le port 8000")
uvicorn.run(app, host="0.0.0.0", port=8000)