|
Download Readme.md from Hfzune/Test: direct link, hf CLI and curl.
- Browser
- Download file 11.2 kB
-
https://huggingface.co/spaces/Hfzune/Test/resolve/main/Readme.md
- Command line
-
hf download hf://spaces/Hfzune/Test/Readme.md
-
curl -L -o Readme.md https://huggingface.co/spaces/Hfzune/Test/resolve/main/Readme.md
11.2 kB
| 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://<user>-<space>.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<TOKEN>/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://<user>-<space>.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://<user>-<space>.hf.space/health || true | |
| ``` | |
| ⚠️ **Internal heartbeats don't count.** The container must receive external traffic. | |
| ### 8. First admin login | |
| - Visit `https://<user>-<space>.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 <that-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) |