Skip to main content
Glama
seasayDev

neonize-whatsapp-gateway

by seasayDev
README.md
# neonize-whatsapp-gateway

A small, reusable **WhatsApp capture + messaging layer** built on top of
[`neonize`](https://github.com/krypton-byte/neonize) (Python wrapper around
[`whatsmeow`](https://github.com/tulir/whatsmeow)).

Out of the box, `neonize`/`whatsmeow` does **not** give you an inbox: it
delivers messages using `@lid` (Linked-Device) JIDs and does not populate a
contacts table. This project fixes that with a thin capture + SQLite layer
and a set of MCP-compatible tools, so an LLM agent (Hermes, Claude, etc.)
can **read your messages, list chats, manage contacts, and reply**.

## Features

- πŸ“₯ **Inbox capture** β€” every incoming/outgoing message is stored in a local
  SQLite DB (`inbox.db`), with `from_me`, `media_type`, `pushname`, timestamp.
- ☎️ **Readable contacts** β€” LID JIDs are auto-resolved to real phone numbers
  via `get_pn_from_lid`, so your contact book is human-readable.
- πŸ’¬ **MCP-compatible stdio server** (`neonize_gateway.py`) exposing tools:
  `whatsapp_send`, `whatsapp_send_image`, `whatsapp_send_file`,
  `whatsapp_get_messages`, `whatsapp_list_chats`, `whatsapp_get_contacts`,
  `whatsapp_add_contact`, `whatsapp_reply`.
- πŸŽ™οΈ **Voice notes transcription** β€” `voice_handler.py` downloads incoming
  voice messages, decodes OGG/Opus β†’ WAV with ffmpeg, and transcribes them
  with [faster-whisper](https://github.com/SYSTRAN/faster-whisper). The
  transcript is stored in the inbox (and optionally auto-replied as text).
- πŸ”§ **Fully configurable** via environment variables β€” no hardcoded paths.

## Why this exists

> "Can you read my WhatsApp inbox? Why don't I have access to my contacts?
> Can you make the system read messages and reply to conversations?"

The stock library answers "no" to all three. This repo turns that into "yes".

## Install

```bash
pip install neonize        # ships prebuilt wheels with the Go backend
# or from this repo:
pip install -r requirements.txt
```

> **Platform note:** the Go backend needs **glibc**. On Android/Termux run
> everything inside `proot-distro login ubuntu`.

## Pair your account (first time only)

```bash
python pairing.py
```

It prints an 8-character code. In WhatsApp go to
**Linked Devices β†’ Link a device β†’ Link with phone number** and enter it.
The session is saved in the DB and you never pair again.

## Run

Capture only:
```bash
python capture_daemon.py
```

As an MCP server (stdio) β€” e.g. plug it into an LLM gateway:
```bash
python neonize_gateway.py
```

### Environment variables

| Variable        | Default      | Meaning                          |
|-----------------|--------------|----------------------------------|
| `NEONIZE_DB`    | `./bot.db`   | whatsmeow session DB             |
| `DB_PATH`       | (alias)      | same as `NEONIZE_DB`             |
| `INBOX_DB`      | `./inbox.db` | capture SQLite DB                |

Example:
```bash
NEONIZE_DB=/secure/bot.db INBOX_DB=/secure/inbox.db python capture_daemon.py
```

## MCP tools

| Tool | Description |
|------|-------------|
| `whatsapp_send` | Send a text message (phone or JID) |
| `whatsapp_send_image` | Send an image (local path or URL) |
| `whatsapp_send_file` | Send a document (local path or URL) |
| `whatsapp_get_messages` | Read last N captured messages (filter by chat/direction) |
| `whatsapp_list_chats` | List unique conversations |
| `whatsapp_get_contacts` | Read the contact book (local carnet + whatsmeow fallback) |
| `whatsapp_add_contact` | Manually register a contact (name β†’ JID) |
| `whatsapp_reply` | Send a message into an existing conversation |

The MCP server speaks JSON-RPC 2.0 over stdio, so any MCP-compatible client
can call these tools directly.

## Reading the inbox directly (no MCP needed)

```python
import sqlite3
c = sqlite3.connect("inbox.db")
for r in c.execute(
    "SELECT chat, from_me, text, media_type, timestamp "
    "FROM messages ORDER BY id DESC LIMIT 10"
):
    print(r)
```

## Voice notes (transcription)

`voice_handler.py` turns incoming WhatsApp voice messages into text:

```bash
# dependencies (mobile/CPU-friendly β€” no torch/CUDA)
pip install faster-whisper
# ffmpeg must be on PATH (or set FFMPEG_BIN to its absolute path)
apt-get install ffmpeg        # Debian/Ubuntu
# on Termux/Android ffmpeg lives at /data/data/com.termux/files/usr/bin/ffmpeg

python voice_handler.py                 # capture + log transcripts
AUTO_REPLY=1 python voice_handler.py    # also send the transcript back as a text reply
```

How it works: on a `MessageEv` with `audioMessage`, it calls
`download_media_with_path`, decodes the OGG/Opus blob to 16 kHz mono WAV with
ffmpeg, then runs `faster_whisper.WhisperModel("base","cpu")` and stores the
transcript in the inbox (`media_type = "voice"`, `text = "[voice] <transcript>"`).
The first run downloads the whisper model from HuggingFace (~140 MB for `base`).

> **Performance note:** use `faster-whisper` (CTranslate2, int8) rather than
> `openai-whisper` on phones β€” it avoids the ~800 MB torch/CUDA pull and is
> 5–10Γ— faster on ARM CPUs.

## Important caveats

- **One client per DB.** Only ONE neonize client may connect to the session
  DB at a time. Do **not** run `capture_daemon.py` and `neonize_gateway.py`
  against the same `NEONIZE_DB` simultaneously β€” the session will thrash.
- **`whatsmeow_contacts` is empty by default.** neonize does not force the
  WhatsApp contact app-state sync. This project builds its own contact book
  from captured messages + LID→PN resolution.
- **`MessageEv` only fires for received messages.** Sending via
  `send_message` does not echo an event to the same client. To verify
  capture, message yourself or have a contact reply.
- **ToS.** Automating WhatsApp may violate WhatsApp/Meta Terms of Service.
  Use for personal/experimental purposes at your own risk.

## License

MIT β€” use freely, but respect WhatsApp's terms.