cd /news/artificial-intelligence/telegram-filter-bot-and-bluesky-post… Β· home β€Ί topics β€Ί artificial-intelligence β€Ί article
[ARTICLE Β· art-26856] src=github.com β†— pub= topic=artificial-intelligence verified=true sentiment=Β· neutral

Telegram filter bot and Bluesky poster

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.

read10 min publishedJun 14, 2026

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.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     controlbot.py                       β”‚
β”‚          Telegram bot that manages the other two        β”‚
β”‚     /start, /stop, /restart, /startall, /logs, etc.     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ manages              β”‚ manages
               β–Ό                      β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      filterbot.py        β”‚  β”‚      posterbot.py         β”‚
β”‚                          β”‚  β”‚                           β”‚
β”‚ Monitors TG channels     β”‚  β”‚ Watches filterbot output  β”‚
β”‚ Keyword pre-filter       │──│ AI-formats for Bluesky    β”‚
β”‚ Semantic deduplication   β”‚  β”‚ Vision: logo detection    β”‚
β”‚ Auto-translation         β”‚  β”‚ Vision: auto-captioning   β”‚
β”‚ LLM evaluation (Groq)    β”‚  β”‚ Semantic deduplication    β”‚
β”‚ Urgency tagging          β”‚  β”‚ Story threading           β”‚
β”‚ Forwards to destination  β”‚  β”‚ Posts to Bluesky          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
File Description
controlbot.py
Telegram 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.
filterbot.py
The 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).
posterbot.py
Bluesky 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.
(TOOL)export_telegram_channels.py
Utility 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.
channels.json
Your personal channel configuration (gitignored). Contains channel IDs, names, credibility tiers, and the destination channel. Generated by the export tool.
channels.example.json
Template showing the channels.json format. Copy this and fill it in if you prefer manual setup over the export tool.
filters.json
Your keyword filters and LLM prompt (gitignored). Defines what topics the bot looks for, what it rejects, and how the AI evaluates messages.
filters.example.json
Template showing the filters.json format with placeholder keywords. Copy and customize for your use case.
private.env
Environment variables file containing all API keys and tokens. Never commit this to Git.

You need credentials from four services:

Service What you need Where to get it
Telegram API
TELEGRAM_API_ID and TELEGRAM_API_HASH

Telegram BotCONTROL_BOT_TOKEN

@BotFatheron Telegram β†’/newbot

Telegram User IDADMIN_TELEGRAM_ID

@userinfoboton TelegramGroqGROQ_API_KEY

console.groq.com/keysβ€” free tier availableBlueskyBLUESKY_HANDLE

and BLUESKY_APP_PASSWORD

bsky.app/settings/app-passwords| Software | Download | |---|---| Python 3.11+ | |

pip install telethon python-telegram-bot python-dotenv deep-translator groq pydantic langdetect sentence-transformers torch atproto
git clone https://github.com/bananaosint/bsky-poster.git
cd bsky-poster
pip install telethon python-telegram-bot python-dotenv deep-translator groq pydantic langdetect sentence-transformers torch atproto

Create a file called private.env

in the project root with the following contents:

TELEGRAM_API_ID=your_api_id
TELEGRAM_API_HASH=your_api_hash

BLUESKY_HANDLE=yourhandle.bsky.social
BLUESKY_APP_PASSWORD=xxxx-xxxx-xxxx-xxxx

GROQ_API_KEY=gsk_xxxxxxxxxxxx

CONTROL_BOT_TOKEN=1234567890:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
ADMIN_TELEGRAM_ID=your_numeric_telegram_id

You have two options:

The export tool automatically finds all Telegram channels you're subscribed to and generates a channels.json

config file:

python "(TOOL)export_telegram_channels.py"

On 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.

The tool will create channels.json

with all your channels. Then open it and:

Setβ€” Changedestination_channel

-100000000000

to 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"

β€” Official accounts, verified outlets (IDF, Al Jazeera, etc.)"medium"

or""

β€” General news aggregators, unverified"low"

β€” Propaganda outlets, known bias sources

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.

Copy the template and fill it in manually:

cp channels.example.json channels.json

Then edit channels.json

β€” see the format in channels.example.json

. You can find channel IDs by forwarding a message from the channel to @userinfobot.

Copy the example filter config:

cp filters.example.json filters.json

