115 lines
4.4 KiB
Markdown
115 lines
4.4 KiB
Markdown
|
|
# Contrato de integración con n8n — WebChatV2
|
||
|
|
|
||
|
|
El frontend hace un `POST` al **webhook de n8n** con el mensaje del usuario y el historial,
|
||
|
|
y espera una respuesta JSON con el texto del asistente y, opcionalmente, KeyNotes
|
||
|
|
(resumen / To-Do) que se insertan automáticamente en el panel derecho y que el usuario
|
||
|
|
puede editar después.
|
||
|
|
|
||
|
|
## 1. Configuración de la URL
|
||
|
|
|
||
|
|
La URL del webhook se resuelve en **tiempo de ejecución** (no se "hornea" al compilar),
|
||
|
|
para que puedas cambiarla sin reconstruir la imagen Docker:
|
||
|
|
|
||
|
|
1. `public/config.js` → define `window.APP_CONFIG.N8N_WEBHOOK_URL` (prioridad alta).
|
||
|
|
2. Si no existe, se usa la variable de entorno `VITE_N8N_WEBHOOK_URL` (definida al compilar).
|
||
|
|
|
||
|
|
En Docker, edita el archivo `config.js` servido por nginx (o monta un volumen sobre
|
||
|
|
`/usr/share/nginx/html/config.js`) y recarga la página.
|
||
|
|
|
||
|
|
## 2. Request — `POST {N8N_WEBHOOK_URL}`
|
||
|
|
|
||
|
|
`Content-Type: application/json`
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"themeId": "theme_abc123",
|
||
|
|
"subThemeId": "sub_def456",
|
||
|
|
"themeTitle": "Tema Principal",
|
||
|
|
"subThemeTitle": "Subtema 1",
|
||
|
|
"history": [
|
||
|
|
{ "role": "user", "content": "Hola" },
|
||
|
|
{ "role": "assistant", "content": "¿En qué puedo ayudarte?" }
|
||
|
|
],
|
||
|
|
"message": "Explícame cómo funciona esto"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
| Campo | Tipo | Descripción |
|
||
|
|
| --------------- | -------- | ------------------------------------------------------------------ |
|
||
|
|
| `themeId` | string | ID del MainTheme activo. Útil para guardar contexto en n8n/DB. |
|
||
|
|
| `subThemeId` | string | ID del SubTheme activo (la conversación actual). |
|
||
|
|
| `themeTitle` | string | Título del tema (legible). |
|
||
|
|
| `subThemeTitle` | string | Título del subtema (legible). |
|
||
|
|
| `history` | array | Mensajes previos `{role, content}` (orden cronológico). |
|
||
|
|
| `message` | string | Texto que el usuario acaba de escribir (NO está incluido en history).|
|
||
|
|
|
||
|
|
`role` es `"user"` | `"assistant"`.
|
||
|
|
|
||
|
|
## 3. Response — `200 OK` (JSON)
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"reply": "Respuesta en **Markdown** del asistente…",
|
||
|
|
"keyNotes": [
|
||
|
|
{
|
||
|
|
"type": "summary",
|
||
|
|
"title": "Resumen de la conversación",
|
||
|
|
"content": "Puntos clave tratados…"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"type": "todo",
|
||
|
|
"title": "Tareas pendientes",
|
||
|
|
"items": [
|
||
|
|
{ "text": "Revisar la documentación", "done": false },
|
||
|
|
{ "text": "Configurar el webhook", "done": true }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Reglas
|
||
|
|
|
||
|
|
- `reply` (**obligatorio**, `string`): texto de respuesta. Se renderiza como **Markdown**
|
||
|
|
(soporta GFM: listas, tablas, bloques de código, etc.).
|
||
|
|
- `keyNotes` (**opcional**, `array`): notas que se añaden al SubTheme activo con
|
||
|
|
`source: "n8n"`. El usuario puede editarlas/eliminarlas libremente.
|
||
|
|
|
||
|
|
### Tipos de KeyNote
|
||
|
|
|
||
|
|
| `type` | Requiere |
|
||
|
|
| --------- | -------------------------------------------------------- |
|
||
|
|
| `summary` | `title` + `content` (string, Markdown plano) |
|
||
|
|
| `todo` | `title` + `items[]` con `{ text: string, done?: boolean }` |
|
||
|
|
| `free` | `title` + `content` |
|
||
|
|
|
||
|
|
`done` es opcional y por defecto `false`.
|
||
|
|
|
||
|
|
## 4. Errores y timeouts
|
||
|
|
|
||
|
|
- Cualquier status HTTP fuera del rango 2xx se trata como error y se marca el mensaje
|
||
|
|
como `status: "error"`. El usuario puede pulsar **Reintentar**.
|
||
|
|
- Timeout por defecto: **120 s**. La solicitud puede cancelarse con el botón **Detener**
|
||
|
|
(usa `AbortController`), lo que aborta el fetch hacia n8n.
|
||
|
|
|
||
|
|
## 5. Ejemplo de workflow n8n (orientativo)
|
||
|
|
|
||
|
|
```
|
||
|
|
Webhook (POST /webhook/chat)
|
||
|
|
→ Set (extraer body.message, body.history, body.themeTitle…)
|
||
|
|
→ [tu LLM / lógica]
|
||
|
|
→ Set (construir JSON { reply, keyNotes })
|
||
|
|
→ Respond to Webhook (JSON, 200)
|
||
|
|
```
|
||
|
|
|
||
|
|
> En n8n usa el nodo **Respond to Webhook** con `Respond With: JSON` y en `Response Body`
|
||
|
|
> pega el objeto `{ "reply": ..., "keyNotes": [...] }`.
|
||
|
|
|
||
|
|
## 6. Evolución futura (streaming / persistencia en DB)
|
||
|
|
|
||
|
|
- **Streaming:** el contrato queda preparado para añadir SSE (`text/event-stream`)
|
||
|
|
más adelante sin romper la UI (el indicador "escribiendo…" ya existe).
|
||
|
|
- **Persistencia:** el estado vive hoy en `localStorage`. Para sincronizar con una DB
|
||
|
|
vía n8n, añade endpoints `GET/POST /webhook/state` y reemplaza el adapter en
|
||
|
|
`src/store/persistence.ts` (punto único de intercambio).
|