Skip to content
BotServBotServ
SignalBotBot IAOllamasignal-cliE2EEPrivacySelf-Hosting

Bot Signal con IA Local

Crea un bot Signal con signal-cli y Ollama: chats IA cifrados E2E, JSON-RPC, grupos y Docker.

S

schutzgeist

7 min read
Bot Signal con IA Local

Bot de Signal con IA local

Qué cubre este artículo

  • Cómo construir un bot de Signal con signal-cli y Ollama.
  • Registro de número de bot y emparejamiento de dispositivo.
  • Recepción y envío mediante JSON-RPC y modo daemon.
  • Extensiones: grupos, RAG, adjuntos, reacciones.
  • Por qué Signal es la plataforma de bots más privada.

Introducción

Signal es la única plataforma convencional con cifrado de extremo a extremo genuino para todo, incluidos los mensajes de bot. Si necesitas un bot de IA para comunicación confidencial (periodistas, abogados, secretos empresariales), Signal es tu opción.

El inconveniente: no existe una API oficial de bot. El enfoque estándar es signal-cli, un CLI de Java que implementa el protocolo Signal y ofrece modo daemon con JSON-RPC. Técnicamente, tu bot es un “cliente de Signal” que funciona como un dispositivo normal.

Casos de uso típicos

  • Asistente de IA confidencial: Los chats permanecen cifrados de extremo a extremo hasta tu servidor, ideal para preguntas sensibles.
  • Bot para familia o equipo: Comunicación interna sin Meta, Google ni nubes.
  • Alertas: Notificaciones de monitoreo cifradas de extremo a extremo en el móvil (mejor que email).
  • Asistente de documentos: Envía documentos confidenciales por Signal para procesar localmente.
  • Contacto editorial: Las fuentes pueden hablar anónimamente con la IA.

Requisitos previos

  • Un número de teléfono para el bot (funciona teléfono fijo: verificación por llamada; o segunda SIM/eSIM)
  • Java 17+ (signal-cli es Java) o la imagen Docker
  • Ollama con un modelo (como llama3.1:8b)
  • Python para la lógica del bot

Paso 1: instalar y registrar signal-cli

# Descarga binaria (Linux)
wget https://github.com/AsamK/signal-cli/releases/download/v0.13.x/signal-cli-0.13.x-Linux.tar.gz
sudo tar xf signal-cli-*.tar.gz -C /opt
sudo ln -s /opt/signal-cli-*/bin/signal-cli /usr/local/bin/signal-cli