Then edit filters.json

to define what topics your bot monitors. The file has four sections:

Messages containing any of these words bypass ALL other checks and go straight to the LLM. Use for your most critical, unambiguous signals.

Messages containing any of these are dropped immediately. Use for spam, ads, and off-topic noise.

Messages 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.

The system prompt that tells the LLM what "important" means for your use case. Customize this to match your topic.

Examples for different use cases:

Cryptocurrency / DeFi monitoring

{
    "override_keywords": {
        "keywords": ["hack", "exploit", "rug pull", "flash loan attack", "bridge drained", "sec charges"]
    },
    "instant_reject_keywords": {
        "keywords": ["airdrop", "giveaway", "join our group", "buy now", "100x gem", "not financial advice"]
    },
    "must_match_keywords": {
        "keywords": ["bitcoin", "ethereum", "defi", "hack", "exploit", "sec", "regulation", "whale", "liquidation", "stablecoin", "depeg", "exchange", "binance", "coinbase"]
    },
    "llm_prompt": {
        "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)."
    }
}

Sports / Football scores

{
    "override_keywords": {
        "keywords": ["goal!", "red card", "penalty", "injury time", "transfer confirmed"]
    },
    "instant_reject_keywords": {
        "keywords": ["bet now", "odds", "prediction", "fantasy", "subscribe"]
    },
    "must_match_keywords": {
        "keywords": ["goal", "score", "match", "transfer", "signed", "injury", "lineup", "suspended", "champions league", "premier league", "red card", "var"]
    },
    "llm_prompt": {
        "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)."
    }
}

Natural disaster / Weather alerts

{
    "override_keywords": {
        "keywords": ["tsunami warning", "earthquake", "tornado warning", "hurricane", "evacuation order"]
    },
    "instant_reject_keywords": {
        "keywords": ["donate", "pray for", "climate change debate", "subscribe"]
    },
    "must_match_keywords": {
        "keywords": ["earthquake", "tsunami", "tornado", "hurricane", "wildfire", "flood", "evacuation", "magnitude", "category", "storm surge", "landslide", "volcanic"]
    },
    "llm_prompt": {
        "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)."
    }
}
python controlbot.py

Then on Telegram, message your control bot:

/startall

This starts both filterbot and posterbot. On first run, filterbot will prompt in the terminal for your Telegram phone number and a login code.

Command Description
/status
Show running status of all bots
/start <bot>
Start filterbot or posterbot
/stop <bot>
Stop a specific bot
/restart <bot>
Restart a specific bot
/startall
Start all bots at once
/stopall
Stop all bots
/restartall
Restart all bots
/logs <bot>
View last 50 log lines
/stats
Latest heartbeat from each bot
/clearstats
Reset saved heartbeat stats
/help
List all commands
Incoming message from source channels
    β”‚
    β”œβ”€β”€ 1. Keyword Pre-Filter (0ms, no API cost)
    β”‚       β”œβ”€β”€ Override keywords β†’ PASS immediately (e.g. "airstrike", "breaking:")
    β”‚       β”œβ”€β”€ Instant-reject keywords β†’ DROP (e.g. "donate", "subscribe")
    β”‚       └── Must-match keywords β†’ PASS if signal found, DROP if not
    β”‚
    β”œβ”€β”€ 2. Semantic Deduplication
    β”‚       └── Compares against last 13 messages using sentence embeddings
    β”‚           Score β‰₯ 0.65 β†’ duplicate β†’ DROP
    β”‚
    β”œβ”€β”€ 3. Auto-Translation
    β”‚       └── Non-English messages translated via Google Translate
    β”‚
    β”œβ”€β”€ 4. LLM Evaluation (Groq β€” Llama 3.1 8B)
    β”‚       β”œβ”€β”€ Important β†’ FORWARD with urgency tag
    β”‚       └── Not important β†’ DROP
    β”‚
    └── 5. Forward to destination channel
            β”œβ”€β”€ πŸ”΄ FLASH β€” active kinetic events
            β”œβ”€β”€ 🟑 NOTABLE β€” significant geopolitical developments
            └── (no tag) β€” routine newsworthy updates
