--- title: DeepSeek-OCR Full-Page CSV emoji: πŸ“„ colorFrom: blue colorTo: green sdk: gradio sdk_version: 5.49.1 python_version: "3.10" app_file: app.py pinned: false --- # πŸ€– Qwen Telegram Bot A Telegram bot backed by **Qwen2.5-1.5B-Instruct** running on Hugging Face **ZeroGPU** (free tier), with streaming responses, per-user token access, and a full admin panel for monitoring conversations, managing tokens, and exporting logs. Built to survive the ZeroGPU free tier: no Docker, no external servers, no paid APIs. --- ## ✨ Features ### For users (Telegram) - πŸ”’ **Token-gated access** β€” only users with an admin-issued token can chat - ⚑ **Streaming replies** β€” see the response as it's generated - πŸ’» **Proper code formatting** β€” Markdown β†’ Telegram HTML, with language-tagged code boxes - πŸ“œ **Conversation memory** β€” rolling window of past turns (configurable) - 🧹 `/reset` to clear the current chat's memory - πŸ“Š `/stats` to see your own usage ### For admin (web panel) - πŸ” **Password-gated** admin tab inside the Gradio UI - πŸ“Š **Dashboard** β€” users, turns, GPU quota consumed today - πŸ‘₯ **User management** β€” view, revoke, delete users - πŸ’¬ **Conversation logs** β€” filter by user, search, view full history - πŸ“€ **Export logs** β€” JSON / CSV / Markdown, full conversation dump - 🎟️ **Token management** β€” generate individually, bulk-generate, revoke, reassign - βš™οΈ **Runtime settings** β€” system prompt, temperature, top_p, max tokens, conversation window, daily limit - 🩺 **Health** β€” recent GPU calls, latency, quota status --- ## πŸ—οΈ Architecture ``` Telegram ──webhook──▢ HF Space (Gradio SDK, ZeroGPU) β”‚ β”œβ”€β”€ Gradio UI (Status + Admin tabs) β”œβ”€β”€ /webhook β†’ bot logic β”œβ”€β”€ /health β†’ keep-alive target β”œβ”€β”€ /admin/* β†’ admin API β”‚ β”œβ”€β”€ SQLite (/data/bot.db) users, tokens, convs, gpu_log └── @spaces.GPU generate_stream() β”‚ β–Ό Qwen2.5-1.5B on Blackwell GPU (48 GB slice) ``` - **Single Gradio app** β€” admin panel is a tab, not a separate mount (this avoids the 33 s Node SSR startup hang) - **Route injection at index 0** β€” `/webhook` and `/health` take priority over Gradio's catch-all - **Model loaded at module scope** β€” ZeroGPU "packs" weights to disk; each `@spaces.GPU` call attaches the GPU - **All persistence in the main process** β€” SQLite in WAL mode; conversation state survives GPU worker forks --- ## πŸš€ Deployment ### 1. Create the Space - Go to https://huggingface.co/new-space - **SDK:** Gradio - **Hardware:** ZeroGPU (free tier is fine) - **Visibility:** Private or Public β€” your choice ### 2. Get a Telegram bot token - Message [@BotFather](https://t.me/BotFather) β†’ `/newbot` - Save the token (looks like `123456789:ABC...`) ### 3. Configure Space secrets Settings β†’ **Variables and secrets** β†’ add: | Name | Required | Value | |---|---|---| | `TELEGRAM_BOT_TOKEN` | βœ… | Bot token from BotFather | | `PUBLIC_URL` | βœ… | `https://-.hf.space` (your Space URL, no trailing slash) | | `TELEGRAM_WEBHOOK_SECRET` | ⭐ recommended | Random string β€” Telegram will send it in `X-Telegram-Bot-Api-Secret-Token` | | `ADMIN_PASSWORD` | ⭐ recommended | Password for the web admin panel. **Default: `tom123`** β€” change it! | | `ADMIN_TELEGRAM_IDS` | optional | Comma-separated Telegram IDs allowed to use `/admin` bot command | | `MODEL_ID` | optional | Override model. Default: `thirdeyeai/Qwen2.5-1.5B-Instruct-uncensored` | | `TELEGRAM_PROXY` | optional | Cloudflare Worker URL if `api.telegram.org` is blocked in your Space's region | ### 4. Upload the files Push the repo (git, web upload, or HF CLI). Structure: ``` . β”œβ”€β”€ app.py β”œβ”€β”€ requirements.txt β”œβ”€β”€ README.md β”œβ”€β”€ admin/ β”‚ β”œβ”€β”€ __init__.py β”‚ β”œβ”€β”€ auth.py β”‚ β”œβ”€β”€ exports.py β”‚ └── panel.py β”œβ”€β”€ bot/ β”‚ β”œβ”€β”€ __init__.py β”‚ β”œβ”€β”€ onboarding.py β”‚ β”œβ”€β”€ streaming.py β”‚ β”œβ”€β”€ telegram_api.py β”‚ └── webhook.py β”œβ”€β”€ db/ β”‚ β”œβ”€β”€ __init__.py β”‚ β”œβ”€β”€ init.py β”‚ β”œβ”€β”€ models.py β”‚ └── schema.sql β”œβ”€β”€ model/ β”‚ β”œβ”€β”€ __init__.py β”‚ └── qwen.py └── utils/ β”œβ”€β”€ __init__.py β”œβ”€β”€ audit.py β”œβ”€β”€ health.py └── quota.py ``` ### 5. Wait for the build First boot downloads ~3 GB of model weights. Watch the **Logs** tab for: ``` Loading weights: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| db: DB initialised at /data/bot.db app: Launching Gradio... app: Boot complete. Blocking. ``` ### 6. Register the webhook The app auto-registers on boot if `PUBLIC_URL` is set. Verify with: ``` https://api.telegram.org/bot/getWebhookInfo ``` You should see your Space URL and no `last_error_message`. ### 7. Keep it awake ZeroGPU Spaces sleep after idle. Set up an **external** pinger: **Option A β€” cron-job.org** (free, 5 min) - URL: `https://-.hf.space/health` - Interval: every 5 minutes **Option B β€” GitHub Actions** ```yaml name: keepalive on: schedule: [{cron: "*/5 * * * *"}] jobs: ping: runs-on: ubuntu-latest steps: - run: curl -fsS https://-.hf.space/health || true ``` ⚠️ **Internal heartbeats don't count.** The container must receive external traffic. ### 8. First admin login - Visit `https://-.hf.space/` - Click **πŸ” Admin Panel** tab - Enter `tom123` (or your `ADMIN_PASSWORD`) ### 9. Issue your first token - Admin β†’ **🎟️ Tokens** tab β†’ **Generate batch (1)** - Copy the token - In Telegram, DM your bot: `/token ` - You'll see **Token accepted.** β€” you can now chat --- ## πŸ’¬ Telegram Commands | Command | Description | |---|---| | `/start` | Welcome / onboarding | | `/token VALUE` | Submit or replace your access token | | `/reset` | Clear this chat's conversation memory | | `/stats` | Show your usage stats | | `/help` | List commands | | `/admin` | (Admin IDs only) β€” reminder of the web admin URL | --- ## 🌐 HTTP Endpoints | Method | Path | Purpose | |---|---|---| | GET | `/health` | Keep-alive target β€” returns JSON with uptime | | POST | `/webhook` | Telegram updates (validated by secret header) | | GET | `/admin` | Redirects to `/` (admin is a tab) | | GET | `/admin/quota` | JSON quota snapshot | | POST | `/admin/boot_webhook` | Re-register the Telegram webhook | --- ## πŸ—„οΈ Database Schema All tables live in `/data/bot.db` (persistent across Space restarts). | Table | Purpose | |---|---| | `users` | Telegram user records, `is_active` flag, token binding | | `tokens` | Issued tokens with `assigned_to`, `turns_used`, `last_used` | | `conversations` | Every user/assistant message with timestamps and latency | | `admin_audit` | Admin actions (boot, generate, revoke) | | `gpu_log` | Every GPU call with duration β€” used for quota tracking | | `settings` | Runtime-configurable key/value pairs | --- ## βš™οΈ Runtime Settings (Admin β†’ Settings tab) | Setting | Default | Notes | |---|---|---| | `system_prompt` | "You are a helpful assistant." | Change this to steer the model's behavior | | `conversation_window` | 6 turns | How many past turns are sent as context | | `max_new_tokens` | 1024 | Hard cap on reply length | | `temperature` | 0.7 | 0 = deterministic, 1.0 = creative | | `top_p` | 0.9 | Nucleus sampling cutoff | | `daily_turn_limit` | 100 | Max turns per user per day | Changes apply **immediately** to the next message β€” no restart needed. --- ## πŸ“€ Export Formats Admin β†’ Conversations β†’ Export: - **JSON** β€” full nested structure, one object per user with all their turns - **CSV** β€” flat, one row per message (best for spreadsheets) - **Markdown** β€” human-readable transcript per user Each message row includes timestamp, role, content, `latency_ms`, `gpu_time_ms`. --- ## 🧠 Free-Tier Reality Check ZeroGPU free tier gives roughly **300 seconds of GPU time per day**. A typical chat turn on a 1.5B model at BF16 costs **2–5 seconds**. That works out to roughly **60–100 turns per day** across all users. Practical implications: - **Admin β†’ Dashboard** shows `GPU seconds used today / 300` - The bot refuses new generations when usage exceeds ~280 s (safety margin) - **Keep conversations short** β€” larger `conversation_window` = more tokens = more GPU time - If you need more headroom, either: - Reduce `max_new_tokens` - Reduce `conversation_window` - Upgrade to HF PRO (~25Γ— more GPU quota) --- ## πŸ› οΈ Troubleshooting ### Bot replies to `/start` but ignores messages Check `user_has_valid_token` β€” the user must have redeemed a token via `/token`. ### `Bad Request: unsupported parse_mode` Only happens if you modified `telegram_api.py`. The fix: never send `parse_mode: null` β€” omit the key entirely for plain text. ### Messages are cut off mid-sentence Increase `max_new_tokens` in Admin β†’ Settings. Or ask for shorter responses. ### Code blocks show as raw text Means the model produced HTML that our converter didn't recognize. Check Admin β†’ Conversations to see the raw output and open an issue with the exact text. ### Space sleeps and cold-starts take 30 s External pinger isn't running. Check cron-job.org logs. Remember: only **external** traffic resets the idle timer. ### `Bad Request: message is too long` Shouldn't happen β€” we auto-split at 3900 chars. If you see it, a single HTML entity is likely breaking the length math; open an issue. --- ## ⚠️ Security Notes - **Never paste your `TELEGRAM_BOT_TOKEN` publicly.** If leaked, revoke it via BotFather (`/revoke` β†’ pick bot). - **Change `ADMIN_PASSWORD`** from the default `tom123` before going public. - **Set `TELEGRAM_WEBHOOK_SECRET`** β€” otherwise anyone who guesses your Space URL can POST fake updates. - The bot accepts **only text** messages. Photos, voice, and files are rejected β€” this is by design. - Conversation content is stored in plain SQLite. Don't paste secrets into the chat. --- ## πŸ“‹ Project Structure Notes - **`app.py`** β€” entry point. HfFolder shim β†’ Gradio build β†’ launch β†’ route injection β†’ block. - **`model/qwen.py`** β€” the only file with `@spaces.GPU`. Everything else runs on CPU. - **`bot/telegram_api.py`** β€” all Telegram HTTP calls, markdownβ†’HTML conversion, and message chunking. - **`db/models.py`** β€” all SQL. No ORM, just explicit queries. - **`admin/panel.py`** β€” Gradio Blocks built *inside* the main app context (no second mount). --- ## πŸ“œ License Personal project. Do whatever you want with it. --- ## πŸ™ Credits - Model: [thirdeyeai/Qwen2.5-1.5B-Instruct-uncensored](https://huggingface.co/thirdeyeai/Qwen2.5-1.5B-Instruct-uncensored) - ZeroGPU: [Hugging Face Spaces](https://huggingface.co/docs/hub/spaces-gpus) - Gradio: [gradio.app](https://gradio.app)