Skip to content

Commit 9685c7d

Browse files
committed
feat: Aggiungi supporto per chat_id nella gestione della cronologia chat e aggiorna la documentazione
1 parent 28d9104 commit 9685c7d

5 files changed

Lines changed: 379 additions & 46 deletions

File tree

IA_docs/CHAT_SSE_STREAMING.md

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
# Chat SSE Streaming - Documentazione
2+
3+
## Panoramica
4+
5+
L'endpoint `/chat/text` utilizza Server-Sent Events (SSE) per inviare risposte in streaming dal server al client. Il sistema è stato aggiornato per gestire la cronologia delle chat lato server tramite `chat_id`, eliminando la necessità di inviare l'intera cronologia ad ogni richiesta.
6+
7+
## Cambiamenti Implementati
8+
9+
### Prima (Vecchio Sistema)
10+
```typescript
11+
// Il client inviava tutta la cronologia messaggi
12+
await sendMessageToBot(
13+
userMessage,
14+
modelType,
15+
previousMessages, // ❌ Tutta la cronologia inviata dal client
16+
onStreamChunk,
17+
chatId
18+
);
19+
```
20+
21+
### Dopo (Nuovo Sistema)
22+
```typescript
23+
// Il client invia solo il chat_id per identificare la sessione
24+
await sendMessageToBot(
25+
userMessage,
26+
modelType,
27+
onStreamChunk,
28+
chatId // ✅ Solo il chat_id per identificare la chat
29+
);
30+
```
31+
32+
## Formato Request
33+
34+
### Endpoint
35+
```
36+
POST /chat/text
37+
Content-Type: application/json
38+
Authorization: Bearer {token}
39+
```
40+
41+
### Body
42+
```json
43+
{
44+
"quest": "Il tuo messaggio qui",
45+
"model": "base" | "advanced",
46+
"chat_id": "uuid-della-chat-opzionale"
47+
}
48+
```
49+
50+
**Parametri:**
51+
- `quest` (required): Il messaggio dell'utente
52+
- `model` (optional): Tipo di modello ("base" o "advanced", default: "base")
53+
- `chat_id` (optional): ID della chat per continuare una conversazione esistente
54+
55+
## Formato Response (SSE)
56+
57+
Il server invia eventi Server-Sent Events con i seguenti tipi:
58+
59+
### 1. Chat Info Event
60+
Inviato all'inizio dello stream per comunicare il `chat_id` della sessione.
61+
62+
```
63+
data: {"type": "chat_info", "chat_id": "550e8400-e29b-41d4-a716-446655440000", "is_new": true}
64+
```
65+
66+
**Campi:**
67+
- `type`: "chat_info"
68+
- `chat_id`: UUID della sessione di chat
69+
- `is_new`: `true` se è una nuova chat creata automaticamente, `false` se è una chat esistente
70+
71+
### 2. Status Event
72+
Informazioni sullo stato di elaborazione.
73+
74+
```
75+
data: {"type": "status", "message": "Processing with MCP tools..."}
76+
```
77+
78+
### 3. Tool Call Event
79+
Notifica quando viene chiamato un tool MCP.
80+
81+
```
82+
data: {"type": "tool_call", "tool_name": "create_task", "tool_args": {...}, "item_index": 0}
83+
```
84+
85+
**Campi:**
86+
- `type`: "tool_call"
87+
- `tool_name`: Nome del tool chiamato
88+
- `tool_args`: Argomenti passati al tool
89+
- `item_index`: Indice dell'item nel contesto di streaming
90+
91+
### 4. Tool Output Event
92+
Risultato dell'esecuzione di un tool.
93+
94+
```
95+
data: {"type": "tool_output", "tool_name": "create_task", "output": "...", "item_index": 0}
96+
```
97+
98+
**Campi:**
99+
- `type`: "tool_output"
100+
- `tool_name`: Nome del tool
101+
- `output`: Output del tool (JSON stringificato)
102+
- `item_index`: Indice dell'item per correlare con tool_call
103+
104+
### 5. Content Event
105+
Chunk di testo della risposta dell'assistente.
106+
107+
```
108+
data: {"type": "content", "delta": "Ho creato"}
109+
data: {"type": "content", "delta": " il task"}
110+
data: {"type": "content", "delta": " con successo!"}
111+
```
112+
113+
**Campi:**
114+
- `type`: "content"
115+
- `delta`: Frammento di testo da aggiungere alla risposta
116+
117+
### 6. Error Event
118+
Notifica di errore durante l'elaborazione.
119+
120+
```
121+
data: {"type": "error", "message": "Errore durante l'elaborazione"}
122+
```
123+
124+
### 7. Done Event
125+
Indica il completamento dello stream.
126+
127+
```
128+
data: {"type": "done", "message": "Stream completed"}
129+
```
130+
131+
## Esempio Completo di Stream
132+
133+
```
134+
data: {"type": "chat_info", "chat_id": "550e8400-e29b-41d4-a716-446655440000", "is_new": true}
135+
136+
data: {"type": "status", "message": "Processing with MCP tools..."}
137+
138+
data: {"type": "tool_call", "tool_name": "create_task", "tool_args": {"title": "Comprare il latte", "due_date": "2024-01-20"}, "item_index": 0}
139+
140+
data: {"type": "tool_output", "tool_name": "create_task", "output": "{\"success\": true, \"task_id\": 123}", "item_index": 0}
141+
142+
data: {"type": "content", "delta": "Ho creato"}
143+
144+
data: {"type": "content", "delta": " il task"}
145+
146+
data: {"type": "content", "delta": " 'Comprare il latte'"}
147+
148+
data: {"type": "content", "delta": " con scadenza"}
149+
150+
data: {"type": "content", "delta": " il 20 gennaio."}
151+
152+
data: {"type": "done", "message": "Stream completed"}
153+
```
154+
155+
## Gestione Client
156+
157+
### TypeScript Client Implementation
158+
159+
```typescript
160+
import { sendMessageToBot } from './services/botservice';
161+
162+
// Stato per tracciare chat_id
163+
const [currentChatId, setCurrentChatId] = useState<string | null>(null);
164+
165+
// Callback per gestire lo streaming
166+
const onStreamChunk = (
167+
chunk: string,
168+
isComplete: boolean,
169+
toolWidgets?: ToolWidget[],
170+
chatInfo?: { chat_id: string; is_new: boolean }
171+
) => {
172+
// Aggiorna chat_id se ricevuto dal server
173+
if (chatInfo?.chat_id) {
174+
setCurrentChatId(chatInfo.chat_id);
175+
if (chatInfo.is_new) {
176+
console.log('Nuova chat creata:', chatInfo.chat_id);
177+
}
178+
}
179+
180+
// Gestisci chunk di testo
181+
if (chunk) {
182+
// Aggiungi chunk al messaggio
183+
}
184+
185+
// Gestisci tool widgets
186+
if (toolWidgets) {
187+
// Aggiorna UI con widgets
188+
}
189+
190+
// Se completato, finalizza il messaggio
191+
if (isComplete) {
192+
// Messaggio completato
193+
}
194+
};
195+
196+
// Invia messaggio
197+
const result = await sendMessageToBot(
198+
userMessage,
199+
modelType,
200+
onStreamChunk,
201+
currentChatId || undefined
202+
);
203+
204+
// Aggiorna chat_id se cambiato
205+
if (result.chat_id && result.chat_id !== currentChatId) {
206+
setCurrentChatId(result.chat_id);
207+
}
208+
```
209+
210+
### Gestione Chat History
211+
212+
```typescript
213+
// Carica una chat esistente
214+
import { getChatWithMessages } from './services/chatHistoryService';
215+
216+
const loadChat = async (chatId: string) => {
217+
const chatData = await getChatWithMessages(chatId);
218+
219+
// Imposta chat_id corrente
220+
setCurrentChatId(chatId);
221+
222+
// Carica messaggi nella UI
223+
setMessages(chatData.messages.map(msg => ({
224+
id: msg.message_id.toString(),
225+
text: msg.content,
226+
sender: msg.role === 'user' ? 'user' : 'bot',
227+
// ... altri campi
228+
})));
229+
};
230+
231+
// Crea nuova chat
232+
import { createNewChat } from './services/botservice';
233+
234+
const startNewChat = async () => {
235+
const chatId = await createNewChat();
236+
setCurrentChatId(chatId);
237+
setMessages([]);
238+
};
239+
```
240+
241+
## Vantaggi del Nuovo Sistema
242+
243+
1. **Riduzione Banda**: Non è più necessario inviare tutta la cronologia ad ogni messaggio
244+
2. **Performance**: Meno dati da processare lato client e server
245+
3. **Scalabilità**: La cronologia è gestita centralmente nel database
246+
4. **Semplicità**: L'API client è più semplice e intuitiva
247+
5. **Consistenza**: La cronologia è sempre sincronizzata con il server
248+
249+
## Retrocompatibilità
250+
251+
Il server supporta ancora richieste senza `chat_id`. In questo caso:
252+
- Viene creata automaticamente una nuova chat
253+
- Il `chat_id` viene restituito nell'evento `chat_info`
254+
- Il client può salvare il `chat_id` per messaggi successivi
255+
256+
## Best Practices
257+
258+
1. **Persistenza Chat ID**: Salva sempre il `chat_id` ricevuto dal server
259+
2. **Gestione Errori**: Implementa fallback se il `chat_id` non è più valido
260+
3. **Nuova Chat**: Resetta il `chat_id` quando l'utente inizia una nuova conversazione
261+
4. **Loading States**: Mostra indicatori di caricamento durante lo streaming
262+
5. **Widget Management**: Usa `item_index` per correlare tool_call e tool_output
263+
264+
## Troubleshooting
265+
266+
### Chat ID non valido
267+
Se il server non trova il `chat_id`, crea automaticamente una nuova chat e restituisce il nuovo ID nell'evento `chat_info`.
268+
269+
### Tool Output con tool_name "unknown"
270+
Il client usa `item_index` per correlare tool_output con tool_call, risolvendo il problema del tool_name "unknown".
271+
272+
### Streaming interrotto
273+
Gestisci l'evento `error` e mostra un messaggio appropriato all'utente.
274+
275+
## Riferimenti
276+
277+
- [Chat History API Documentation](./CHAT_HISTORY_API.md)
278+
- [Bot Service Implementation](../src/services/botservice.ts)
279+
- [Chat History Service](../src/services/chatHistoryService.ts)