Message arrives in destination channel
    β”‚
    β”œβ”€β”€ 1. Semantic Deduplication (with thread override)
    β”‚
    β”œβ”€β”€ 2. Batch Queue (processes every 60 seconds)
    β”‚
    β”œβ”€β”€ 3. Image Analysis (if media attached)
    β”‚       β”œβ”€β”€ Logo detection β†’ drop image if it's a channel logo
    β”‚       └── Auto-captioning β†’ generate caption if no text
    β”‚
    β”œβ”€β”€ 4. Story Threading Detection
    β”‚       └── Checks if message is an update to a recently posted story
    β”‚           Score 0.55–0.64 β†’ format as "UPDATE:" and reply to original
    β”‚
    β”œβ”€β”€ 5. AI Formatting (Groq β€” Llama 3.3 70B)
    β”‚       β”œβ”€β”€ Standalone β†’ 25-50 word factual summary
    β”‚       └── Thread update β†’ short follow-up referencing original
    β”‚
    └── 6. Post to Bluesky
            β”œβ”€β”€ Text-only, text + image, or text + video
            └── Thread replies create Bluesky conversation threads
{
    "destination_channel": -100XXXXXXXXXX,
    "channels": {
        "-100XXXXXXXXXX": "Channel Name",
        "-100YYYYYYYYYY": "Another Channel"
    },
    "channel_tiers": {
        "-100XXXXXXXXXX": "high",
        "-100YYYYYYYYYY": ""
    },
    "rapid_update_channels": [
        -100XXXXXXXXXX
    ]
}
Field Description
destination_channel
Where filterbot forwards approved messages. Posterbot also watches this channel.
channels
Map of channel ID β†’ display name. These are the channels filterbot monitors.
channel_tiers
Credibility rating per channel. Affects how strictly the LLM evaluates messages.
rapid_update_channels
Channels that get a lower dedup threshold for rapid-fire updates.
{
    "override_keywords": {
        "_comment": "Tier 0: Instant pass β€” highest confidence signals",
        "keywords": ["breaking:", "flash:", "your critical keyword"]
    },
    "instant_reject_keywords": {
        "_comment": "Tier 1: Instant drop β€” spam and noise",
        "keywords": ["donate", "subscribe", "your noise keyword"]
    },
    "must_match_keywords": {
        "_comment": "Tier 2: Topic gate β€” at least one must match",
        "keywords": ["your", "topic", "keywords", "here"]
    },
    "llm_prompt": {
        "_comment": "The AI evaluation prompt β€” customize for your domain",
        "system_prompt": "Your system prompt here..."
    }
}
Field Description
override_keywords
Messages with these words pass instantly. Use for unambiguous, high-priority signals.
instant_reject_keywords
Messages with these words are dropped. Use for spam, ads, engagement bait.
must_match_keywords
At least one must match for the message to reach the LLM. This is your main topic filter.
llm_prompt
The 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.

Note:All keywords are matched as lowercase substrings. Messages are auto-lowercased before matching, so"airstrike"

will match"AIRSTRIKE"

,"Airstrike"

, etc.

Parameter File Default Description
SEMANTIC_THRESHOLD
filterbot / posterbot 0.65
Similarity score above which messages are considered duplicates
UPDATE_THRESHOLD
posterbot 0.55
Min similarity to consider a message a story update (for threading)
BATCH_INTERVAL
posterbot 60
Seconds between batch processing cycles
QUEUE_MAX_SIZE
posterbot 10
Max messages queued before oldest is dropped
LOG_BUFFER_SIZE
controlbot 200
Rolling log lines kept per bot

Both bots emit a heartbeat log every 5 minutes with key metrics:

πŸ’“ filterbot | ⏱ 2h15m | πŸ“₯ 847 received | ⚑ 312 passed pre-filter (37%) | ⏭ 28 deduped | βœ… 89 forwarded | ❌ 195 rejected | πŸ”΄ 0 Groq fails

πŸ’“ posterbot | ⏱ 2h15m | πŸ“₯ 89 received | ⏭ 3 deduped | πŸš€ 82 posted | 🧡 7 threaded | ❌ 1 failed | πŸ” 4 logos dropped | πŸ“‹ Queue: 0/10

filterbot also sends a daily digest summary to the destination channel every 24 hours.

This project is private. Do not distribute without permission.

── more in #artificial-intelligence 4 stories Β· sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/telegram-filter-bot-…] indexed:0 read:10min 2026-06-14 Β· β€”