尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
One dashboard that answers a single question — "is today calm, or not?" — by blending weather, geomagnetic activity, earthquakes/wildfires, news volume, and market volatility into one integral index. Live demo → (neutral placeholder city, no history)
What it does
Every day (GitHub Actions, once a day) it pulls from ten free/keyless APIs, computes one weighted activity index, renders a 4-tab static site, and — if anything crossed a threshold — pings Telegram:檢視完整 README ↗One dashboard that answers a single question — "is today calm, or not?" — by blending weather, geomagnetic activity, earthquakes/wildfires, news volume, and market volatility into one integral index. Live demo → (neutral placeholder city, no history)
Русская версия: README.ru.md
Every day (GitHub Actions, once a day) it pulls from ten free/keyless APIs, computes one weighted activity index, renders a 4-tab static site, and — if anything crossed a threshold — pings Telegram:
Design is inspired by sungeo.net — earth-tone palette, ring gauge, status badges.
A second, independent index tracks hazard risk for a specific coastal point — the same EONET/USGS feeds, geo-filtered by radius (earthquakes within 2500 km and no older than a configurable age cutoff, storms within 1500 km), with its own weighted scoring (compute_sri_lanka_index in composite.py). It started as personal risk-monitoring for a place the author cares about and stayed in as a worked example of the trap of a stale-but-technically-in-window event silently pinning an index for weeks (see the age-cutoff fix, SRI_LANKA_QUAKE_MAX_AGE_DAYS, documented in the code). Always shown in the Telegram notification alongside live sea/air temperature and wind for the coast, regardless of whether a trigger fired — see Automation below.
The scoring/filtering logic isn't tied to Sri Lanka specifically — swapping the coordinates and radii in sources.py repoints it at any coastal location.
pip install -r requirements.txt
export OPENWEATHERMAP_API_KEY=... # openweathermap.org/api, free tier
python build.py "London,GB" # or any other city — no args builds the same placeholder demo published on Pages
Open the generated index.html in a browser.
| Source | What it provides |
|---|---|
| OpenWeatherMap | current weather + forecast |
| NOAA SWPC | Kp/Ap index, solar wind, aurora probability |
| Schumann Resonance Live | Schumann resonance (unofficial source, honestly flagged when stale) |
| NASA EONET | open natural-event feed (storms feed the coastal-hazard index) |
| USGS | significant earthquakes, filtered to a recent window (feeds the coastal-hazard index) |
| Open-Meteo / Open-Meteo Marine | air temperature, wind, sea temperature for the coastal point |
| BBC / Google News / Al Jazeera / RIA Novosti (RSS) | "digital noise" — publication frequency as an indirect indicator |
| Yahoo Finance chart API | S&P 500, VIX, MOEX, USD/RUB, EUR/USD — daily % change |
.github/workflows/daily-check.yml)flowchart TD
subgraph SRC["Data sources (all keyless except OpenWeatherMap)"]
OWM["OpenWeatherMap"]
NOAA["NOAA SWPC<br/>Kp/Ap, solar wind, aurora"]
SCHU["Schumann Resonance Live"]
EONET["NASA EONET<br/>storms/wildfires/ice"]
USGS["USGS<br/>earthquakes"]
OM["Open-Meteo / Marine<br/>coastal air+sea+wind"]
RSS["BBC / Google News /<br/>Al Jazeera / RIA (RSS)"]
YF["Yahoo Finance chart API"]
end
subgraph GHA["GitHub Actions — daily-check.yml (cron, once a day)"]
SRCPY["sources.py<br/>collect()"]
MOON["moon.py<br/>phase, no API"]
COMP["composite.py<br/>integral index +<br/>coastal-hazard index"]
BUILD["build.py"]
RENDER["templates.py + pages.py + charts.py<br/>→ 4 HTML files"]
SUMMARY[("data/latest_summary.json<br/>data/history.jsonl")]
NOTIFY["notify.py<br/>evaluate() trigger conditions"]
SRCPY --> COMP
COMP --> BUILD
MOON --> BUILD
BUILD --> RENDER
BUILD --> SUMMARY
SUMMARY --> NOTIFY
end
PRIVREPO[("Private history repo<br/>(not this repo)")]
TG["Telegram Bot API<br/>sendMessage"]
CHAT(["Your Telegram chat"])
DISCARD["discarded — never committed<br/>(.gitignore *.html)"]
OWM --> SRCPY
NOAA --> SRCPY
SCHU --> SRCPY
EONET --> SRCPY
USGS --> SRCPY
OM --> SRCPY
RSS --> SRCPY
YF --> SRCPY
PRIVREPO -- "history_sync.py pull<br/>(before build)" --> SRCPY
SUMMARY -- "history_sync.py push<br/>(after build)" --> PRIVREPO
RENDER -.-> DISCARD
NOTIFY -- "NOTIFY_MODE=always,<br/>or a trigger fired" --> TG
TG --> CHAT
Trigger conditions notify.py checks in NOTIFY_MODE=condition (any one fires the alert; in the default always mode it sends every run regardless): integral index ≠ "Calm" · market volatility or news-headline volume >1.5× its historical average (only once enough history has accumulated) · coastal-hazard index ≠ "Calm". The coastal-hazard block is always included in the message body, whether or not it was the thing that fired.
This repository is public and holds only code — neither the real city nor the run history is committed here (see .gitignore and the docstrings in build.py/history_sync.py): a public git history growing on a schedule would quietly leak geolocation and usage patterns. So:
data/history.jsonl) is synced with a separate private repo via history_sync.py (pull before build, push after) — never written to this public repo.demo/ folder is the one deliberate exception — see below.)notify.py): by default (NOTIFY_MODE=always, the settled mode) a Telegram notification goes out on every run regardless of trigger — the coastal-hazard block is always visible in it. If NOTIFY_MODE=condition is explicitly set, it only sends when a trigger actually fired: the integral index ≠ "Calm", OR market volatility / news volume is notably (>1.5×) above its historical average (once enough history has accumulated), OR the coastal-hazard index ≠ "Calm" (a ~M5.75+ earthquake within 2500 km in the last few days, or an active storm in the basin).| Secret | Purpose |
|---|---|
OPENWEATHERMAP_API_KEY | weather API key |
WEATHER_CITY | e.g. London,GB — never stored in code |
HISTORY_PUSH_TOKEN | GitHub PAT with write access to the private history repo |
TELEGRAM_MOTION_BOT_TOKEN | Telegram bot token for alerts |
TELEGRAM_MOTION_CHAT_ID | where to send the alert |
NOTIFY_MODE | optional; always (default if unset) or condition — see above |
demo/ folder and GitHub Pagesdemo/ is a one-time, committed build for a neutral placeholder city (London) — the one deliberate exception to "nothing generated gets committed," precisely because it carries no real location or history. .github/workflows/deploy-pages.yml publishes it to GitHub Pages on every push to demo/; it's a separate workflow from daily-check.yml and never touches the real automation. To refresh the demo after a UI change: run python build.py (no args → the default placeholder city), copy the four HTML files into demo/, commit.
sources.py — fetches data from every sourcemoon.py — moon phase, pure calculation, no APIcomposite.py — the integral activity index (normalization + weighted blend) + the separate coastal-hazard indexcharts.py — SVG line/bar/ring chartstemplates.py — shared page shell (nav, CSS)pages.py — each tab's bodybuild.py — entry point: collects data, computes the index, writes history + summary, renders 4 HTML fileshistory_sync.py — pull/push data/history.jsonl to/from the private history reponotify.py — checks the alert condition, sends to Telegram.github/workflows/daily-check.yml — schedule + steps.github/workflows/deploy-pages.yml — publishes demo/ to GitHub PagesSee CONTRIBUTING.md. Issues and PRs welcome.