Rebuilding My TG Forward Bot
On this page
Why Switch
Section titled “Why Switch”The forwarding bot I used before was Node Forward Bot. I used it for quite a while, but I kept getting flooded with ads, which got really annoying. Taking another look at it, the project had already been dead for a year. NFD2 wasn’t open source (I think? Couldn’t find a repo), so I didn’t try it, and I’ve no idea whether it has ad-blocking features. So I decided to reinvent the wheel and build my own.
What About Keyword Filtering?
Section titled “What About Keyword Filtering?”My first attempt was stuffing it with a huge list of sensitive words to auto-block on match. Then I got mysterious results like blocking x86_64 (for “64”), Steam platform exclusive (substring matching “Taiwan independence” in Chinese), Python scripts (matching “cheats”), and listening port (matching “surveillance”).
So… Regex?
Section titled “So… Regex?”Ugh… clearly that road went nowhere. So I listened to some group chat friends and tried writing a bunch of regex expressions. But as everyone knows, Chinese spam is incredibly cryptic: 丅子, 微 P 嗯, weird emoji concatenations… Can regex really defend against all this? Maybe, but my brain clearly isn’t that powerful (sweat), so in the end I decided to bring in an LLM for moderation.
Exhausted… LLM, Launch!
Section titled “Exhausted… LLM, Launch!”I needed a model that was as fast as possible, didn’t need to be super smart, but could understand the text. As everyone knows, Google has a model called gemini-3-flash, which felt suitable for content moderation. So I used it, wrote a simple prompt, and had it judge user input — outputting either SAFE or UNSAFE.
const MODERATION_PROMPT = `# RoleContent Moderator API. Output one word only.
# RulesUNSAFE if:- Real human nudity/sex- QR codes/spam/ads/gambling promotion- Real gore/shock content- Illegal content promotion- Scam/phishing attempts
SAFE if:- 2D/Anime/Cartoon (even suggestive)- Normal photos/text/screenshots- Regular conversation
# OutputOne word: "SAFE" or "UNSAFE"
Analyze the content:`;There’s a small amount of latency, but it’s basically negligible. Compared to traditional rule-based matching, an LLM can understand context and semantics, so the false-positive rate is much lower. The downside is probably cost, but Gemini has a free quota — not a generous one though. With three API keys, that’s about 60 calls per day, which is just barely enough for ad blocking.
TypeScript Is Great!
Section titled “TypeScript Is Great!”The whole project uses a modular structure:
.├── src│ ├── ai.ts│ ├── config.ts│ ├── handlers│ │ ├── admin│ │ │ ├── callbacks.ts│ │ │ ├── commands.ts│ │ │ ├── index.ts│ │ │ ├── replies.ts│ │ │ └── shared.ts│ │ └── guest.ts│ ├── i18n│ │ ├── en.ts│ │ └── zh.ts│ ├── i18n.ts│ ├── index.ts│ ├── storage.ts│ ├── telegram.ts│ └── types.ts├── tsconfig.json└── wrangler.tomlImplemented these features:
| Feature | Description |
|---|---|
| LLM Content Moderation | LLM-based harmful content detection |
| Ban List | View all banned users |
| Content Hash Cache | Prevent wasted tokens from repeated spam |
| Blacklist System | Same — multiple blocks trigger an auto-ban |
| Whitelist System | Stop moderation after consecutive clean messages |
| Stats System | Message count, user count, AI block count |
| Multi API Key Rotation | Google’s API quota is way too stingy |
Who is 20 API calls a day enough for? It used to be 100 calls a day. Gemini CLI and Antigravity are all-you-can-eat, but the API is just miserly.
Edit: Now even Gemini CLI and Antigravity aren’t enough anymore.
The whole project runs on Cloudflare Workers (NFD works the same way — convenient, useful, and free), a completely zero-cost solution. The LLM usage is free-tier too.