Metadata-Version: 2.4
Name: rotbot
Version: 1.0.0
Summary: Multi-platform AI chatbot with Bring Your Own Key support — Ollama, OpenAI, Anthropic, Gemini, Groq, OpenRouter
Author: Harshit Saxena
License: MIT
Project-URL: Homepage, https://github.com/imarkinfotechllc/rotbot
Project-URL: Repository, https://github.com/imarkinfotechllc/rotbot
Project-URL: Issues, https://github.com/imarkinfotechllc/rotbot/issues
Keywords: chatbot,ai,discord,telegram,signal,ollama,openai,anthropic,gemini,byok
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Communications :: Chat
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: requests>=2.31.0
Requires-Dist: aiohttp>=3.9.0
Requires-Dist: feedparser>=6.0.0
Requires-Dist: duckduckgo-search>=4.0.0
Requires-Dist: beautifulsoup4>=4.12.0
Provides-Extra: discord
Requires-Dist: discord.py>=2.3.0; extra == "discord"
Requires-Dist: yt-dlp>=2024.1.0; extra == "discord"
Provides-Extra: telegram
Requires-Dist: pyTelegramBotAPI>=4.14.0; extra == "telegram"
Provides-Extra: signal
Provides-Extra: openai
Requires-Dist: openai>=1.0.0; extra == "openai"
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.30.0; extra == "anthropic"
Provides-Extra: google
Requires-Dist: google-generativeai>=0.5.0; extra == "google"
Provides-Extra: groq
Requires-Dist: groq>=0.5.0; extra == "groq"
Provides-Extra: math
Requires-Dist: sympy>=1.12; extra == "math"
Provides-Extra: all
Requires-Dist: discord.py>=2.3.0; extra == "all"
Requires-Dist: yt-dlp>=2024.1.0; extra == "all"
Requires-Dist: pyTelegramBotAPI>=4.14.0; extra == "all"
Requires-Dist: sympy>=1.12; extra == "all"
Requires-Dist: openai>=1.0.0; extra == "all"
Requires-Dist: anthropic>=0.30.0; extra == "all"
Requires-Dist: google-generativeai>=0.5.0; extra == "all"
Requires-Dist: groq>=0.5.0; extra == "all"
Dynamic: license-file

# BotServer

**A multi-platform AI chatbot that connects Discord, Telegram, and Signal to locally-running Ollama LLMs.**

Zero cloud AI dependencies — all inference runs on your own hardware through a local Ollama server. Your conversations stay private, your data stays local.

```
Discord ─┐
Telegram ─┤──▶ BotServer ──▶ Ollama (local) ──▶ LLM on your GPU
Signal  ──┘
```

---

## Table of Contents

