Multi-source event radar that discovers events from WeChat posts, links, text, and images, enriches them with vision understanding, deduplicates them, and turns them into a subscribable calendar.
WeChat Fetching · Daily Archives · Vision Understanding · Event Extraction · Dedupe · ICS Calendar · Automation
中文 · Why · Quick Start · Features · Architecture · API · Configuration
EventRadar is a local-first event intelligence tool. It currently focuses on WeChat article fetching, RSS subscriptions, and image archiving, while leaving room for future sources such as Xiaohongshu, web links, group-chat text, and event posters. It adds MiniMax-powered vision understanding, structured event extraction, deduplication, review workflows, automation, and ICS calendar subscriptions for lectures, competitions, registrations, roadshows, open days, summits, hackathons, and more.
This project is built on top of the open-source WeChat Download API project. The original project provides the WeChat login, article fetching, RSS, anti-risk controls, and image proxy foundation; EventRadar extends it into a calendar-centered event intelligence system.
| Pain Point | How EventRadar Helps |
|---|---|
| Event information is scattered across posts, posters, links, and text. | Archive multi-source content and extract structured event records. |
| Image-only posters are hard to search, copy, and organize. | Use MiniMax vision understanding to read event names, times, locations, signup methods, and organizers. |
| Repeated imports can quickly clutter a calendar. | Dedupe at storage, listing, and ICS layers while preserving favorite and confirmed states. |
| Event start, signup open, and deadline times are often mixed together. | Place events by the earliest actionable time whenever possible. |
| Manual calendar maintenance is expensive. | Support scheduled polling, archiving, extraction, cleanup, and ICS subscriptions. |
Under the hood, EventRadar combines:
- FastAPI runtime: static pages, API routes, startup tasks, and health checks.
- WeChat and RSS foundation: login, account search, subscription, polling, article parsing, and image proxying.
- Daily archive pipeline: persist articles and images by date.
- Event extraction pipeline: MiniMax plus fallback rules turn article text and image understanding results into events.
- SQLite event store: dedupe, status, priority, favorite, cleanup, CSV, and ICS.
- Browser calendar UI: review, filtering, editing, manual entry, settings, and automation progress.
| Area | What it does |
|---|---|
| 🔐 WeChat & RSS | QR login, account search, subscriptions, polling, article lists, and full-content fetching. |
| 🗂️ Daily archive | Writes data/daily_archives/YYYY-MM-DD/articles.json and downloads cover/body images. |
| 👁️ Vision understanding | Uses MiniMax Token Plan vision to recover details from image-only WeChat posts. |
| 🧠 Event extraction | Combines article text and vision output, then extracts structured events with LLM and fallback rules. |
| ⏱️ Calendar-first timing | Prioritizes signup open/deadline when they come before the event start. |
| 🧹 Re-import dedupe | Keeps one event record for repeated imports while preserving review state. |
| ⭐ Event store | Manages pending / confirmed / ignored, S/A/B/C priority, favorites, and cleanup rules. |
| 🗓️ Calendar UI | Provides filters, month/week/list views, day modals, editing, favorites, and manual entry. |
| 📤 ICS & CSV export | Serves /api/events/calendar.ics and CSV exports for downstream tools. |
| ⚙️ Automation | Runs scheduled polling, archiving, extraction, dedupe, saving, and progress tracking. |
| 🌐 Public access | Works with cloudflared for a temporary trycloudflare.com URL when needed. |
| Calendar views and event review | Event detail and editing |
|---|---|
![]() |
![]() |
| More calendar interactions | Admin console |
|---|---|
![]() |
![]() |
| Source management | Personal profile | Automation settings |
|---|---|---|
![]() |
![]() |
![]() |
The diagram above shows the main runtime layers and data flow. The detailed module responsibilities live in
app.py,routes/,utils/,static/, anddata/.
The recommended flow is to initialize the local environment, log in to WeChat, set up RSS subscriptions, archive articles, and then run event extraction.
Create env -> Start backend -> WeChat QR login -> Subscribe accounts -> Poll RSS -> Archive articles/images -> Extract events -> Review calendar -> Subscribe ICS
cd /path/to/eventradar
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp env.example .envEdit .env and verify at least these settings:
PORT=5001
HOST=0.0.0.0
DAILY_ARCHIVE_TIMEZONE=Asia/Shanghai
DAILY_ARCHIVE_DOWNLOAD_IMAGES=true
MINIMAX_API_KEY=your MiniMax Token Plan key
MINIMAX_API_STYLE=anthropic
MINIMAX_BASE_URL=https://api.minimax.io/anthropic
MINIMAX_API_HOST=https://api.minimaxi.com
MINIMAX_MODEL=MiniMax-M2.7
MINIMAX_VISION_ENABLED=true
EVENT_AUTOMATION_ENABLED=false
EVENT_AUTOMATION_LOOKBACK_DAYS=0
EVENT_AUTOMATION_USE_LLM=true
EVENT_AUTOMATION_USE_VISION=true
EVENT_RETENTION_DAYS=15Notes:
MINIMAX_MODELis used for text-based structured extraction.- Vision understanding uses the Token Plan
/v1/coding_plan/vlmendpoint and prefersMINIMAX_API_HOST, with automatic fallback betweenapi.minimaxi.comandapi.minimax.io. - Without a MiniMax key, fallback rules still work, but image-only event recognition will be much weaker.
source venv/bin/activate
python app.pyYou should see output like:
EventRadar - FastAPI Service
Admin Page: http://localhost:5001/admin.html
Events Page: http://localhost:5001/events.html
API Docs: http://localhost:5001/api/docs
Common pages:
| Page | Purpose |
|---|---|
http://localhost:5001/admin.html |
Admin panel for login, RSS, and API checks |
http://localhost:5001/login.html |
WeChat QR-code login |
http://localhost:5001/rss.html |
WeChat RSS subscription management |
http://localhost:5001/events.html |
Main EventRadar calendar UI |
http://localhost:5001/api/docs |
Swagger API docs |
Before using event extraction for the first time:
- Open
login.htmland scan the QR code with a WeChat official account administrator. - Open
admin.htmlorrss.html, search for accounts, and subscribe to the ones you want to monitor. - Trigger RSS polling and confirm articles are written into
data/rss.db. - Generate a daily archive and confirm
data/daily_archives/YYYY-MM-DD/articles.jsonplus the image directory exist.
Related API calls:
# Subscribe to an account. fakeid can be found through the search API or UI.
curl -X POST http://localhost:5001/api/rss/subscribe \
-H "Content-Type: application/json" \
-d '{"fakeid":"account fakeid","nickname":"account name"}'
# Poll subscribed accounts
curl -X POST http://localhost:5001/api/rss/poll
# Create today's article archive and download images
curl -X POST "http://localhost:5001/api/rss/archive/daily?poll=false&download_images=true"Open events.html, choose an account and date range, then run extraction. You can also call the API directly:
curl -X POST http://localhost:5001/api/events/extract \
-H "Content-Type: application/json" \
-d '{
"date": "2026-05-21",
"use_llm": true,
"use_vision": true,
"max_chars": 9000
}'You can also run the full pipeline by account and date range:
curl -X POST http://localhost:5001/api/events/run-account-range \
-H "Content-Type: application/json" \
-d '{
"account": "account name",
"start_date": "2026-05-15",
"end_date": "2026-05-21",
"use_llm": true,
"use_vision": true,
"download_images": true
}'Outputs:
- Event store:
data/events.db - Daily JSON:
data/events/YYYY-MM-DD/events.json - CSV:
data/events/YYYY-MM-DD/events.csv - ICS:
data/events/YYYY-MM-DD/calendar.ics - Long-lived ICS:
http://localhost:5001/api/events/calendar.ics
You can enable automation from the settings panel in events.html, or configure .env:
EVENT_AUTOMATION_ENABLED=true
EVENT_AUTOMATION_TIME=09:07
EVENT_AUTOMATION_LOOKBACK_DAYS=0
EVENT_AUTOMATION_USE_LLM=true
EVENT_AUTOMATION_USE_VISION=true
EVENT_RETENTION_DAYS=15Meaning:
- Poll automation-enabled accounts at the configured time every day.
EVENT_AUTOMATION_LOOKBACK_DAYS=0means only today; a conservative free-mode setup should usually keep it at0, with occasional manual backfill.- Each save triggers dedupe so repeated imports keep one record.
- Unfavorited old events are cleaned after the retention window; favorited events are always preserved.
Check progress:
curl http://localhost:5001/api/events/settingsThe response includes automation.progress, and the frontend settings panel also displays the current stage and progress.
For local debugging, you can expose the service with Cloudflare Quick Tunnel:
cloudflared tunnel --url http://127.0.0.1:5001It will return a URL like:
https://example-words.trycloudflare.com
Then visit:
https://example-words.trycloudflare.com/events.htmlhttps://example-words.trycloudflare.com/admin.html
You can also let start.sh launch the tunnel automatically:
CLOUDFLARE_TUNNEL_ENABLED=true
PORT=5001Then run:
bash start.shCloudflare Quick Tunnel URLs are temporary and may change after restart. For production use, prefer a fixed domain and a formal tunnel.
Build and run locally:
cp env.example .env
docker-compose up -d --build
docker-compose logs -fThe default port is controlled by PORT in .env. After the first launch, visit login.html to complete WeChat QR login.
If you use the original upstream image, note that it may not include EventRadar's latest event extraction and calendar features. Building from this repository is recommended.
EventRadar can be packaged as a macOS desktop app with a Tauri shell and a PyInstaller-built FastAPI sidecar.
Download the latest EventRadar_*.dmg from the repository's GitHub Releases page, open it, and drag EventRadar.app into Applications.
On first launch, open the admin panel and configure MiniMax, Webhook, and proxy settings in Model & Runtime Config. The desktop app stores user data outside the project directory:
~/Library/Application Support/EventRadar/
This directory contains the desktop .env, SQLite databases, logs, QR codes, archives, and event exports.
If macOS warns that the app is from an unidentified developer, right-click EventRadar.app, choose Open, and confirm once. Code signing and notarization can be added later for a smoother public release.
Build the backend sidecar only:
bash packaging/desktop/build_pyinstaller.shOutput:
src-tauri/bin/eventradar-server-<target-triple>
Build the .app and .dmg installer:
bash packaging/desktop/build_tauri.shOutput:
src-tauri/target/release/bundle/macos/EventRadar.app
src-tauri/target/release/bundle/dmg/EventRadar_*.dmg
The desktop app starts eventradar-server as a sidecar, waits for /api/health, opens /events.html in a native window, and stops the backend process when the app exits. Runtime data is stored in ~/Library/Application Support/EventRadar/.
Upload this file to GitHub Releases for one-click macOS installation:
src-tauri/target/release/bundle/dmg/EventRadar_1.0.0_aarch64.dmg
The .dmg, .app, PyInstaller output, Rust target directory, and generated sidecar binaries are intentionally ignored by Git. Keep them as Release assets instead of committing them to the repository.
For Intel Macs, build on an Intel macOS machine or configure a matching x86_64-apple-darwin build. The generated sidecar must be named with the matching target triple under src-tauri/bin/.
The older lightweight launcher scripts are still available in packaging/macos for local experiments.
| Group | Entry points |
|---|---|
| 🩺 Health | /api/health |
| 🔐 WeChat foundation | /api/public/searchbiz, /api/article, /api/rss/* |
| 🗓️ Event calendar | /api/events/extract, /api/events/list, /api/events/calendar.ics, /api/events/settings |
curl http://localhost:5001/api/health| Method | Path | Description |
|---|---|---|
GET |
/api/public/searchbiz?query=keyword |
Search WeChat accounts and get fakeid |
POST |
/api/article |
Parse one WeChat article |
POST |
/api/rss/subscribe |
Add an account subscription |
GET |
/api/rss/subscriptions |
List subscriptions |
POST |
/api/rss/poll |
Manually poll account articles |
POST |
/api/rss/archive/daily |
Create daily article archive |
GET |
/api/rss/{fakeid} |
Serve RSS feed |
| Method | Path | Description |
|---|---|---|
POST |
/api/events/extract |
Extract events from daily archives |
POST |
/api/events/run-account |
Subscribe, poll, archive, and extract for one account |
POST |
/api/events/run-account-range |
Run extraction by account and date range |
GET |
/api/events/list |
Query events by date, status, priority, and keyword |
PATCH |
/api/events/{event_id} |
Edit event content, status, and priority |
POST |
/api/events/{event_id}/favorite |
Favorite or unfavorite an event |
GET |
/api/events/calendar.ics |
Long-lived ICS calendar subscription |
GET |
/api/events/export.csv |
Export CSV |
POST |
/api/events/cleanup |
Clean up old unfavorited events |
POST |
/api/events/cleanup-duplicates |
Manually remove duplicates |
GET |
/api/events/settings |
Read automation settings and progress |
POST |
/api/events/settings |
Save automation settings |
When content is imported repeatedly, EventRadar deduplicates at the storage, list, and ICS layers:
- Records from the same source article, event title, or event date can reuse existing events.
- Higher-quality extracted content can update the stored record while preserving status, favorite, and notes.
- Favorite or confirmed state is migrated to the retained event.
- Duplicate cleanup runs automatically after extraction saves.
- Low-quality legacy records with empty time fields can be removed on startup or manual cleanup.
This means repeated daily imports should not produce multiple copies of the same calendar item.
The calendar does not simply use start_time; it sorts by the earliest actionable time:
- If signup start time exists, use it first.
- If there is no signup start but a deadline exists, use the deadline.
- Otherwise, use the event start time.
- Deadline-like
May 10 24:00is kept on May 10 instead of drifting to May 11. - Timezone-aware ISO timestamps are displayed on the correct local date.
Most deployments only need to touch four groups first: service address, WeChat credentials, MiniMax extraction, and automation cadence.
Common settings:
| Key | Description | Default |
|---|---|---|
PORT |
Service port | 5000 |
HOST |
Bind host | 0.0.0.0 |
SITE_URL |
Image proxy and external URL | http://localhost:5000 |
PUBLIC_URL |
Optional fixed public URL | empty |
WECHAT_TOKEN / WECHAT_COOKIE |
WeChat credentials filled after QR login | empty |
RSS_FETCH_FULL_CONTENT |
Whether RSS fetches full content | true |
WECHAT_FETCH_CONCURRENCY |
Full-content fetch concurrency; lower is safer | 1 |
WECHAT_FETCH_DELAY_MIN / WECHAT_FETCH_DELAY_MAX |
Random delay between full-content fetches, in seconds | 8 / 18 |
WECHAT_ACCOUNT_DELAY |
Delay between accounts, in seconds | 20 |
WECHAT_MAX_ARTICLES_PER_ACCOUNT |
Max full articles per account per poll | 10 |
WECHAT_VERIFICATION_PAUSE_MINUTES |
Cooldown minutes after verification is triggered | 60 |
WECHAT_VERIFICATION_STOP_THRESHOLD |
Verification threshold before cooldown | 1 |
WECHAT_PROXY_REQUIRED |
Require proxy pool before fetching full content | false |
DAILY_ARCHIVE_DOWNLOAD_IMAGES |
Download images during daily archive | true |
MINIMAX_API_KEY |
MiniMax Token Plan Key | empty |
MINIMAX_API_STYLE |
Text model API style | anthropic |
MINIMAX_BASE_URL |
Text model base URL | https://api.minimax.io/anthropic |
MINIMAX_API_HOST |
Vision endpoint host | https://api.minimaxi.com |
MINIMAX_MODEL |
Text extraction model | MiniMax-M2.7 |
MINIMAX_VISION_ENABLED |
Enable vision understanding | true |
EVENT_AUTOMATION_ENABLED |
Enable scheduled event automation | false |
EVENT_AUTOMATION_LOOKBACK_DAYS |
Automation lookback days | 0 |
EVENT_RETENTION_DAYS |
Retention days for old unfavorited events | 15 |
PROXY_URLS |
SOCKS5/HTTP proxy pool | empty |
CLOUDFLARE_TUNNEL_ENABLED |
Whether start.sh launches Cloudflare Tunnel |
false |
Anti-risk suggestions:
- When fetching full content, use 2-3 SOCKS5 proxies to reduce WeChat risk checks.
- Example:
PROXY_URLS=socks5://user:pass@ip1:1080,socks5://user:pass@ip2:1080 - The default is a conservative free-mode setup: one scheduled run per day,
0-1lookback days, and up to10full articles per account per poll. - Conservative settings:
WECHAT_FETCH_CONCURRENCY=1,WECHAT_FETCH_DELAY_MIN=8,WECHAT_FETCH_DELAY_MAX=18,WECHAT_ACCOUNT_DELAY=20. - After proxies are stable, concurrency can be raised to
2; staying above3long term is not recommended. - If verification is triggered, the system enters a 60-minute cooldown, shows the remaining cooldown in settings, and stops the current scheduled run.
When full-content fetching is enabled, a proxy pool is strongly recommended to reduce the chance of WeChat risk checks. Direct connections without proxies may lead to frequent verification prompts, account restrictions, or IP blocking. Using 2-3 proxy IPs helps distribute requests and lowers operational risk.
Purpose: distribute article full-content requests across multiple IPs while using Chrome TLS fingerprint simulation. EventRadar uses curl_cffi to mimic Chrome-like TLS fingerprints, so requests look closer to real browser traffic; a proxy pool makes this setup more robust.
Recommended setup: prepare 2-3 low-cost VPS instances and run one SOCKS5 proxy service on each. gost is recommended because it is a single Go binary with no extra runtime dependencies.
# Download the release package. This example uses Linux amd64.
# For other architectures, choose the matching file from GitHub Releases.
wget https://github.com/go-gost/gost/releases/download/v3.2.6/gost_3.2.6_linux_amd64.tar.gz
# If GitHub downloads are slow, use an acceleration mirror when available.
wget https://gh-proxy.com/https://github.com/go-gost/gost/releases/download/v3.2.6/gost_3.2.6_linux_amd64.tar.gz
# or
wget https://ghproxy.cc/https://github.com/go-gost/gost/releases/download/v3.2.6/gost_3.2.6_linux_amd64.tar.gz
# Extract and install
tar -xzf gost_3.2.6_linux_amd64.tar.gz
mv gost /usr/local/bin/
chmod +x /usr/local/bin/gost
# Verify installation
gost -V# With username/password authentication (recommended; replace myuser / mypass / port)
gost -L socks5://myuser:mypass@:1080
# Without authentication (only for private networks or strict firewall rules)
gost -L socks5://:1080cat > /etc/systemd/system/gost.service << 'EOF'
[Unit]
Description=GOST Proxy
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/gost -L socks5://myuser:mypass@:1080
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable gost
systemctl start gost# Allow only your main server IP to connect. Replace with the real IP.
ufw allow from YOUR_MAIN_SERVER_IP to any port 1080If you use a cloud security group, add an inbound rule in the provider console: port 1080 / TCP / source IP restricted to your main server.
PROXY_URLS=socks5://myuser:mypass@vps1-ip:1080,socks5://myuser:mypass@vps2-ip:1080,socks5://myuser:mypass@vps3-ip:1080Restart the service after configuration. Article requests will rotate across proxy IPs. You can verify proxy-pool status with GET /api/health. Leaving PROXY_URLS empty uses direct connections, which is the default behavior.
PYTHONPYCACHEPREFIX=.pycache venv/bin/python -m unittest discover -s tests
PYTHONPYCACHEPREFIX=.pycache venv/bin/python -m compileall -q app.py routes utils tests| Path | Description |
|---|---|
data/rss.db |
Account subscriptions and article cache |
data/events.db |
Event store |
data/daily_archives/YYYY-MM-DD/articles.json |
Daily article archive |
data/daily_archives/YYYY-MM-DD/images/ |
Daily image archive |
data/events/YYYY-MM-DD/events.json |
Daily event export |
data/events/YYYY-MM-DD/calendar.ics |
Daily ICS export |
data/automation/ |
Automation run history |
- This project requires QR-code login with a WeChat official account administrator. Credentials usually expire after about 4 days.
- Chrome TLS fingerprinting, proxy rotation, random delays, account-level spacing, verification detection, and cooldown are built in; for bulk full-content fetching, a proxy pool and low concurrency are still recommended.
- Image-only articles depend on MiniMax Token Plan vision understanding. Without a key, only weak fallback rules are available.
- Quick Tunnel public URLs are temporary and not ideal for production.
- This project is for learning, research, and personal information organization. Please follow the relevant WeChat platform terms.
EventRadar is developed on top of the original open-source WeChat Download API project, which provides the essential WeChat login, article fetching, RSS, image proxy, anti-risk, and FastAPI foundation. This project adds event extraction, vision understanding, an event store, calendar UI, ICS subscription, automation progress, favorite protection, retention cleanup, and repeated-import dedupe.
Thanks to:
- Original author tmwgsicp and the open-source
wechat-download-api - FastAPI
- curl_cffi
- HTTPX
- MiniMax
- Cloudflare Tunnel
This project follows the original project's AGPL-3.0 license. If you modify it and provide it as a network service, please comply with AGPL-3.0 obligations.