src/navigation/screens/BotChat.tsx

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,15 @@ const BotChat: React.FC = () => {
234234
// 3. Accumulo dati streaming
235235
let accumulatedText = "";
236236
let currentWidgets: any[] = [];
237+
let receivedChatId: string | undefined;
237238

238239
// 4. Callback per aggiornare UI durante streaming
239-
const onStreamChunk = (chunk: string, isComplete: boolean, toolWidgets?: any[]) => {
240+
const onStreamChunk = (
241+
chunk: string,
242+
isComplete: boolean,
243+
toolWidgets?: any[],
244+
chatInfo?: { chat_id: string; is_new: boolean }
245+
) => {
240246
if (chunk) {
241247
accumulatedText += chunk;
242248
}
@@ -245,6 +251,14 @@ const BotChat: React.FC = () => {
245251
currentWidgets = toolWidgets;
246252
}
247253

254+
// Se riceviamo chat_id dal server, aggiorniamo lo stato
255+
if (chatInfo?.chat_id) {
256+
receivedChatId = chatInfo.chat_id;
257+
if (chatInfo.is_new) {
258+
console.log('[BotChat] Nuova chat creata automaticamente dal server:', receivedChatId);
259+
}
260+
}
261+
248262
// Aggiorna il messaggio bot con testo + widgets accumulati
249263
setMessages(prevMessages =>
250264
prevMessages.map(msg =>
@@ -262,19 +276,20 @@ const BotChat: React.FC = () => {
262276
};
263277

264278
try {
265-
// 5. Otteniamo gli ultimi messaggi per contesto
266-
const currentMessages = [...messages, userMessage];
267-
const lastMessages = currentMessages.slice(-6); // Ultimi 6 messaggi
268-
269-
// 6. Invia richiesta con streaming callback e chat_id
279+
// 5. Invia richiesta con streaming callback e chat_id
270280
const result = await sendMessageToBot(
271281
text,
272282
modelType,
273-
lastMessages,
274283
onStreamChunk,
275284
currentChatId || undefined
276285
);
277286

287+
// 6. Aggiorna currentChatId se il server ha restituito un chat_id
288+
if (result.chat_id && result.chat_id !== currentChatId) {
289+
console.log('[BotChat] Aggiornamento chat_id da:', currentChatId, 'a:', result.chat_id);
290+
setCurrentChatId(result.chat_id);
291+
}
292+
278293
// 7. Aggiornamento finale con dati completi
279294
const formattedText = formatMessage(result.text);
280295

src/navigation/screens/Home.tsx

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -337,17 +337,31 @@ const HomeScreen = () => {
337337

338338
try {
339339
// Callback per gestire lo streaming
340-
const onStreamChunk: StreamingCallback = (chunk: string, isComplete: boolean, toolWidgets?: ToolWidget[]) => {
340+
const onStreamChunk: StreamingCallback = (
341+
chunk: string,
342+
isComplete: boolean,
343+
toolWidgets?: ToolWidget[],
344+
chatInfo?: { chat_id: string; is_new: boolean }
345+
) => {
341346
if (typeof chunk !== 'string' && chunk) {
342347
console.warn('[HOME] onStreamChunk received non-string chunk:', chunk);
343348
}
344349
console.log('[HOME] onStreamChunk', {
345350
isComplete,
346351
chunkPreview: typeof chunk === 'string' ? chunk.slice(0, 40) : chunk,
347352
widgetsCount: toolWidgets?.length || 0,
348-
widgets: toolWidgets?.map(w => ({ toolName: w.toolName, status: w.status, type: w.toolOutput?.type }))
353+
widgets: toolWidgets?.map(w => ({ toolName: w.toolName, status: w.status, type: w.toolOutput?.type })),
354+
chatInfo
349355
});
350356

357+
// Se riceviamo chat_id dal server, aggiorniamo lo stato
358+
if (chatInfo?.chat_id) {
359+
if (chatInfo.is_new) {
360+
console.log('[HOME] Nuova chat creata automaticamente dal server:', chatInfo.chat_id);
361+
}
362+
setCurrentChatId(chatInfo.chat_id);
363+
}
364+
351365
if (isComplete) {
352366
// Lo streaming è completato, applica formatMessage al testo completo e aggiorna toolWidgets
353367
setMessages((prev) =>
@@ -380,14 +394,19 @@ const HomeScreen = () => {
380394
};
381395

382396
// Invia il messaggio al bot con streaming e chat_id
383-
await sendMessageToBot(
397+
const result = await sendMessageToBot(
384398
trimmedMessage,
385399
"advanced",
386-
messages,
387400
onStreamChunk,
388401
chatIdToUse || undefined
389402
);
390403

404+
// Aggiorna currentChatId se il server ha restituito un chat_id
405+
if (result.chat_id && result.chat_id !== currentChatId) {
406+
console.log('[HOME] Aggiornamento chat_id da:', currentChatId, 'a:', result.chat_id);
407+
setCurrentChatId(result.chat_id);
408+
}
409+
391410
} catch (error) {
392411
console.error("[HOME] Errore nell'invio del messaggio:", error);
393412

0 commit comments

Comments
 (0)