A RAG-powered WhatsApp auto-reply bot that runs entirely on your Android phone via Termux - no server, no cloud hosting, no monthly fees.
WhatsApp
│
▼
WhatsAuto ──── POST /reply ────► groq-bot (Flask)
│
┌─────────┴──────────┐
│ │
TF-IDF search Session memory
(your docs) (per sender)
│
▼
Groq LLM ──► { "reply": "..." }
│
▼
Cloudflare Tunnel
(public HTTPS URL)
- Zero heavy dependencies - pure-Python TF-IDF retrieval, no
numpyorsentence-transformers; compiles on ARM without issues - Conversation memory - per-sender session history with configurable TTL and turn limit; the bot remembers context across messages
- Stays silent when it should - relevance threshold prevents the bot from replying when no document matches the question
- Response cache - repeated questions skip the Groq API call entirely
- Permanent public URL - optional named Cloudflare tunnel so your WhatsAuto webhook URL never changes between restarts
- Fully self-installing -
bot startinstalls Python packages, cloudflared, and termux-api automatically on first run, skipping anything already present - Wake lock - acquires an Android wake lock on start so the bot keeps running when the screen is off
| Requirement | Notes |
|---|---|
| Termux | Install from F-Droid, not Google Play (the Play version is outdated) |
| Termux:API app | Free companion app - required for wake lock. Install manually from F-Droid or Google Play |
| WhatsAuto | Or any app that can POST incoming WhatsApp messages to a webhook |
| Groq API key | Free tier is sufficient |
bot.shautomatically installs all Termux packages and Python dependencies on first run. The only thing you need to install manually is the Termux:API Android app - Android does not allow apps to install other apps programmatically.
1. Download the files into Termux
pkg install git
git clone https://github.com/cedroid/groq-bot.git
cd groq-bot
chmod +x bot.sh2. Install the bot command
bash bot.shThis copies the script to your $PATH as bot and exits. All dependencies are installed automatically on first bot start.
3. Install the Termux:API companion app
Download from F-Droid or Google Play. Required for the wake lock that keeps the bot alive when your screen is off.
4. Set your Groq API key
bot config5. Add your knowledge base
Drop .txt files into ~/groq-bot/docs/ - these are the documents the bot will use to answer questions.
bot reindex6. Start
bot startThe bot starts, opens a Cloudflare tunnel, acquires a wake lock, and prints your public URL:
┌──────────────────────────────────────────────────────────────────┐
│ Public URL : https://abc-def-123.trycloudflare.com │
│ Endpoint : https://abc-def-123.trycloudflare.com/reply │
└──────────────────────────────────────────────────────────────────┘
Use that endpoint URL in WhatsAuto.
| Command | Description |
|---|---|
bot start |
Start server + open Cloudflare tunnel + acquire wake lock |
bot stop |
Stop server + close tunnel + release wake lock |
bot restart |
Restart everything |
bot status |
Show running status, public URL, and doc count |
bot logs |
Stream server logs in real time (Ctrl-C to quit) |
bot chat |
Interactive terminal chat for local testing |
bot config |
Edit API key, model, and all settings interactively |
bot reindex |
Rebuild the document index from docs/ (no restart needed) |
bot tunnel-setup |
One-time setup for a permanent Cloudflare URL |
bot uninstall |
Remove all bot files and the bot command |
- Open WhatsAuto → Server
- Paste your public URL with
/replyappended:https://abc-def-123.trycloudflare.com/reply - Method:
POST| Type:JSON - Save
WhatsAuto sends this payload to the bot:
{
"app": "WhatsAuto",
"sender": "Contact Name",
"phone": "+521234567890",
"message": "the incoming message text",
"group_name": "Group name, or empty for direct messages"
}The bot responds with:
{ "reply": "the response text" }When reply is an empty string, WhatsAuto sends nothing - this happens when the question scores below the relevance threshold and the bot decides to stay silent.
By default each restart generates a new random trycloudflare.com URL, which means you'd need to update WhatsAuto after every restart. To get a fixed URL that never changes, run the guided setup once:
bot tunnel-setupThis requires:
- A free Cloudflare account
- A domain you control added to Cloudflare (a free subdomain via
*.pages.devworks too)
After setup, bot start always uses the same hostname — no further changes to WhatsAuto needed.
The bot answers questions exclusively from the .txt files in ~/groq-bot/docs/. It will not fabricate answers - if no document is relevant enough, it stays silent.
~/groq-bot/docs/
cabins.txt ← cabin descriptions, amenities, pricing
faq.txt ← frequently asked questions
policies.txt ← check-in times, cancellation, house rules
Plain text works best. After adding or editing any file:
bot reindexNo restart required. You can also trigger a live reindex from any HTTP client:
curl -X POST http://localhost:5000/reindexRun bot config to edit settings interactively, or edit ~/groq-bot/config.json directly.
| Key | Default | Description |
|---|---|---|
api_key |
(required) | Your Groq API key |
model |
llama-3.1-8b-instant |
Groq model to use |
relevance_threshold |
0.08 |
Minimum cosine similarity score to trigger a reply. Raise it to make the bot more selective; set to 0 to always reply |
session_ttl |
1800 |
Seconds of inactivity before a conversation session expires (default: 30 min) |
session_max_turns |
8 |
Maximum number of conversation turns kept in memory per sender |
top_k |
5 |
Number of document chunks retrieved per query |
chunk_words |
400 |
Words per document chunk |
chunk_overlap |
100 |
Word overlap between consecutive chunks |
system_prompt |
(see bot.py) | The LLM system prompt - customise the bot's persona here |
Environment variables override config.json and are useful for scripting:
export GROQ_API_KEY="gsk_..."
export GROQ_MODEL="llama-3.3-70b-versatile"
export BOT_PORT=8080| Method | Path | Description |
|---|---|---|
POST |
/reply |
Main webhook. Accepts JSON, form data, or URL query params |
GET |
/health |
Returns { status, chunks, model, sessions } |
POST |
/reindex |
Rebuild the document index without restarting |
DELETE |
/session/<sender> |
Clear conversation history for a specific sender |
~/groq-bot/
├── bot.py # Flask server, TF-IDF engine, session store, Groq client
├── bot.sh # Termux service manager (install, start, stop, tunnel…)
├── config.json # Runtime configuration (created by bot config)
├── vectors.json # Document index cache (created by bot reindex)
├── cache.json # Response cache
├── bot.log # Server log (stream with bot logs)
├── docs/ # ← put your .txt knowledge base files here
└── cloudflare/ # Named tunnel credentials (created by bot tunnel-setup)
Recommended .gitignore if you fork this project:
config.json
vectors.json
cache.json
bot.log
*.pid
cloudflare/
docs/
venv/
__pycache__/
*.pyc- A WhatsApp message arrives → WhatsAuto POSTs it to
/reply - The bot looks up the sender's session (conversation history)
- TF-IDF retrieval finds the most relevant chunks from your documents
- If the best relevance score is below the threshold → return empty reply (silence)
- The context chunks + conversation history are sent to the Groq LLM
- The reply is stored in the session and returned to WhatsAuto
- WhatsAuto sends the reply back to the WhatsApp contact
bot start fails immediately
Run bot logs right after — the most common cause is a missing API key. Run bot config to set it.
WhatsAuto shows Error: null
The server is receiving the request (check bot logs for POST /reply 200). This is a display bug in WhatsAuto's test button — it shows null even on successful responses. Test with a real WhatsApp message instead.
Bot always replies "I will confirm that information with our team"
Your docs/ folder is empty or the question isn't covered by your documents. Add relevant .txt files and run bot reindex.
Bot stops when the screen turns off
Make sure the Termux:API companion app is installed. The wake lock requires both pkg install termux-api (done automatically) and the Android app.
URL changes every time I restart
Run bot tunnel-setup once to configure a named Cloudflare tunnel with a permanent hostname.
MIT - do whatever you want with it.