SilverElixir commited on
Commit
892d9dd
·
unverified ·
1 Parent(s): fc1a78a

Add files via upload

Browse files
Files changed (2) hide show
  1. docs/ARCHITECTURE.md +1 -1
  2. docs/README.md +118 -0
docs/ARCHITECTURE.md CHANGED
@@ -12,7 +12,7 @@ This document goes one level deeper than the main [README](../README.md) into ho
12
 
13
  ## Automatic model routing
14
 
15
- There is no `/model` or `/provider` command. The router builds a fresh candidate list for every message:
16
 
17
  - **A YouTube or website link** → Gemini only. It's the only provider that can read page content (`url_context`) or analyze a video by URL.
18
  - **A video or audio attachment** → Gemini only. OpenRouter's multimodal models only accept images as base64.
 
12
 
13
  ## Automatic model routing
14
 
15
+ Routing is fully automatic: the router builds a fresh candidate list for every message:
16
 
17
  - **A YouTube or website link** → Gemini only. It's the only provider that can read page content (`url_context`) or analyze a video by URL.
18
  - **A video or audio attachment** → Gemini only. OpenRouter's multimodal models only accept images as base64.
docs/README.md ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Lumen
3
+ colorFrom: yellow
4
+ colorTo: gray
5
+ sdk: docker
6
+ app_port: 7860
7
+ pinned: false
8
+ ---
9
+
10
+ <p align="center">
11
+ <img src="assets/lumen-banner.svg" alt="Lumen: Intelligence. Clarity." width="480">
12
+ </p>
13
+
14
+ A Telegram bot styled after Claude's tone and personality (direct, warm, light on hedging), running on Google Gemini and free OpenRouter models with automatic per-message routing between them. Lumen also generates images, downloads TikTok videos without watermarks, and reads text back as speech. It runs as a webhook service on Hugging Face Spaces (Docker).
15
+
16
+ **Stack:** Python 3.13 · aiogram · FastAPI · google-genai · Docker
17
+
18
+ > The YAML block above is Hugging Face Space metadata, not a mistake: this same `README.md` doubles as the Space card. Everything below it is normal GitHub documentation.
19
+
20
+ ## Features
21
+
22
+ - **Automatic model routing.** Every message goes to whichever provider actually has what it needs: web search and link reading go to Gemini, everything else defaults to free OpenRouter models, protecting Gemini's tight daily quota.
23
+ - **Streaming replies** with a self-calibrating typing-speed pacer, so answers type themselves in instead of landing in a few large chunks.
24
+ - **Defenses against prompt injection and identity leaks.** A deterministic input filter plus output scrubbers keep the bot from revealing which model or provider actually answered.
25
+ - **TikTok downloads** without watermarks: video, slideshows (including "live" photo slides), and original sound.
26
+ - **Image generation** through Pollinations.ai. The model is picked from the prompt itself (anime, fantasy, realism, quick sketch, or a general default).
27
+ - **Text-to-speech**, trying Fish Audio first and falling back to Gemini TTS.
28
+ - `/draw` and `/tts` also work as plain phrases at the start of a message ("draw a cat," "read this out loud"), no slash required.
29
+ - **Persistent state.** An optional Upstash Redis backend keeps chat history and quota counters alive across redeploys.
30
+ - **Error tracking** through an optional Sentry integration that scrubs secrets before sending anything.
31
+
32
+ ## How it works
33
+
34
+ Lumen is a single FastAPI + aiogram service. Telegram delivers updates to a webhook. Each message gets routed through a chain of candidate models (Gemini and/or OpenRouter), built on the fly from the message's content: attachments, links, and a couple of lightweight heuristics for "does this need current information" and "is this a heavy request." The first provider that answers wins; the other is tried as a fallback if its whole chain fails.
35
+
36
+ The codebase is a modular monolith. `bot.py` is the orchestrator; the rest is split into focused modules: `lumen_router_config.py` (model routing), `lumen_formatting.py` (markdown to Telegram HTML), `lumen_security.py` (injection and leak defenses), `lumen_images.py`, `lumen_tts.py`, `lumen_tiktok.py`, `lumen_telegram_transport.py`, `lumen_state_storage.py`, and `lumen_typing_pace.py`.
37
+
38
+ See **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)** for a deeper look at routing, streaming, the security layers, and the TikTok downloader.
39
+
40
+ ## Deploying on Hugging Face Spaces
41
+
42
+ 1. Push this repository to a Space (`sdk: docker` is already set in the frontmatter above).
43
+ 2. Set the two required secrets: `BOT_TOKEN` and `GEMINI_API_KEY`.
44
+ 3. Hugging Face builds the image from `Dockerfile` and runs `python -u bot.py`.
45
+ 4. On startup the bot registers its own webhook. If that fails, check the logs for `[webhook] setWebhook failed` and register it manually:
46
+ ```bash
47
+ curl -H "Authorization: Bearer <ADMIN_PANEL_KEY>" https://<space-host>/webhook_url
48
+ ```
49
+ then open the `register_link` it returns.
50
+ 5. `WEBHOOK_SECRET` and `ADMIN_PANEL_KEY` are derived deterministically from `BOT_TOKEN` (or from `ADMIN_SECRET_SEED`, if set). Fetch them with:
51
+ ```bash
52
+ curl -H "Authorization: Bearer <BOT_TOKEN>" https://<space-host>/admin_keys
53
+ ```
54
+
55
+ Hugging Face Spaces' outbound IPs are blocked by Telegram's API at the network level, so a small proxy is required. See [Proxy setup](#proxy-setup) below.
56
+
57
+ ## Configuration
58
+
59
+ Only `BOT_TOKEN` and `GEMINI_API_KEY` are required. Everything else has a sane default; the full reference (proxy addresses, timeouts, storage, rate limiting, TikTok tuning) lives in **[docs/ENVIRONMENT.md](docs/ENVIRONMENT.md)**.
60
+
61
+ ## Proxy setup
62
+
63
+ Hugging Face Spaces' outbound IPs are blocked by Telegram's Bot API entirely, and TikWM (the TikTok API this bot uses) returns `403` to the same IPs. Both are fixed by one small pass-through proxy, deployed separately on Deno Deploy (source: `proxy.ts`):
64
+
65
+ ```bash
66
+ TELEGRAM_API_BASE_URL=https://<proxy-domain>/fetch/api.telegram.org
67
+ TIKWM_API_BASE_URL=https://<proxy-domain>/fetch/www.tikwm.com
68
+ ```
69
+
70
+ The proxy only forwards to an explicit host allowlist (`api.telegram.org`, `www.tikwm.com`, `tikwm.com`). See `proxy.ts` for the implementation and `proxy_test.ts` for its tests.
71
+
72
+ ## Diagnostics
73
+
74
+ All three endpoints below require `Authorization: Bearer <ADMIN_PANEL_KEY>` (`/admin_keys`, covered in the deploy steps above, uses `BOT_TOKEN` instead):
75
+
76
+ | Endpoint | Purpose |
77
+ |---|---|
78
+ | `GET /diag` | Checks outbound network reachability (Telegram, Gemini, OpenRouter, TikWM, Pollinations, etc.) from inside the container. |
79
+ | `GET /webhook_url` | Shows the computed webhook URL and a ready-to-open registration link. |
80
+ | `GET /export_state` | Dumps all chat histories and quota counters as JSON, for manual backup. |
81
+
82
+ `/logs` (a Telegram command, owner-only) sends the current `bot.log` with secrets redacted.
83
+
84
+ ## Commands
85
+
86
+ `/start`, `/reset`, `/draw`, and `/tts` show up in Telegram's command menu:
87
+
88
+ | Command | Access | Purpose |
89
+ |---|---|---|
90
+ | `/start` | anyone | Shows a short intro and the command list. |
91
+ | `/reset` | anyone in DMs; group admins/owner in groups | Clears the chat's conversation history. |
92
+ | `/draw [description]` | anyone | Generates an image (see [Features](#features)). |
93
+ | `/tts [text]` | anyone | Reads text out loud. |
94
+
95
+ Two more owner-only commands stay out of the menu on purpose, since they surface internal details that shouldn't be visible in a group chat:
96
+
97
+ | Command | Access | Purpose |
98
+ |---|---|---|
99
+ | `/stats` | bot owner, DMs only | Active chat count, process uptime, per-model quota usage. |
100
+ | `/logs` | bot owner, DMs only | Sends `bot.log` with secrets redacted. |
101
+
102
+ ## Testing
103
+
104
+ ```bash
105
+ pip install -r requirements.txt -r requirements-dev.txt
106
+ pytest -v
107
+ ```
108
+
109
+ Test files mirror the module split: `test_lumen_formatting.py`, `test_lumen_security.py`, `test_lumen_router_config.py`, and `test_lumen_typing_pace.py` each test their matching module directly, while `test_bot.py` covers everything defined in `bot.py` itself. `conftest.py` stubs `BOT_TOKEN`/`GEMINI_API_KEY`/`BOT_LOG_PATH` so the suite needs no real secrets.
110
+
111
+ CI (`.github/workflows/ci.yml`) runs `pyflakes` + `pytest` + `pip-audit` on every push and pull request; a successful run triggers `sync-to-hf.yml`, which mirrors the commit to the Hugging Face Space.
112
+
113
+ ## Known limitations
114
+
115
+ - Chat history and quota counters survive redeploys only if Upstash is configured (see [docs/ENVIRONMENT.md](docs/ENVIRONMENT.md)); otherwise they live on the container's ephemeral disk and reset on every rebuild.
116
+ - YouTube downloading isn't supported, because Hugging Face Spaces' outbound IPs are blocked at the TLS handshake level. Viewing and analyzing a video by link still works.
117
+ - TikTok downloading depends on the unofficial TikWM API, not an official TikTok endpoint, and needs the proxy above to work from Hugging Face Spaces at all.
118
+ - Streaming has only been exercised against mocked clients, not live Gemini/OpenRouter SSE traffic. See the manual smoke-test checklist in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) before touching that code path.