- [Features](#features)
- [Architecture](#architecture)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Configuration](#configuration)
- [Running the Bots](#running-the-bots)
- [Commands Reference](#commands-reference)
- [AI Modes](#ai-modes)
- [How Streaming Works](#how-streaming-works)
- [Context Awareness](#context-awareness)
- [Security & Guardrails](#security--guardrails)
- [Access Control](#access-control)
- [Music Playback (Discord)](#music-playback-discord)
- [News Feeds](#news-feeds)
- [Project Structure](#project-structure)
- [Troubleshooting](#troubleshooting)

---

## Features

| Feature | Discord | Telegram | Signal |
|---|:---:|:---:|:---:|
| Streaming responses (live-edit) | Yes (0.6s) | Yes (1.0s) | Buffered |
| Conversation history (10 msgs) | Yes | Yes | Yes |
| Context-aware prompts | Yes | Yes | Yes |
| AI mode switching | Yes | Yes | Yes |
| Custom model per user | Yes | Yes | Yes |
| Web search + AI summary | Yes | Yes | Yes |
| Deep thinking (DeepSeek-R1) | Spoiler tags | Spoiler tags | Separate msg |
| Music playback | Yes (voice) | — | YouTube links |
| News feeds (RSS) | Yes | — | Yes |
| Access control | Open | Location-based | Phone-based |
| Typing indicators | — | — | Yes |
| Group support | Yes | Yes | Yes (commands only) |
| Output guardrails (PII/secrets) | Yes | Yes | Yes |
| Input guardrails (injection) | Yes | Yes | Yes |

---

## Architecture

```
User Message
     │
     ▼
┌─────────────────────────────────────────────┐
│  Platform Bot                                │
│  (discord_bot / telegram_bot / signal_bot)   │
└─────────────┬───────────────────────────────┘
              │
              ▼
┌─────────────────────────┐
│  Guardrails (Input)     │ ── Prompt injection detection
│  guardrails.py          │ ── Content safety checks
│                         │ ── Rate limiting
└─────────────┬───────────┘
              │
              ▼
┌─────────────────────────┐
│  Context Analyzer        │ ── Topic detection (8 categories)
│  context_analyzer.py     │ ── Intent classification
│                          │ ── Entity extraction
│                          │ ── Pronoun referent resolution
└─────────────┬────────────┘
              │
              ▼
┌─────────────────────────┐
│  Ollama Handler          │ ── Sync & async streaming
│  ollama_handler.py       │ ── /api/generate & /api/chat
│                          │ ── Model keep-alive (VRAM)
└─────────────┬────────────┘
              │
              ▼
┌─────────────────────────┐
│  Think Parser            │ ── DeepSeek-R1 <think> tag parsing
│  think_parser.py         │ ── Streaming state machine
└─────────────┬────────────┘
              │
              ▼
┌─────────────────────────┐
│  Guardrails (Output)     │ ── PII redaction
│  guardrails.py           │ ── API key/token scrubbing
│                          │ ── Infrastructure URL filtering
└─────────────┬────────────┘
              │
              ▼
     Platform Response
     (formatted, split, streamed)
```

### Module Breakdown

| Module | Lines | Purpose |
|---|---|---|
| `discord_bot.py` | ~1070 | Discord bot with streaming, music, news |
| `telegram_bot.py` | ~1270 | Telegram bot with location-based access control |
| `signal_bot.py` | ~1070 | Signal bot via signal-cli JSON-RPC (fully async) |
| `ollama_handler.py` | ~230 | Ollama API wrapper (sync + async streaming) |
| `context_analyzer.py` | ~390 | Keyword-based conversation analysis (zero ML overhead) |
| `think_parser.py` | ~120 | Streaming `<think>` tag state machine parser |
| `web_search.py` | ~85 | DuckDuckGo search with retry logic |
| `guardrails.py` | ~590 | 5-layer input/output security system |
| `access_store.py` | ~160 | Thread-safe persistent user approval store |

---

## Prerequisites

- **Python 3.10+**
- **[Ollama](https://ollama.com)** installed and running locally
- At least one LLM pulled (e.g., `ollama pull llama3.1:8b`)
- **For Discord:** A Discord bot token ([Discord Developer Portal](https://discord.com/developers/applications))
- **For Telegram:** A bot token from [@BotFather](https://t.me/BotFather)
- **For Signal:** [signal-cli](https://github.com/AsamK/signal-cli) installed and linked to a phone number
- **For Discord music:** [FFmpeg](https://ffmpeg.org/) installed and in PATH

---

## Installation

1. **Clone the repository:**
   ```bash
   git clone https://github.com/your-username/BotServer.git
   cd BotServer
   ```

2. **Install Python dependencies:**
   ```bash
   pip install discord.py pyTelegramBotAPI aiohttp requests feedparser yt-dlp qrcode duckduckgo-search python-dotenv
   ```

3. **Pull Ollama models:**
   ```bash
   ollama pull llama3.1:8b        # General mode
   ollama pull deepseek-r1:8b     # Reasoning mode
   ollama pull qwen3-coder        # Coding mode (adjust tag as needed)
   ```

4. **Create your `.env` file** (see [Configuration](#configuration) below).

5. **Start Ollama** (if not already running):
   ```bash
   ollama serve
   ```

---

## Configuration

Create a `.env` file in the project root with the following variables:

```env
# ── Discord ──────────────────────────────────
DISCORD_BOT_TOKEN=your_discord_bot_token_here

# ── Telegram ─────────────────────────────────
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
TELEGRAM_ADMIN_ID=your_numeric_telegram_user_id

# ── Signal ───────────────────────────────────
SIGNAL_PHONE_NUMBER=+1234567890          # Bot's linked phone number
SIGNAL_CLI_HOST=localhost                # signal-cli daemon host
SIGNAL_CLI_PORT=7583                     # signal-cli daemon port
SIGNAL_ADMIN_NUMBER=+1234567890          # Admin's phone number

# ── Ollama ───────────────────────────────────
OLLAMA_BASE_URL=http://localhost:11434   # Ollama server URL
OLLAMA_DEFAULT_MODEL=llama3.1:8b         # Default model for general mode
```

> **Note:** Only configure the platforms you plan to use. Each bot loads only its own variables.

---

## Running the Bots

### Run individually

```bash
python discord_bot.py      # Starts Discord bot
python telegram_bot.py     # Starts Telegram bot
python signal_bot.py       # Starts Signal bot (requires signal-cli daemon)
```

### Run all at once

**Windows (batch):**
```bash
botserver.bat
```
This launches each bot in its own terminal window, including the signal-cli daemon.

**Windows (PowerShell):**
```powershell
.\start_all.ps1
```
Monitors all processes and reports exits. Ctrl+C stops everything cleanly.

**Linux/macOS:**
```bash
./start_all.sh
```
Runs all bots in background, traps SIGINT/SIGTERM for clean shutdown.

### Signal-specific setup

Signal requires a running `signal-cli` daemon:

```bash
signal-cli -a +YOUR_NUMBER daemon --tcp 7583
```

To link a new device, use the included helper:
```bash
python signal_link.py    # Generates QR code for Signal linking
```

> Each bot binds a singleton port (Discord: 47001, Telegram: 47002, Signal: 47003) to prevent duplicate instances.

---

## Commands Reference

### Chat & Modes

| Command | Discord | Telegram | Signal | Description |
|---|---|---|---|---|
| Switch to General | `!chat` | `/chat` | `/chat` | llama3.1:8b — general assistant |
| Switch to Coding | `!coder` | `/coder` | `/coder` | qwen3-coder — code-focused |
| Switch to Reasoning | `!think` | `/think` | `/think` | deepseek-r1:8b — step-by-step |
| Toggle thinking display | `!deepthink` | `/deepthink` | `/deepthink` | Show/hide `<think>` reasoning |
| Reset history | `!reset` | `/reset` | `/reset` | Clear conversation memory |

### Questions & Search

| Command | Discord | Telegram | Signal | Description |
|---|---|---|---|---|
| One-shot question | `!ask <q>` | `/ask <q>` | `/ask <q>` | No history, direct answer |
| Problem solver | `!solve <q>` | `/solve <q>` | `/solve <q>` | Uses deepseek-r1 |
| Web search | `!search <q>` | `/search <q>` | `/search <q>` | DuckDuckGo + AI summary |

### Model Management

| Command | Discord | Telegram | Signal | Description |
|---|---|---|---|---|
| Show current model | `!model` | `/model` | `/model` | Displays active mode & model |
| Set custom model | `!setmodel <name>` | `/setmodel <name>` | `/setmodel <name>` | Override with any Ollama model |
| List available models | `!models` | `/models` | `/models` | Fetches live list from Ollama |

> `!setmodel` also accepts a number (e.g., `!setmodel 3`) to pick from the models list.

### Music (Discord only)

| Command | Description |
|---|---|
| `!play <song>` | Search YouTube and play in voice channel |
| `!skip` | Skip current track |
| `!pause` / `!resume` | Pause or resume playback |
| `!stop` | Stop and disconnect from voice |
| `!queue` | Show upcoming tracks |
| `!volume <0-100>` | Set playback volume |

### Music (Signal)

| Command | Description |
|---|---|
| `/music <song>` | Returns YouTube search results |
| `/recommend <mood/genre>` | AI-generated music suggestions |

### News Feeds

| Command | Platform | Description |
|---|---|---|
| `!news [category] [count]` | Discord | Google News RSS headlines |
| `/news [category] [count]` | Signal | Google News RSS headlines |

Categories: `top`, `tech`, `science`, `world`, `business`

### Admin Commands (Telegram & Signal)

| Command | Description |
|---|---|
| `/approve [id]` | Approve a pending user |
| `/deny [id]` | Deny a pending user |
| `/revoke <id>` | Revoke an approved user |
| `/pending` | List pending access requests |
| `/users` | List all approved users |

### Default behavior

- **Discord:** @mention the bot or type in its channel for a streaming conversation
- **Telegram:** Any message from an approved user gets a streaming AI response
- **Signal DMs:** Plain text messages get streaming AI responses
- **Signal Groups:** Only `/commands` are processed (no free-text chat)

---

## AI Modes

BotServer offers three switchable AI personalities per user:

### General Mode (default)
- **Model:** `llama3.1:8b`
- **Best for:** Everyday questions, conversation, general knowledge
- **System prompt:** Helpful, friendly assistant with conversation context awareness

### Coding Mode
- **Model:** `qwen3-coder:480b-cloud`
- **Best for:** Code generation, debugging, technical explanations
- **System prompt:** Expert programmer focused on clean, efficient code

### Reasoning Mode
- **Model:** `deepseek-r1:8b`
- **Best for:** Complex problems, math, logic, step-by-step analysis
- **System prompt:** Deep analytical thinker showing reasoning process
- **Special:** Produces `<think>...</think>` blocks showing internal reasoning

Users can also override their model with `!setmodel` / `/setmodel` to use any model available on their Ollama server.

---

## How Streaming Works

All bots stream responses token-by-token from Ollama, but display them differently:

**Discord** edits the reply message every **0.6 seconds** with accumulated tokens. If a response exceeds 2000 characters, it splits into multiple messages. While generating, the bot shows rotating "thinking" status phrases (81 unique phrases).

**Telegram** edits the reply message every **1.0 seconds** (longer interval to respect Telegram rate limits). Responses are capped at 4000 characters per message.

**Signal** buffers the entire response since Signal doesn't support message editing. It sends typing indicators while generating. Long responses are split at 4000-character boundaries.

After every response, performance stats are appended:

```
⏱ 3.2s  |  ⚙ llama3.1:8b  |  ↑ 142 tokens  |  ↓ 256 tokens  |  42.1 tok/s
```

---

## Context Awareness

BotServer enriches every prompt with conversation intelligence — without making extra LLM calls:

1. **Topic Detection** — Scans the last 6 messages for keywords across 8 categories (programming, math, science, writing, business, health, gaming, music) and tells the model what the conversation is about.

2. **Intent Classification** — Determines if the user is asking a question, debugging, brainstorming, learning, or just chatting. The model adjusts its response style accordingly.

3. **Entity Extraction** — Identifies repeated nouns and key terms, helping the model maintain focus on what matters.

4. **Referent Resolution** — When a user says "fix it" or "explain that," the analyzer determines what "it" or "that" refers to from conversation history.

5. **Conversation Type** — Labels the chat as debugging, Q&A, learning, brainstorming, or casual — giving the model meta-awareness of the interaction style.

6. **Geolocation** (Telegram only) — If the user shared their location, it's included in the system prompt for location-aware responses.

All analysis is keyword/pattern-based (regex + word frequency), adding negligible latency.

---

## Security & Guardrails

BotServer implements a **5-layer security system** via `guardrails.py`:

### Layer 1: Input Filtering
- **Prompt injection detection** — Catches "forget previous instructions," "act as DAN," "bypass rules," and other common jailbreak patterns
- **Encoded evasion detection** — Flags Base64, hex escapes, and HTML entity attempts
- **Educational context awareness** — Avoids false positives on legitimate questions (e.g., "how to ignore errors in bash")
- **Rate limiting** — 3 suspicious probes per user in 10 minutes triggers a 30-minute block

### Layer 2: Content Safety
- Blocks requests involving violence, self-harm, CSAM, illegal activity, and hate speech
- Severity levels: critical, high, medium, low

### Layer 3: Output Filtering
- **PII redaction** — SSNs, credit card numbers
- **Secret scrubbing** — API keys, JWT tokens, bot tokens, environment variables
- **Infrastructure hiding** — Localhost URLs, file paths, internal endpoints
- **Smart context** — Preserves code blocks and avoids redacting model self-references

### Layer 4: Prompt-Level Safety
- A `SAFETY_GUARDRAIL` string is appended to every prompt sent to Ollama, instructing the model to refuse harmful requests

### Layer 5: Operational Security
- Log sanitization (redacts emails, tokens, phone numbers, URLs)
- Message length enforcement (4000 chars message, 200 chars search query, 500 chars command arg)

---

## Access Control

### Discord
Open to all server members — no approval needed. Security is handled at the Discord server level.

### Telegram
New users go through a **location-based approval flow:**

1. User sends `/start` — bot asks them to share their location
2. User shares location via keyboard button
3. Request goes to **pending** with name, username, and coordinates
4. Admin receives notification and reviews with `/pending`
5. Admin runs `/approve` or `/deny`
6. Approved users can chat freely; denied users are removed

### Signal
Phone-number-based approval:

1. New user sends a message — bot notifies admin
2. Admin approves with `/approve +phone_number`
3. Approved users can chat in DMs and use commands in groups

All approval data persists in `approved_users.json` (thread-safe, auto-saving).

---

## Music Playback (Discord)

Discord bot includes a full music player with queue management:

- Searches YouTube via **yt-dlp** and streams audio into voice channels
- **Queue system** — add multiple songs, skip, view upcoming tracks
- **Volume control** — adjustable 0–100%
- **Auto-detection** — finds FFmpeg from PATH or common Windows install locations
- Requires the bot to be in a voice channel (auto-joins when you use `!play`)

---

## News Feeds

Discord and Signal bots can fetch headlines from **Google News RSS**:

```
!news tech 5       # 5 latest tech headlines (Discord)
/news science 3    # 3 latest science headlines (Signal)
```

Available categories: `top` (default), `tech`, `science`, `world`, `business`

---

## Project Structure

```
BotServer/
├── discord_bot.py        # Discord bot (streaming, music, news)
├── telegram_bot.py       # Telegram bot (location-based access)
├── signal_bot.py         # Signal bot (async JSON-RPC)
├── ollama_handler.py     # Ollama API wrapper
├── context_analyzer.py   # Conversation intelligence
├── think_parser.py       # DeepSeek-R1 <think> tag parser
├── web_search.py         # DuckDuckGo search integration
├── guardrails.py         # 5-layer security system
├── access_store.py       # Persistent user approval store
├── gen_qr.py             # QR code generator utility
├── signal_link.py        # Signal device linking helper
├── approved_users.json   # User approval data (auto-generated)
├── .env                  # Configuration (create manually)
├── botserver.bat         # Windows launcher (batch)
├── start_all.ps1         # Windows launcher (PowerShell)
├── start_all.sh          # Linux/macOS launcher
└── CLAUDE.md             # AI coding assistant instructions
```

---

## Troubleshooting

**Bot won't start — "Address already in use"**
Each bot uses a singleton port (47001/47002/47003). Another instance is already running. Kill the existing process or restart.

**Ollama connection refused**
Make sure Ollama is running (`ollama serve`) and the `OLLAMA_BASE_URL` in `.env` matches your setup.

**Slow first response**
The first request after startup loads the model into VRAM. BotServer pre-loads models with `keep_alive()` to minimize this. Subsequent responses are fast.

**Signal bot can't connect**
Ensure signal-cli is running as a daemon: `signal-cli -a +YOUR_NUMBER daemon --tcp 7583`. The bot auto-reconnects with exponential backoff if the connection drops.

**Discord music not working**
FFmpeg must be installed and accessible. On Windows, the bot also checks `C:\ffmpeg\bin\` and `C:\Program Files\ffmpeg\bin\`. Verify with `ffmpeg -version`.

**Telegram bot not responding to messages**
The user may not be approved. Check `/pending` as admin, or verify the user completed the location-sharing step.

**"Model not found" errors**
Run `ollama list` to see available models. Pull missing ones with `ollama pull <model_name>`.

---

## State Management

All per-user state is stored in **memory** (module-level dictionaries) and is **not persisted** across restarts:

- `user_modes[user_id]` — Current AI mode (general / coding / reasoning)
- `user_custom_models[user_id]` — Custom model override
- `deep_thinking_enabled[user_id]` — Whether to show `<think>` blocks
- `conversation_history[key]` — Last 10 messages per user

The only persisted state is `approved_users.json` for access control.

---

## License

This project is provided as-is for personal and educational use.
