File size: 4,889 Bytes
f7b069f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# ======================================
# main.py – FastAPI pour chatbot douanier 🇹🇳
# ======================================

from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Optional, List, Dict
import uuid
import uvicorn

# Import des modules internes
from core.retrieval import find_relevant_articles
from core.llm import generate_synthesized_llm_response_with_sources
from core.memory import (
    start_new_session,
    add_message_to_session,
    rename_session,
    update_session_title,
    get_messages_for_session,
    load_all_sessions
)

# ======================================================
# CONFIGURATION DE L'APPLICATION
# ======================================================

app = FastAPI(title="Chatbot Douane API 🇹🇳")

# CORS (pour permettre les requêtes depuis un frontend)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"]
)

# ----------------------------
# Pydantic models
# ----------------------------

class MessageData(BaseModel):
    type: Optional[str] = "human"
    content: str

class AddMessageRequest(BaseModel):
    session_id: str
    message: MessageData

class RenameSessionRequest(BaseModel):
    session_id: str
    new_title: str

class NewSessionResponse(BaseModel):
    session_id: str

class ChatRequest(BaseModel):
    question: str
    session_id: Optional[str] = None
    web_results: Optional[Dict] = None

class ChatResponse(BaseModel):
    session_id: str
    answer: str
    articles_found: List[Dict]

# ----------------------------
# Session endpoints
# ----------------------------

@app.get("/sessions")
def get_all_sessions():
    """Return all sessions with their titles and creation date."""
    sessions = load_all_sessions()
    return sessions

@app.post("/sessions/new", response_model=NewSessionResponse)
def create_session():
    """Create a new session and return its ID."""
    session_state = {"sessions": {}}
    session_id = start_new_session(session_state)
    return {"session_id": session_id}

@app.post("/sessions/add_message")
def add_message(req: AddMessageRequest):
    """Add a message to a session."""
    try:
        add_message_to_session(req.session_id, req.message.dict())
        return {"status": "success"}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@app.post("/sessions/rename")
def rename(req: RenameSessionRequest):
    """Rename a session manually."""
    try:
        rename_session(req.session_id, req.new_title)
        return {"status": "success"}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@app.post("/sessions/update_title/{session_id}")
def update_title(session_id: str):
    """Update session title automatically based on first message."""
    try:
        update_session_title(session_id)
        return {"status": "success"}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

@app.get("/sessions/{session_id}/messages")
def get_messages(session_id: str):
    """Get all messages for a given session."""
    try:
        messages = get_messages_for_session(session_id)
        return messages
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))

# ----------------------------
# Chatbot endpoint
# ----------------------------

@app.post("/chat", response_model=ChatResponse)
def chat_with_bot(request: ChatRequest):
    """
    Envoie une question au chatbot douanier.
    - Recherche les articles pertinents
    - Génère la réponse à l’aide du LLM
    - Sauvegarde l’historique dans MongoDB
    """
    try:
        # Si pas de session fourni, créer un nouvel ID
        session_id = request.session_id or f"session_{uuid.uuid4()}"

        # Récupérer les articles pertinents
        top_articles = find_relevant_articles(request.question)

        # Générer la réponse via LLM
        answer, _ = generate_synthesized_llm_response_with_sources(
            question=request.question,
            top_articles=top_articles,
            web_results=request.web_results or {},
            session_id=session_id
        )

        # Format des articles
        articles = [
            {
                "article_num": doc.get("article_num"),
                "similarity": round(sim, 3)
            }
            for doc, sim in top_articles
        ]

        # Retour API
        return ChatResponse(
            session_id=session_id,
            answer=answer,
            articles_found=articles
        )

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

# ======================================================
# LANCEMENT LOCAL
# ======================================================