{"slug": "telegram-filter-bot-and-bluesky-poster", "title": "Telegram filter bot and Bluesky poster", "summary": "A developer created a three-bot system that monitors Telegram OSINT and geopolitics channels, filters messages through keyword and LLM evaluation, and automatically posts approved stories to Bluesky with AI-generated summaries and image analysis.", "body_md": "A three-bot system that monitors Telegram OSINT/geopolitics channels, filters messages through a keyword pre-filter and LLM evaluation, and automatically posts approved stories to Bluesky with AI-generated summaries, image analysis, and automatic story threading.\n\n```\n┌─────────────────────────────────────────────────────────┐\n│                     controlbot.py                       │\n│          Telegram bot that manages the other two        │\n│     /start, /stop, /restart, /startall, /logs, etc.     │\n└──────────────┬──────────────────────┬───────────────────┘\n               │ manages              │ manages\n               ▼                      ▼\n┌──────────────────────────┐  ┌──────────────────────────┐\n│      filterbot.py        │  │      posterbot.py         │\n│                          │  │                           │\n│ Monitors TG channels     │  │ Watches filterbot output  │\n│ Keyword pre-filter       │──│ AI-formats for Bluesky    │\n│ Semantic deduplication   │  │ Vision: logo detection    │\n│ Auto-translation         │  │ Vision: auto-captioning   │\n│ LLM evaluation (Groq)    │  │ Semantic deduplication    │\n│ Urgency tagging          │  │ Story threading           │\n│ Forwards to destination  │  │ Posts to Bluesky          │\n└──────────────────────────┘  └──────────────────────────┘\n```\n\n| File | Description |\n|---|---|\n`controlbot.py` |\nTelegram bot supervisor. Runs as the parent process and manages filterbot and posterbot as child processes. Send commands from your phone to start/stop/restart bots, view logs, and check heartbeat stats. |\n`filterbot.py` |\nThe core intelligence filter. Connects to your Telegram user account via Telethon, monitors source channels, runs a three-tier keyword pre-filter (override → instant-reject → must-match), detects semantic duplicates, auto-translates non-English messages, and evaluates importance via Groq LLM. Approved messages are forwarded to a destination Telegram channel with urgency tags (🔴 FLASH / 🟡 NOTABLE). |\n`posterbot.py` |\nBluesky publisher. Watches the destination channel that filterbot writes to, batches incoming messages, uses Groq to rewrite them as concise Bluesky posts (≤300 chars), runs vision analysis on images (logo detection + auto-captioning), detects story updates and posts them as threaded replies, and publishes to Bluesky. |\n`(TOOL)export_telegram_channels.py` |\nUtility script. Connects to your Telegram account and exports all channels you're subscribed to into a `channels.json` config file. This is the first thing you run when setting up the project. |\n`channels.json` |\nYour personal channel configuration (gitignored). Contains channel IDs, names, credibility tiers, and the destination channel. Generated by the export tool. |\n`channels.example.json` |\nTemplate showing the `channels.json` format. Copy this and fill it in if you prefer manual setup over the export tool. |\n`filters.json` |\nYour keyword filters and LLM prompt (gitignored). Defines what topics the bot looks for, what it rejects, and how the AI evaluates messages. |\n`filters.example.json` |\nTemplate showing the `filters.json` format with placeholder keywords. Copy and customize for your use case. |\n`private.env` |\nEnvironment variables file containing all API keys and tokens. Never commit this to Git. |\n\nYou need credentials from **four** services:\n\n| Service | What you need | Where to get it |\n|---|---|---|\nTelegram API |\n`TELEGRAM_API_ID` and `TELEGRAM_API_HASH` |\n|\n\n**Telegram Bot**`CONTROL_BOT_TOKEN`\n\n[@BotFather](https://t.me/BotFather)on Telegram →`/newbot`\n\n**Telegram User ID**`ADMIN_TELEGRAM_ID`\n\n[@userinfobot](https://t.me/userinfobot)on Telegram**Groq**`GROQ_API_KEY`\n\n[console.groq.com/keys](https://console.groq.com/keys)— free tier available**Bluesky**`BLUESKY_HANDLE`\n\nand `BLUESKY_APP_PASSWORD`\n\n[bsky.app/settings/app-passwords](https://bsky.app/settings/app-passwords)| Software | Download |\n|---|---|\nPython 3.11+ |\n|\n\n```\npip install telethon python-telegram-bot python-dotenv deep-translator groq pydantic langdetect sentence-transformers torch atproto\ngit clone https://github.com/bananaosint/bsky-poster.git\ncd bsky-poster\npip install telethon python-telegram-bot python-dotenv deep-translator groq pydantic langdetect sentence-transformers torch atproto\n```\n\nCreate a file called `private.env`\n\nin the project root with the following contents:\n\n```\n# Telegram\nTELEGRAM_API_ID=your_api_id\nTELEGRAM_API_HASH=your_api_hash\n\n# Bluesky\nBLUESKY_HANDLE=yourhandle.bsky.social\nBLUESKY_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx\n\n# Groq\nGROQ_API_KEY=gsk_xxxxxxxxxxxx\n\n# Control Bot\nCONTROL_BOT_TOKEN=1234567890:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\nADMIN_TELEGRAM_ID=your_numeric_telegram_id\n```\n\nYou have two options:\n\nThe export tool automatically finds all Telegram channels you're subscribed to and generates a `channels.json`\n\nconfig file:\n\n```\npython \"(TOOL)export_telegram_channels.py\"\n```\n\nOn first run, Telethon will ask for your **phone number** and a **login code** sent to Telegram. This creates a local session file so you only need to authenticate once.\n\nThe tool will create `channels.json`\n\nwith all your channels. Then open it and:\n\n**Set**— Change`destination_channel`\n\n`-100000000000`\n\nto the Telegram channel ID where filterbot should forward approved messages. This must be a channel you own or have admin access to.**Remove channels** you don't want monitored.**Set channel tiers**— Rate each source's credibility:`\"high\"`\n\n— Official accounts, verified outlets (IDF, Al Jazeera, etc.)`\"medium\"`\n\nor`\"\"`\n\n— General news aggregators, unverified`\"low\"`\n\n— Propaganda outlets, known bias sources\n\n**Add rapid-update channels**— Channels that post many updates per minute (e.g., air raid alert bots). These get a lower dedup threshold so legitimate rapid-fire updates aren't dropped.\n\nCopy the template and fill it in manually:\n\n```\ncp channels.example.json channels.json\n```\n\nThen edit `channels.json`\n\n— see the format in `channels.example.json`\n\n. You can find channel IDs by forwarding a message from the channel to [@userinfobot](https://t.me/userinfobot).\n\nCopy the example filter config:\n\n```\ncp filters.example.json filters.json\n```\n\nThen edit `filters.json`\n\nto define **what topics your bot monitors**. The file has four sections:\n\nMessages containing any of these words bypass ALL other checks and go straight to the LLM. Use for your most critical, unambiguous signals.\n\nMessages containing any of these are dropped immediately. Use for spam, ads, and off-topic noise.\n\nMessages must contain at least one of these to proceed to the LLM. This is your main topic gate — **add keywords for whatever you're monitoring**.\n\nThe system prompt that tells the LLM what \"important\" means for your use case. Customize this to match your topic.\n\n**Examples for different use cases:**\n\n**Cryptocurrency / DeFi monitoring**\n\n```\n{\n    \"override_keywords\": {\n        \"keywords\": [\"hack\", \"exploit\", \"rug pull\", \"flash loan attack\", \"bridge drained\", \"sec charges\"]\n    },\n    \"instant_reject_keywords\": {\n        \"keywords\": [\"airdrop\", \"giveaway\", \"join our group\", \"buy now\", \"100x gem\", \"not financial advice\"]\n    },\n    \"must_match_keywords\": {\n        \"keywords\": [\"bitcoin\", \"ethereum\", \"defi\", \"hack\", \"exploit\", \"sec\", \"regulation\", \"whale\", \"liquidation\", \"stablecoin\", \"depeg\", \"exchange\", \"binance\", \"coinbase\"]\n    },\n    \"llm_prompt\": {\n        \"system_prompt\": \"You are a crypto intelligence filter. Approve messages about: security exploits, major price movements (>5%), regulatory actions, exchange issues, whale movements. Reject: shilling, price predictions, memes, influencer opinions. Return JSON with 'important' (bool), 'urgency' (1-3), 'reason' (string).\"\n    }\n}\n```\n\n**Sports / Football scores**\n\n```\n{\n    \"override_keywords\": {\n        \"keywords\": [\"goal!\", \"red card\", \"penalty\", \"injury time\", \"transfer confirmed\"]\n    },\n    \"instant_reject_keywords\": {\n        \"keywords\": [\"bet now\", \"odds\", \"prediction\", \"fantasy\", \"subscribe\"]\n    },\n    \"must_match_keywords\": {\n        \"keywords\": [\"goal\", \"score\", \"match\", \"transfer\", \"signed\", \"injury\", \"lineup\", \"suspended\", \"champions league\", \"premier league\", \"red card\", \"var\"]\n    },\n    \"llm_prompt\": {\n        \"system_prompt\": \"You are a football news filter. Approve: live match events (goals, cards, substitutions), confirmed transfers, injuries, official announcements. Reject: rumours, opinions, betting, fantasy football. Return JSON with 'important' (bool), 'urgency' (1-3), 'reason' (string).\"\n    }\n}\n```\n\n**Natural disaster / Weather alerts**\n\n```\n{\n    \"override_keywords\": {\n        \"keywords\": [\"tsunami warning\", \"earthquake\", \"tornado warning\", \"hurricane\", \"evacuation order\"]\n    },\n    \"instant_reject_keywords\": {\n        \"keywords\": [\"donate\", \"pray for\", \"climate change debate\", \"subscribe\"]\n    },\n    \"must_match_keywords\": {\n        \"keywords\": [\"earthquake\", \"tsunami\", \"tornado\", \"hurricane\", \"wildfire\", \"flood\", \"evacuation\", \"magnitude\", \"category\", \"storm surge\", \"landslide\", \"volcanic\"]\n    },\n    \"llm_prompt\": {\n        \"system_prompt\": \"You are a disaster alert filter. Approve: active natural disaster reports, official warnings, evacuation orders, casualty reports, damage assessments. Reject: general weather forecasts, climate opinions, historical events. Return JSON with 'important' (bool), 'urgency' (1-3), 'reason' (string).\"\n    }\n}\npython controlbot.py\n```\n\nThen on Telegram, message your control bot:\n\n```\n/startall\n```\n\nThis starts both filterbot and posterbot. On first run, filterbot will prompt in the terminal for your Telegram phone number and a login code.\n\n| Command | Description |\n|---|---|\n`/status` |\nShow running status of all bots |\n`/start <bot>` |\nStart filterbot or posterbot |\n`/stop <bot>` |\nStop a specific bot |\n`/restart <bot>` |\nRestart a specific bot |\n`/startall` |\nStart all bots at once |\n`/stopall` |\nStop all bots |\n`/restartall` |\nRestart all bots |\n`/logs <bot>` |\nView last 50 log lines |\n`/stats` |\nLatest heartbeat from each bot |\n`/clearstats` |\nReset saved heartbeat stats |\n`/help` |\nList all commands |\n\n```\nIncoming message from source channels\n    │\n    ├── 1. Keyword Pre-Filter (0ms, no API cost)\n    │       ├── Override keywords → PASS immediately (e.g. \"airstrike\", \"breaking:\")\n    │       ├── Instant-reject keywords → DROP (e.g. \"donate\", \"subscribe\")\n    │       └── Must-match keywords → PASS if signal found, DROP if not\n    │\n    ├── 2. Semantic Deduplication\n    │       └── Compares against last 13 messages using sentence embeddings\n    │           Score ≥ 0.65 → duplicate → DROP\n    │\n    ├── 3. Auto-Translation\n    │       └── Non-English messages translated via Google Translate\n    │\n    ├── 4. LLM Evaluation (Groq — Llama 3.1 8B)\n    │       ├── Important → FORWARD with urgency tag\n    │       └── Not important → DROP\n    │\n    └── 5. Forward to destination channel\n            ├── 🔴 FLASH — active kinetic events\n            ├── 🟡 NOTABLE — significant geopolitical developments\n            └── (no tag) — routine newsworthy updates\nMessage arrives in destination channel\n    │\n    ├── 1. Semantic Deduplication (with thread override)\n    │\n    ├── 2. Batch Queue (processes every 60 seconds)\n    │\n    ├── 3. Image Analysis (if media attached)\n    │       ├── Logo detection → drop image if it's a channel logo\n    │       └── Auto-captioning → generate caption if no text\n    │\n    ├── 4. Story Threading Detection\n    │       └── Checks if message is an update to a recently posted story\n    │           Score 0.55–0.64 → format as \"UPDATE:\" and reply to original\n    │\n    ├── 5. AI Formatting (Groq — Llama 3.3 70B)\n    │       ├── Standalone → 25-50 word factual summary\n    │       └── Thread update → short follow-up referencing original\n    │\n    └── 6. Post to Bluesky\n            ├── Text-only, text + image, or text + video\n            └── Thread replies create Bluesky conversation threads\n{\n    \"destination_channel\": -100XXXXXXXXXX,\n    \"channels\": {\n        \"-100XXXXXXXXXX\": \"Channel Name\",\n        \"-100YYYYYYYYYY\": \"Another Channel\"\n    },\n    \"channel_tiers\": {\n        \"-100XXXXXXXXXX\": \"high\",\n        \"-100YYYYYYYYYY\": \"\"\n    },\n    \"rapid_update_channels\": [\n        -100XXXXXXXXXX\n    ]\n}\n```\n\n| Field | Description |\n|---|---|\n`destination_channel` |\nWhere filterbot forwards approved messages. Posterbot also watches this channel. |\n`channels` |\nMap of channel ID → display name. These are the channels filterbot monitors. |\n`channel_tiers` |\nCredibility rating per channel. Affects how strictly the LLM evaluates messages. |\n`rapid_update_channels` |\nChannels that get a lower dedup threshold for rapid-fire updates. |\n\n```\n{\n    \"override_keywords\": {\n        \"_comment\": \"Tier 0: Instant pass — highest confidence signals\",\n        \"keywords\": [\"breaking:\", \"flash:\", \"your critical keyword\"]\n    },\n    \"instant_reject_keywords\": {\n        \"_comment\": \"Tier 1: Instant drop — spam and noise\",\n        \"keywords\": [\"donate\", \"subscribe\", \"your noise keyword\"]\n    },\n    \"must_match_keywords\": {\n        \"_comment\": \"Tier 2: Topic gate — at least one must match\",\n        \"keywords\": [\"your\", \"topic\", \"keywords\", \"here\"]\n    },\n    \"llm_prompt\": {\n        \"_comment\": \"The AI evaluation prompt — customize for your domain\",\n        \"system_prompt\": \"Your system prompt here...\"\n    }\n}\n```\n\n| Field | Description |\n|---|---|\n`override_keywords` |\nMessages with these words pass instantly. Use for unambiguous, high-priority signals. |\n`instant_reject_keywords` |\nMessages with these words are dropped. Use for spam, ads, engagement bait. |\n`must_match_keywords` |\nAt least one must match for the message to reach the LLM. This is your main topic filter. |\n`llm_prompt` |\nThe system prompt sent to the AI. Defines what \"important\" means for your use case. Must instruct the LLM to return JSON with `important` , `urgency` , and `reason` fields. |\n\nNote:All keywords are matched as lowercase substrings. Messages are auto-lowercased before matching, so`\"airstrike\"`\n\nwill match`\"AIRSTRIKE\"`\n\n,`\"Airstrike\"`\n\n, etc.\n\n| Parameter | File | Default | Description |\n|---|---|---|---|\n`SEMANTIC_THRESHOLD` |\nfilterbot / posterbot | `0.65` |\nSimilarity score above which messages are considered duplicates |\n`UPDATE_THRESHOLD` |\nposterbot | `0.55` |\nMin similarity to consider a message a story update (for threading) |\n`BATCH_INTERVAL` |\nposterbot | `60` |\nSeconds between batch processing cycles |\n`QUEUE_MAX_SIZE` |\nposterbot | `10` |\nMax messages queued before oldest is dropped |\n`LOG_BUFFER_SIZE` |\ncontrolbot | `200` |\nRolling log lines kept per bot |\n\nBoth bots emit a heartbeat log every 5 minutes with key metrics:\n\n```\n💓 filterbot | ⏱ 2h15m | 📥 847 received | ⚡ 312 passed pre-filter (37%) | ⏭ 28 deduped | ✅ 89 forwarded | ❌ 195 rejected | 🔴 0 Groq fails\n\n💓 posterbot | ⏱ 2h15m | 📥 89 received | ⏭ 3 deduped | 🚀 82 posted | 🧵 7 threaded | ❌ 1 failed | 🔍 4 logos dropped | 📋 Queue: 0/10\n```\n\nfilterbot also sends a **daily digest** summary to the destination channel every 24 hours.\n\nThis project is private. Do not distribute without permission.", "url": "https://wpnews.pro/news/telegram-filter-bot-and-bluesky-poster", "canonical_source": "https://github.com/bananaosint/bsky-poster", "published_at": "2026-06-14 08:35:04+00:00", "updated_at": "2026-06-14 09:00:54.293917+00:00", "lang": "en", "topics": ["artificial-intelligence", "large-language-models", "ai-tools", "natural-language-processing", "computer-vision"], "entities": ["Telegram", "Bluesky", "Groq", "Telethon", "BotFather"], "alternates": {"html": "https://wpnews.pro/news/telegram-filter-bot-and-bluesky-poster", "markdown": "https://wpnews.pro/news/telegram-filter-bot-and-bluesky-poster.md", "text": "https://wpnews.pro/news/telegram-filter-bot-and-bluesky-poster.txt", "jsonld": "https://wpnews.pro/news/telegram-filter-bot-and-bluesky-poster.jsonld"}}