feat: n8n initial commit — JavaScript (Node.js) n8n workflow automation + axios/cheerio/puppeteer/xlsx

This commit is contained in:
2026-07-03 12:15:42 -04:00
commit f4731fa87e
11 changed files with 3561 additions and 0 deletions
+518
View File
@@ -0,0 +1,518 @@
# Voz → Calendario Nextcloud — Blueprint Completo
**Versión:** 1.0
**Fecha:** 2026-07-03
**Autor:** Álvaro
**n8n:** https://n8n.crewinghunters.com
---
## Visión General
Grabas un audio en el teléfono → se lo mandas al bot de Telegram → la IA local transcribe y entiende el evento → aparece en tu calendario de Nextcloud → te recuerda 30 minutos antes por Telegram.
```
📱 Audio (teléfono)
▼ Telegram
┌─────────────────────────────────────────────────┐
│ n8n (Raspberry Pi 4 — Colombia) │
│ │
│ 1. Recibe audio de Telegram │
│ 2. Descarga el archivo .ogg/.mp3 │
│ 3. Llama a Whisper API (tu PC via Tailscale) │
│ 4. Llama a Ollama (tu PC via Tailscale) │
│ 5. Crea evento en Nextcloud Calendar (CalDAV) │
│ 6. Confirma por Telegram │
│ 7. Programa recordatorio 30min antes │
└─────────────────────────────────────────────────┘
▼ Tailscale VPN (túnel privado gratis)
┌─────────────────────────────────────────────────┐
│ Tu PC (Windows) │
│ ├── Ollama → AsistentePersonal / qwen2.5:14b │
│ └── Whisper API → faster-whisper (Python) │
└─────────────────────────────────────────────────┘
```
---
## Stack Tecnológico
| Componente | Herramienta | Dónde corre |
|-----------|------------|------------|
| Automatización | n8n | RPi4 Colombia |
| Bot mensajería | Telegram Bot | Cloud (Telegram) |
| Transcripción voz | faster-whisper | Tu PC (Windows) |
| LLM extracción evento | Ollama / qwen2.5:14b | Tu PC (Windows) |
| Calendario | Nextcloud CalDAV | RPi4 Colombia |
| Túnel privado | Tailscale | PC + RPi4 |
| API transcripción | FastAPI (Python) | Tu PC (Windows) |
---
## PASO 1 — Tailscale (conectar PC con RPi4)
Tailscale crea una red privada entre tus dispositivos. Una vez instalado, tu PC tendrá una IP tipo `100.x.x.x` accesible desde el RPi4 sin abrir puertos ni router.
### En tu PC (Windows)
1. Descarga e instala Tailscale: https://tailscale.com/download/windows
2. Inicia sesión con Google o email
3. Anota tu IP Tailscale: aparece en el icono de la bandeja del sistema
- Ejemplo: `100.64.1.10`
### En el RPi4 (via SSH desde Colombia)
```bash
# Conectar al RPi4
ssh usuario@n8n.crewinghunters.com
# Instalar Tailscale en RPi4
curl -fsSL https://tailscale.com/install.sh | sh
# Iniciar y autenticar (con la MISMA cuenta que en el PC)
sudo tailscale up
# Verificar que ve tu PC
tailscale ping 100.64.1.10 # ← IP de tu PC Tailscale
```
✅ Si el ping responde, están conectados. El RPi4 puede hablar con tu PC.
---
## PASO 2 — Whisper API en tu PC
Instalamos faster-whisper y levantamos una API HTTP que n8n puede llamar.
### Instalar faster-whisper
```bash
# En tu PC (PowerShell)
pip install faster-whisper fastapi uvicorn python-multipart
```
### Crear el servidor API
Guarda este archivo en: `C:\whisper-api\server.py`
```python
from fastapi import FastAPI, UploadFile, File
from faster_whisper import WhisperModel
import tempfile, os
app = FastAPI()
# Carga el modelo una vez al iniciar (medium es bueno para español)
# Opciones: "tiny", "base", "small", "medium", "large-v3"
model = WhisperModel("medium", device="cpu", compute_type="int8")
@app.post("/transcribe")
async def transcribe(file: UploadFile = File(...)):
# Guardar audio temporalmente
suffix = os.path.splitext(file.filename)[1] or ".ogg"
with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
tmp.write(await file.read())
tmp_path = tmp.name
# Transcribir
segments, info = model.transcribe(tmp_path, language="es")
text = " ".join([seg.text for seg in segments]).strip()
os.unlink(tmp_path)
return {"text": text, "language": info.language}
@app.get("/health")
def health():
return {"status": "ok"}
```
### Script para iniciar la API (guarda como `C:\whisper-api\start.bat`)
```bat
@echo off
cd C:\whisper-api
uvicorn server:app --host 0.0.0.0 --port 8765
```
### Iniciar automáticamente con Windows
1. Presiona `Win + R` → escribe `shell:startup`
2. Crea un acceso directo a `start.bat` en esa carpeta
3. La API estará disponible en: `http://100.64.1.10:8765` (via Tailscale)
### Verificar que funciona (desde RPi4)
```bash
# Desde el RPi4 via SSH
curl http://100.64.1.10:8765/health
# Debe responder: {"status":"ok"}
```
---
## PASO 3 — Exponer Ollama via Tailscale
Por defecto Ollama solo escucha en localhost. Hay que permitir que escuche en todas las interfaces.
### En tu PC (PowerShell como Administrador)
```powershell
# Agregar variable de entorno para Ollama
[System.Environment]::SetEnvironmentVariable("OLLAMA_HOST", "0.0.0.0:11434", "Machine")
# Reiniciar Ollama (busca en la bandeja del sistema → clic derecho → Quit, luego reabre)
```
### Verificar desde RPi4
```bash
curl http://100.64.1.10:11434/api/tags
# Debe listar tus modelos
```
---
## PASO 4 — Bot de Telegram
### Crear el bot
1. Abre Telegram → busca `@BotFather`
2. Escribe `/newbot`
3. Nombre del bot: `Mi Calendario Personal` (o el que quieras)
4. Username: `mi_calendario_alvaro_bot` (debe terminar en `_bot`)
5. BotFather te da un **token** — guárdalo: `7123456789:AAF...`
### Obtener tu Chat ID
1. Escribe cualquier mensaje a tu nuevo bot
2. Abre en el navegador (reemplaza TOKEN):
```
https://api.telegram.org/botTOKEN/getUpdates
```
3. Busca `"id"` dentro de `"chat"` — ese número es tu **Chat ID**
- Ejemplo: `123456789`
---
## PASO 5 — Nextcloud Calendar (CalDAV)
n8n se conecta al calendario de Nextcloud via CalDAV.
### Obtener la URL CalDAV
En Nextcloud → Calendario → ⚙️ (engranaje junto al calendario) → "Copiar enlace privado"
La URL tiene esta forma:
```
https://tu-nextcloud.com/remote.php/dav/calendars/USUARIO/personal/
```
### Credenciales
- Usuario: tu usuario de Nextcloud
- Contraseña: genera una **contraseña de aplicación** en Nextcloud:
Configuración → Seguridad → Dispositivos y sesiones → "Crear nueva contraseña de aplicación"
- Nombre: `n8n-calendario`
---
## PASO 6 — Organizar Carpetas en n8n
Antes de crear el workflow, organiza las carpetas:
1. Abre https://n8n.crewinghunters.com
2. En el panel izquierdo → "Workflows" → "Add folder"
3. Crea estas carpetas:
```
📁 Prisa Yachts ← mueve el bot de WhatsApp aquí
📁 Personal - Productividad
📁 AIS Navigator
📁 Pruebas / Sandbox
```
4. El nuevo workflow irá en `📁 Personal - Productividad`
---
## PASO 7 — Workflow n8n Completo
Nombre del workflow: `🎙️ Voz → Calendario Nextcloud`
Carpeta: `Personal - Productividad`
### Nodos del workflow (en orden):
```
[Telegram Trigger]
[IF: ¿es audio?]
│ sí
[HTTP: Descargar audio de Telegram]
[HTTP: Whisper API → transcripción]
[HTTP: Ollama → extraer evento]
[Code: parsear JSON respuesta Ollama]
[HTTP: Crear evento CalDAV en Nextcloud]
[Telegram: Confirmar al usuario]
[Wait: esperar hasta 30min antes del evento]
[Telegram: Enviar recordatorio]
```
---
### Nodo 1 — Telegram Trigger
```
Tipo: Telegram Trigger
Credential: (crear nueva → Token del bot)
Updates: message
```
### Nodo 2 — IF: ¿Es audio?
```
Tipo: IF
Condición: {{ $json.message.voice }} existe
O {{ $json.message.audio }} existe
```
### Nodo 3 — HTTP: Descargar audio de Telegram
```
Tipo: HTTP Request
Método: GET
URL: https://api.telegram.org/bot{{ $env.TELEGRAM_TOKEN }}/getFile
Parámetros:
file_id: {{ $json.message.voice.file_id }}
```
Luego un segundo HTTP Request para descargar el archivo:
```
URL: https://api.telegram.org/file/bot{{ $env.TELEGRAM_TOKEN }}/{{ $json.result.file_path }}
Respuesta: archivo binario
```
### Nodo 4 — HTTP: Whisper API (transcripción)
```
Tipo: HTTP Request
Método: POST
URL: http://100.64.1.10:8765/transcribe ← IP Tailscale de tu PC
Body: form-data
file: [archivo de audio del nodo anterior]
```
Resultado esperado:
```json
{ "text": "Reunión con Juan el viernes a las diez de la mañana en el puerto" }
```
### Nodo 5 — HTTP: Ollama (extraer evento)
```
Tipo: HTTP Request
Método: POST
URL: http://100.64.1.10:11434/api/generate
Body JSON:
{
"model": "qwen2.5:14b",
"stream": false,
"prompt": "Extrae el evento de esta frase y devuelve SOLO JSON válido sin explicaciones:\n\nFrase: '{{ $json.text }}'\n\nFecha actual: {{ $now.format('YYYY-MM-DD') }}, {{ $now.format('dddd') }}\n\nDevuelve exactamente este formato:\n{\"titulo\": \"...\", \"fecha\": \"YYYY-MM-DD\", \"hora_inicio\": \"HH:MM\", \"hora_fin\": \"HH:MM\", \"lugar\": \"...\", \"descripcion\": \"...\"}\n\nSi no hay hora fin, suma 1 hora a la hora inicio. Si no hay lugar, pon vacío."
}
```
### Nodo 6 — Code: Parsear respuesta Ollama
```javascript
// Extraer el JSON de la respuesta de Ollama
const responseText = $input.item.json.response;
// Buscar el JSON dentro del texto (por si Ollama añade texto extra)
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
if (!jsonMatch) throw new Error("Ollama no devolvió JSON válido: " + responseText);
const evento = JSON.parse(jsonMatch[0]);
// Construir fechas iCal (formato: 20260704T100000)
const fechaInicio = evento.fecha.replace(/-/g, '') + 'T' + evento.hora_inicio.replace(':', '') + '00';
const fechaFin = evento.fecha.replace(/-/g, '') + 'T' + evento.hora_fin.replace(':', '') + '00';
// UID único para el evento
const uid = 'n8n-' + Date.now() + '@crewinghunters.com';
// Formato iCalendar (CalDAV)
const ical = `BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//n8n//Calendario Voz//ES
BEGIN:VEVENT
UID:${uid}
DTSTART:${fechaInicio}
DTEND:${fechaFin}
SUMMARY:${evento.titulo}
LOCATION:${evento.lugar || ''}
DESCRIPTION:${evento.descripcion || 'Creado por voz via n8n'}
END:VEVENT
END:VCALENDAR`;
return {
json: {
...evento,
ical,
uid,
fechaInicio,
fechaFin,
// Para el recordatorio: fecha ISO completa
fechaRecordatorio: new Date(evento.fecha + 'T' + evento.hora_inicio + ':00').toISOString()
}
};
```
### Nodo 7 — HTTP: Crear evento en Nextcloud (CalDAV)
```
Tipo: HTTP Request
Método: PUT
URL: https://tu-nextcloud.com/remote.php/dav/calendars/USUARIO/personal/{{ $json.uid }}.ics
Autenticación: Basic Auth
Usuario: tu_usuario_nextcloud
Password: contraseña_de_aplicacion
Headers:
Content-Type: text/calendar; charset=utf-8
Body: {{ $json.ical }}
```
### Nodo 8 — Telegram: Confirmar
```
Tipo: Telegram
Operación: Send Message
Chat ID: {{ $env.TELEGRAM_CHAT_ID }}
Texto:
✅ *Evento creado en tu calendario*
📅 *{{ $json.titulo }}*
🗓 {{ $json.fecha }}
🕐 {{ $json.hora_inicio }} {{ $json.hora_fin }}
📍 {{ $json.lugar || 'Sin ubicación' }}
_Te recordaré 30 minutos antes_ ⏰
```
### Nodo 9 — Wait (hasta 30min antes del evento)
```
Tipo: Wait
Modo: Until specified time
Fecha/Hora: {{ $json.fechaRecordatorio }}
Offset: -30 minutos
```
### Nodo 10 — Telegram: Recordatorio
```
Tipo: Telegram
Operación: Send Message
Chat ID: {{ $env.TELEGRAM_CHAT_ID }}
Texto:
⏰ *Recordatorio — en 30 minutos:*
📅 *{{ $json.titulo }}*
🕐 {{ $json.hora_inicio }}
📍 {{ $json.lugar || '' }}
```
---
## PASO 8 — Variables de Entorno en n8n
En n8n → Settings → Variables → Agregar:
| Variable | Valor |
|---------|-------|
| `TELEGRAM_TOKEN` | `7123456789:AAF...` (token del bot) |
| `TELEGRAM_CHAT_ID` | `123456789` (tu chat ID) |
| `WHISPER_URL` | `http://100.64.1.10:8765` |
| `OLLAMA_URL` | `http://100.64.1.10:11434` |
| `NEXTCLOUD_URL` | `https://tu-nextcloud.com` |
| `NEXTCLOUD_USER` | `tu_usuario` |
| `NEXTCLOUD_PASS` | `contraseña_de_aplicacion` |
---
## PASO 9 — Prueba Completa
1. Graba un audio en el teléfono diciendo:
> *"Reunión con Federico el próximo martes a las tres de la tarde en el puerto de Miami"*
2. Envía el audio al bot de Telegram
3. En ~10-15 segundos deberías recibir:
```
✅ Evento creado en tu calendario
📅 Reunión con Federico
🗓 2026-07-07
🕐 15:00 16:00
📍 Puerto de Miami
```
4. Verifica en Nextcloud Calendar que el evento aparece
5. Espera el recordatorio 30 min antes ✅
---
## Checklist de Instalación
### En tu PC (Windows)
- [ ] Instalar Tailscale → anotar IP (`100.x.x.x`)
- [ ] `pip install faster-whisper fastapi uvicorn python-multipart`
- [ ] Crear `C:\whisper-api\server.py` (código arriba)
- [ ] Crear `C:\whisper-api\start.bat`
- [ ] Agregar `start.bat` al inicio de Windows
- [ ] Iniciar la API y verificar: `curl http://localhost:8765/health`
- [ ] Configurar Ollama para escuchar en `0.0.0.0`: variable `OLLAMA_HOST`
### En el RPi4 (via SSH)
- [ ] `curl -fsSL https://tailscale.com/install.sh | sh`
- [ ] `sudo tailscale up` → autenticar con la misma cuenta
- [ ] Verificar ping a PC: `tailscale ping 100.x.x.x`
- [ ] Verificar Whisper: `curl http://100.x.x.x:8765/health`
- [ ] Verificar Ollama: `curl http://100.x.x.x:11434/api/tags`
### En Telegram
- [ ] Crear bot con @BotFather → guardar token
- [ ] Obtener tu Chat ID
- [ ] Escribir un mensaje al bot para activarlo
### En Nextcloud
- [ ] Copiar URL CalDAV del calendario
- [ ] Crear contraseña de aplicación para n8n
### En n8n
- [ ] Crear carpetas: Prisa Yachts / Personal / AIS Navigator / Sandbox
- [ ] Crear variables de entorno (8 variables)
- [ ] Crear workflow `🎙️ Voz → Calendario Nextcloud`
- [ ] Agregar los 10 nodos en orden
- [ ] Activar el workflow
- [ ] Prueba con audio real
---
## Solución de Problemas
| Problema | Causa probable | Solución |
|---------|---------------|---------|
| n8n no llega a Whisper | Tailscale no conectado | `sudo tailscale up` en RPi4 |
| Whisper tarda mucho | Modelo "medium" pesado en CPU | Cambiar a "small" en server.py |
| Ollama no responde | OLLAMA_HOST no configurado | Reiniciar Ollama tras la variable |
| Evento en fecha incorrecta | Ollama interpretó mal el día | Ajustar el prompt con más contexto |
| CalDAV 401 Unauthorized | Contraseña de app incorrecta | Crear nueva contraseña en Nextcloud |
| Audio no se procesa | Formato no soportado | Telegram envía .ogg — faster-whisper lo soporta |
---
## Mejoras Futuras (Fase 2)
- [ ] **Cancelar eventos por voz**: "Cancela la reunión del martes" → n8n borra el evento
- [ ] **Consultar agenda**: "¿Qué tengo mañana?" → n8n lee el CalDAV y responde
- [ ] **Recordatorio personalizable**: "Recuérdame 1 hora antes"
- [ ] **Múltiples calendarios**: personal, trabajo, AIS Navigator
- [ ] **Texto además de voz**: si escribes (no mandas audio), también funciona
---
*Blueprint generado: 2026-07-03 | AR Electronics / Álvaro*