← Volver al catálogo

🎙️ Servidor de webhooks Vapi (Voice Server)

Archivo: /Users/user/rifai-agents/agentes/voice/server.ts · Plist: com.rifai.voice-server · Horario: daemon permanente (KeepAlive=true, RunAtLoad=true). Escucha en el puerto 7411 (VOICE_SERVER_PORT), siempre activo. Vapi accede a él desde fuera vía el túnel cloudflared (com.rifai.voice-tunnel).

Qué hace

Es el cerebro receptor del departamento de voz. Expone un servidor Express que recibe los eventos de Vapi durante y al final de cada llamada, y un conjunto de endpoints de *function calling* que el assistant de voz consulta en vivo (estado de un pedido, info de un producto, stock, envíos, top ventas). Cuando una llamada termina, decide el resultado (CONFIRMADO/RECHAZADO/PENDIENTE/PROBLEMA), lo persiste, actualiza el tag del pedido en Shopify, encola reintentos si quedó pendiente y avisa por Telegram. Sin este servidor, las llamadas se lanzan pero nadie recoge el resultado.

Cómo funciona

1. Levanta Express en 0.0.0.0:7411 con GET /health.

2. POST /vapi/webhook (eventos generales): en end-of-call-report/call.ended extrae análisis, transcript, sentimiento, endedReason, duración y coste. Determina el result desde structuredData o, en su defecto, por heurística (no-answer/busy → PENDIENTE; <15s → PENDIENTE; regex sobre transcript → CONFIRMADO/RECHAZADO). Persiste con updateCallEnd. Lee shopify_order_id de la metadata de la llamada y: actualiza el tag del pedido (updateShopifyTag, limpia tags de estado previos y pone el nuevo), si quedó PENDIENTE encola reintento a 2h (queueForRetry), y notifica Telegram (cs_complaint si PROBLEMA/RECHAZADO, si no ops_tracking).

3. Endpoints de herramientas que el assistant llama en directo, cada uno devuelve texto natural en español listo para leer:

  • POST /vapi/tools/lookup-order — busca pedido por número (#1234) o id y devuelve items, total, ciudad y estado.
  • POST /vapi/tools/lookup-product — busca producto por título/keyword, devuelve precio, stock y descripción.
  • POST /vapi/tools/check-stock — stock total de un producto.
  • POST /vapi/tools/shipping-info — tiempos/costes de envío por zona (península, Canarias, Baleares, Ceuta/Melilla) + garantía.
  • POST /vapi/tools/top-products — top 3 más vendidos de los últimos 30 días.

4. extractToolArgs/toolResponse normalizan el formato de tool-call de Vapi.

Datos/APIs

  • Vapi (entrante): recibe webhooks y tool-calls. La URL pública la registra tunnel-keeper.sh en el assistant (serverUrl).
  • Shopify Admin REST (2024-10): consulta pedidos/productos y PUT de tags. Vars: SHOPIFY_STORE, SHOPIFY_ACCESS_TOKEN.
  • SQLite data/voice-calls.db (lib/voice-db.ts): updateCallEnd, queueForRetry.
  • Telegram vía tools/notify-router.ts (cs_complaint → Cristina; ops_tracking → Oscar).
  • Vars: VOICE_SERVER_PORT (default 7411), SHOPIFY_STORE, SHOPIFY_ACCESS_TOKEN.

Cómo probarlo

cd /Users/user/rifai-agents && npx tsx agentes/voice/server.ts

Esperado: imprime 🎙️ Voice Webhook Server on http://0.0.0.0:7411. Verificar salud en otra terminal:

curl -s http://localhost:7411/health

Debe devolver {"ok":true,"ts":...}. Para probar un tool, hacer un curl POST a /vapi/tools/lookup-order con {"message":{"toolCallList":[{"id":"t1","function":{"name":"lookup_order","arguments":"{\"order_number\":\"1234\"}"}}]}} y ver la respuesta en español. (Levantar manualmente colisiona con el daemon en 7411; parar el daemon antes o usar otro puerto con VOICE_SERVER_PORT.)

Si se rompe / recuperar

launchctl unload ~/Library/LaunchAgents/com.rifai.voice-server.plist
launchctl load   ~/Library/LaunchAgents/com.rifai.voice-server.plist

Logs: /Users/user/rifai-agents/logs/voice-server.out.log y .err.log. Si Vapi no recibe respuesta: comprobar que el daemon escucha en 7411 (curl /health), que el túnel com.rifai.voice-tunnel esté arriba y que la serverUrl actual del assistant apunte al .trycloudflare.com de data/tunnel-url.txt. La URL del túnel cambia en cada reinicio: tunnel-keeper.sh la re-registra automáticamente vía PATCH al assistant Vapi.

Cómo replicarlo

  • Servidor Express con /health, webhook genérico y endpoints de tools.
  • Lógica de clasificación de resultado (structuredData + heurística por endedReason/duración/transcript).
  • Cliente Shopify Admin (lectura pedidos/productos, PUT tags).
  • SQLite (updateCallEnd, queueForRetry).
  • Router de notificaciones Telegram.
  • Túnel público (cloudflared) que registre la serverUrl en el assistant Vapi — ver tunnel-keeper.sh + plist com.rifai.voice-tunnel.
  • Plist daemon con KeepAlive=true y RunAtLoad=true.