Registra el número (requiere captcha: obtén el enlace de https://signalcaptchas.org/):

signal-cli -a +4917612345678 register
signal-cli -a +4917612345678 verify 123456
signal-cli -a +4917612345678 updateProfile --name "Asistente de IA"

Alternativa: vincula el bot como dispositivo a tu cuenta existente. El bot enviará mensajes como tú (adecuado para asistentes personales, no para bots públicos):

signal-cli link -n "Bot-Server"
# devuelve enlace sgnl:// → muéstralo como código QR en el móvil (p. ej., con qrencode) y escanéalo

Paso 2: modo daemon con JSON-RPC

signal-cli puede ejecutarse como daemon JSON-RPC. Tu código Python se comunica por TCP o HTTP:

# Daemon TCP
signal-cli -a +4917612345678 daemon --tcp 127.0.0.1:7583

# o HTTP (estilo REST)
signal-cli -a +4917612345678 daemon --http 127.0.0.1:8080

Métodos JSON-RPC (selección): send, receive, listGroups, sendTyping, addReaction, updateProfile.

Paso 3: lógica del bot con Ollama

La forma más simple es un loop de receive mediante llamadas CLI (bueno para empezar):

#!/usr/bin/env python3
import json
import subprocess
import ollama

BOT_NUMBER = "+4917612345678"
MODEL = "llama3.1:8b"
ALLOWED = {"+491701234567"}          # Quién puede usar el bot
conversations = {}

client = ollama.Client(host="http://localhost:11434")

def send(recipient, text):
    subprocess.run([
        "signal-cli", "-a", BOT_NUMBER, "send",
        "-m", text, recipient
    ], check=False)

def ask_ollama(user, text):
    history = conversations.setdefault(user, [])
    history.append({"role": "user", "content": text})
    history = history[-10:]
    resp = client.chat(
        model=MODEL,
        messages=[{"role": "system", "content":
                   "Eres un asistente útil. Responde brevemente."}] + history,
    )
    answer = resp["message"]["content"]
    history.append({"role": "assistant", "content": answer})
    conversations[user] = history
    return answer

def main():
    proc = subprocess.Popen(
        ["signal-cli", "-a", BOT_NUMBER, "receive", "-t", "-1",
         "--output", "json"],
        stdout=subprocess.PIPE, text=True,
    )
    for line in proc.stdout:
        line = line.strip()
        if not line:
            continue
        try:
            envelope = json.loads(line)
        except json.JSONDecodeError:
            continue
        msg = envelope.get("envelope", {})
        source = msg.get("sourceNumber") or msg.get("source")
        data = msg.get("dataMessage")
        if not data or source not in ALLOWED:
            continue
        text = data.get("message")
        if not text:
            continue
        print(f"[{source}] {text}")
        answer = ask_ollama(source, text)
        # Límite de Signal: ~64k, pero las respuestas cortas son mejores
        send(source, answer[:6000])

if __name__ == "__main__":
    main()

Funciona inmediatamente: modo polling, sin webhooks.

Extensiones

Funcionamiento en grupos

signal-cli puede gestionar grupos. El bot responde en grupos solo si se menciona o hay un prefijo:

data = msg.get("dataMessage")
group = data.get("groupInfo")          # {"groupId": "...", "type": "..."}
text = data.get("message") or ""

if group:
    if not text.startswith("!ki"):
        continue
    text = text[3:].strip()
    # La respuesta va al grupo:
    subprocess.run(["signal-cli", "-a", BOT_NUMBER, "send",
                    "-g", group["groupId"], "-m", answer])

Crea o gestiona grupos por CLI:

signal-cli -a +49... updateGroup -n "IA-Equipo" -m +491701234567 +491702345678
signal-cli -a +49... listGroups

Reacciones e indicador de escritura

# Mostrar que está escribiendo
signal-cli -a +49... sendTyping +491701234567

# Enviar reacción
signal-cli -a +49... sendReaction -e "👍" -a +491701234567 -t 1695123456789 +491701234567

Adjuntos: imágenes a modelo de visión

dataMessage.attachments contiene rutas de archivos: envía imágenes a minicpm-v o llava, audio a Whisper:

for att in data.get("attachments", []):
    if att.get("contentType", "").startswith("image/"):
        resp = client.chat(model="minicpm-v", messages=[{
            "role": "user",
            "content": "¿Qué hay en esta imagen?",
            "images": [att["file"]],
        }])
        send(source, resp["message"]["content"])

RAG como en Telegram

Patrón idéntico: embedding del mensaje → Qdrant → contexto en el prompt del sistema. Ver Bot de Telegram con RAG y RAG local.

Implementación

Docker: signal-cli como daemon

services:
  signal-cli:
    image: registry.gitlab.com/morph027/signal-cli-daemon:latest
    volumes:
      - signal_data:/home/.local/share/signal-cli
    environment:
      - MODE=json-rpc
      - SIGNAL_NUMBER=+4917612345678
    ports:
      - "127.0.0.1:7583:7583"
    restart: always

  signal-bot:
    build: ./bot
    restart: always
    depends_on: [signal-cli, ollama]

  ollama:
    image: ollama/ollama:latest
    volumes: [ollama_data:/root/.ollama]

volumes:
  signal_data:
  ollama_data:

systemd sin Docker

[Unit]
Description=Bot de IA Signal
After=network-online.target

[Service]
Type=simple
User=signalbot
WorkingDirectory=/opt/signal-bot
ExecStart=/usr/bin/python3 bot.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Privacidad, la verdadera razón para elegir Signal

  • E2EE completo: Los mensajes se cifran de extremo a extremo entre el remitente y el servidor del bot. Los servidores de Signal solo ven metadatos y además los minimizan.
  • Sin publicidad ni rastreo: Signal es una asociación sin ánimo de lucro.
  • Código abierto: El cliente, el servidor y signal-cli son de código abierto.
  • Límite importante: El bot descifra los mensajes en tu servidor, así que aplicas tus propias reglas. De todas formas, Signal sigue viendo los metadatos (quién escribe y cuándo).

Problemas comunes

  • Captcha en el registro: Signal exige captchas durante el registro. Solución: registra la cuenta primero en un teléfono, luego vincula el bot como dispositivo asociado.
  • Número bloqueado: Si Signal bloquea el número (raro), ejecuta signal-cli ... register de nuevo.
  • El daemon falla: signal-cli está hecho en Java; si se queda sin memoria, establece JAVA_OPTS="-Xmx512m".
  • Recepción se ralentiza: En el bucle receive, las respuestas lentas bloquean el flujo. Traslade las llamadas a Ollama a un hilo o async.
  • Sealed Sender: Los mensajes de contactos desconocidos requieren confianza. Use signal-cli trust -a <número> para añadir contactos.

Enlaces relacionados

Puntos clave:

  • Los bots de Signal se ejecutan sobre signal-cli (daemon + JSON-RPC), no mediante una API oficial.
  • Es la única plataforma con E2EE completo, perfecta para bots confidenciales.
  • Configuración: registra el número o vincula como dispositivo asociado, luego inicia el bucle de recepción.
  • Extensiones como en cualquier otra plataforma: grupos, RAG, visión, Whisper.
  • Para bots públicos es engorroso. Telegram es más simple, Signal es más privado.

FAQ

¿Existe una API oficial de bots para Signal?

No. signal-cli (de AsamK) es el estándar no oficial, un cliente Signal completo como CLI/Daemon. Es de código abierto y se mantiene desde hace años, pero sin apoyo oficial de Signal.

¿Necesito un número de teléfono propio?

No necesariamente. Puedes vincular el bot como dispositivo asociado a tu cuenta (enviaría mensajes en tu nombre). Para un bot independiente se requiere un número propio, pero vale una línea fija o una segunda SIM.

¿Están realmente cifrados los mensajes del bot?

Sí. Signal cifra todo de extremo a extremo, incluidos los chats con bots. El mensaje se descifra solo en tu servidor. Esto convierte a Signal en la mejor opción para comunicación confidencial con bots.

El registro falla por captcha, ¿qué hago?

Resuelve el captcha en signalcaptchas.org y pasa el token al registro. O bien registra el número primero en un teléfono real, luego vincula el bot como dispositivo asociado, lo que evita ese proceso.

¿Funciona el bot en grupos?

Sí. Añade el bot al grupo y los mensajes llegarán con groupInfo en el envelope. El bot puede responder al grupo, gestionar miembros (updateGroup) y reaccionar.

¿Es signal-cli lo suficientemente rápido?

Para bots sí. Los mensajes llegan en menos de un segundo. El cuello de botella es siempre la inferencia local de IA, no el transporte. Solo el overhead de Java consume unos 200-400 MB de RAM.

¿Signal o Matrix para bots privados?

Signal: mejor E2EE (también minimiza metadatos), pero API no oficial. Matrix: API oficial para bots (matrix-nio), servidor auto-hospedable, E2EE opcional. Para pura privacidad elige Signal, para integración y control elige Matrix.

Fuentes y lecturas recomendadas

Volver al blog
Share:

Entradas relacionadas