15 KiB
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)
- Descarga e instala Tailscale: https://tailscale.com/download/windows
- Inicia sesión con Google o email
- Anota tu IP Tailscale: aparece en el icono de la bandeja del sistema
- Ejemplo:
100.64.1.10
- Ejemplo:
En el RPi4 (via SSH desde Colombia)
# 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
# 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
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)
@echo off
cd C:\whisper-api
uvicorn server:app --host 0.0.0.0 --port 8765
Iniciar automáticamente con Windows
- Presiona
Win + R→ escribeshell:startup - Crea un acceso directo a
start.baten esa carpeta - La API estará disponible en:
http://100.64.1.10:8765(via Tailscale)
Verificar que funciona (desde RPi4)
# 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)
# 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
curl http://100.64.1.10:11434/api/tags
# Debe listar tus modelos
PASO 4 — Bot de Telegram
Crear el bot
- Abre Telegram → busca
@BotFather - Escribe
/newbot - Nombre del bot:
Mi Calendario Personal(o el que quieras) - Username:
mi_calendario_alvaro_bot(debe terminar en_bot) - BotFather te da un token — guárdalo:
7123456789:AAF...
Obtener tu Chat ID
- Escribe cualquier mensaje a tu nuevo bot
- Abre en el navegador (reemplaza TOKEN):
https://api.telegram.org/botTOKEN/getUpdates - Busca
"id"dentro de"chat"— ese número es tu Chat ID- Ejemplo:
123456789
- Ejemplo:
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
- Nombre:
PASO 6 — Organizar Carpetas en n8n
Antes de crear el workflow, organiza las carpetas:
- Abre https://n8n.crewinghunters.com
- En el panel izquierdo → "Workflows" → "Add folder"
- Crea estas carpetas:
📁 Prisa Yachts ← mueve el bot de WhatsApp aquí
📁 Personal - Productividad
📁 AIS Navigator
📁 Pruebas / Sandbox
- 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:
{ "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
// 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
-
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"
-
Envía el audio al bot de Telegram
-
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 -
Verifica en Nextcloud Calendar que el evento aparece
-
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.batal inicio de Windows - Iniciar la API y verificar:
curl http://localhost:8765/health - Configurar Ollama para escuchar en
0.0.0.0: variableOLLAMA_HOST
En el RPi4 (via SSH)
curl -fsSL https://tailscale.com/install.sh | shsudo 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