BikeControl (SwiftControl)
使用 Zwift Click、Zwift Play、Shimano Di2,或任何藍牙控制器搭配 MyWhoosh、Rouvy、Zwift 等。可於 iOS、Android、Windows 與 macOS 免費試用。
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Weekly NFL game predictions blending an Elo-style power rating (built from
real historical results) with Vegas market odds and a weather adjustment.
This is the first vertical slice of a larger planned system (fantasy
projections, player grading, scouting notes, live in-game projections come
later).
• Backend: Python (FastAPI + SQLAlchemy + SQLite), data from
nflreadpy (nflverse),
The Odds API, and
Open-Meteo.
• Frontend: React + TypeScript (Vite).檢視完整 README ↗Weekly NFL game predictions blending an Elo-style power rating (built from real historical results) with Vegas market odds and a weather adjustment.
This is the first vertical slice of a larger planned system (fantasy projections, player grading, scouting notes, live in-game projections come later).
nflreadpy (nflverse),
The Odds API, and
Open-Meteo.Requires Python 3.10+. If your system Python is older, install
uv (curl -LsSf https://astral.sh/uv/install.sh | sh),
which will fetch a pinned Python version automatically.
cd backend
uv sync
cp .env.example .env
# edit .env and add your free API key from https://the-odds-api.com/
Run the API:
uv run uvicorn app.main:app --reload
Run the ingestion + prediction pipeline:
uv run python -m app.cli ingest-all --season 2026 --week 1
uv run python -m app.cli predict-week --season 2026 --week 1
Grade a completed week against actual results:
uv run python -m app.cli grade-week --season 2026 --week 1
Build the offensive/defensive systems & coaching-trees catalog (run once,
re-run after adding a new season to HISTORY_SEASONS in app/cli.py):
uv run python -m app.cli build-scheme-mapping
uv run python -m app.cli ingest-plays
Injury reports are pulled automatically as part of ingest-all (best-effort
-- nflreadpy only has data for seasons that have actually started publishing
practice reports). To backfill a specific past week on its own:
uv run python -m app.cli ingest-injuries --season 2024 --week 10
Each game's prediction card also exposes a "View game plan" panel (injuries,
play-style/scheme matchup, over/under lean, upset alerts) via
GET /api/predictions/game/{game_id}/gameplan, and a Parlays tab
suggests a safest and a best-money-move parlay via
GET /api/parlays/week/{season}/{week}.
Player-level touchdown/yardage projections (rushing, receiving, passing,
anytime-TD probability) live in the same Game Plan panel, backed by
GET /api/predictions/game/{game_id}/players. Build/refresh them with:
uv run python -m app.cli ingest-player-stats --seasons 2021 2022 2023 2024 2025
uv run python -m app.cli project-players --season 2026 --week 1
Team strength (Elo) has always updated automatically from results. Everything
else -- the Elo/market blend weight, the confidence-range widths -- used to
be a fixed constant in config.py that never moved, even though grading
already computed the evidence needed to correct it. app/model/recalibration.py
closes that gap: it grid-searches the blend weight against real Brier scores
and nudges it (capped step, gradual) toward whatever the evidence supports,
and sets the confidence-range widths directly to the observed error std-dev.
Every change is logged (CalibrationAdjustment, GET /api/model/calibration-history,
visible on the dashboard under "self-correction history") with the before/
after numbers -- an auditable trail, not a black box. Gated by a 30-graded-
prediction minimum so a small early streak can't swing it. Elo's own
internals (K-factor, home-field advantage, season regression) are
deliberately NOT auto-tuned -- they're baked into every historical Elo
snapshot, so changing them needs a full build-history rebuild, not a live
nudge.
uv run python -m app.cli recalibrate
Also runs automatically as part of run-routine, after grading, every time
it fires.
Anytime-TD legs are also eligible for the Safest parlay (tagged
anytime_td vs game_winner in the API and UI) -- at most one leg per game
is ever selected, since a team-win leg and that team's own player-TD leg are
correlated outcomes, not independent, and the combined-probability math
assumes independence. Player props are model-probability-only for now (no
market player-prop odds ingested -- see the plan notes for why), so they're
only eligible for Safest, not Best Money Move, which needs a real market
price to compute edge against.
Run tests:
uv run pytest
Requires Node 20+.
cd frontend
npm install
npm run dev
The dashboard expects the backend running at http://localhost:8000
(configurable via frontend/.env → VITE_API_BASE_URL).
A local launchd job runs the ingest → predict → grade → parlay-track
pipeline several times a day, has Claude write a short qualitative read on
the week's most notable games, and self-disables once winner accuracy AND
parlay hit-rate both clear 90% on a real sample (see
backend/app/cli.py:run_routine_cmd for the exact thresholds --
realistically this will just run indefinitely, since ~65-70% is roughly the
ceiling for NFL prediction; that's expected, not a bug).
One-time setup (the auth step has to be done by you -- it's an interactive login tied to your account):
# 1. Install the native CLI (avoids needing sudo for the global npm dir):
npm config set prefix "$HOME/.npm-global"
npm install -g @anthropic-ai/claude-code
export PATH="$HOME/.npm-global/bin:$PATH" # add this line to your ~/.zshrc too
# 2. Authenticate it (interactive -- opens a login flow):
claude setup-token
# 3. Verify:
claude -p "reply with OK" # should print OK, not an auth error
# 4. Load the scheduled job:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.footballpredictor.routine.plist
# Check it's loaded:
launchctl list | grep footballpredictor
Fires at 8:00, 13:00, 18:00, and 23:00 local time (edit the Hour/Minute
values in the plist to change). Each run appends to
backend/routine_log/YYYY-MM-DD.md (the human-readable summary) and
backend/routine_log/launchd-runs.log (raw stdout/stderr, for debugging the
job itself). The routine's own permission scope lives in
.claude/settings.local.json (gitignored) -- it can run the app's own
scripts/tests, edit files in the repo, and self-disable via launchctl bootout, but cannot push to git, commit, or run destructive commands.
Cost-aware by design: run_routine_headless.sh runs pytest and the data
pipeline directly in plain bash on every fire (free, no LLM involved) and
only invokes claude -p when there's something worth its judgment: a test
failure, the first check of the day that has real predictions to analyze
(subsequent same-day fires still refresh data but skip re-analyzing --
backend/routine_log/.analyzed-YYYY-MM-DD is the sentinel), or the stop
condition firing. This isn't optional polish -- the first version called
Claude unconditionally on every fire and burned a full week's usage limit
in two runs during a quiet preseason stretch where there was nothing to do.
If you ever see You've hit your weekly limit in launchd-runs.log, that's
the account-level usage cap talking, not this script; it'll resume once the
limit resets (the message tells you when).
Cadence also adapts to game proximity: the launchd schedule itself stays
static (4 fixed daily fires -- the routine is deliberately not permitted to
touch its own plist, for the same safety reasons it can't git push), but
the 11pm fire is a no-op (skipped before pytest/the pipeline even run) on
any day that isn't a game day or the day before one, per
app/cli.py:is-game-day (app/model/schedule_context.py:is_game_day_or_eve,
checked against whatever schedule data is already in the DB -- no network
call). Net effect: 3x/day (8am/1pm/6pm) on quiet days, 4x/day around actual
games.
To stop it manually at any time:
launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.footballpredictor.routine.plist
Known limitation: nflreadpy has zero preseason game data (verified --
game_type only ever contains REG/WC/DIV/CON/SB, for every season). The
routine can't predict preseason games; it just monitors until Week 1 enters
range each year. Also: the "best money move" parlay leg of the stop
condition needs live market odds (ODDS_API_KEY in backend/.env) --
without one, that half of the 90% target can never be satisfied.
Everything above runs on localhost only. To get a real, public URL on
free-tier hosting:
Architecture: Render (backend, free web service --
sleeps after 15 min idle, ~30-60s to wake on the next request) +
Neon (Postgres, permanent free tier, 0.5GB) +
Vercel (frontend, free static hosting, no sleep) +
GitHub Actions (the cloud routine, genuinely free -- Render's own cron costs
money, so the routine lives here instead, running against the same Neon
database). The existing local launchd routine keeps serving local dev
against local SQLite unchanged; this is a separate, independent production
setup, not a replacement for it.
Setup (each of these is an account/dashboard step only you can do -- I can't create accounts or enter payment/signup details on your behalf):
postgresql:// -- paste it as-is, it's normalized to the
right driver automatically, see app/db.py).backend/render.yaml automatically), and set DATABASE_URL (the Neon
string from step 2), ODDS_API_KEY, and CORS_ALLOWED_ORIGINS in its
dashboard (not committed to git).frontend/, set VITE_API_BASE_URL to the Render URL from
step 3.DATABASE_URL (same Neon value) and
ODDS_API_KEY so .github/workflows/routine.yml can reach them.DATABASE_URL and verify the deployed site end-to-end.Data migration (once you have a real Neon DATABASE_URL, run against
it -- e.g. DATABASE_URL=postgresql://... uv run python -m app.cli ... --
rather than copying the SQLite file; everything is reproducible from real
data sources, so this proves the Postgres path actually works):
uv run python -m app.cli init-db
uv run python -m app.cli build-history
uv run python -m app.cli build-scheme-mapping
uv run python -m app.cli ingest-plays
uv run python -m app.cli ingest-player-stats --seasons 2021 2022 2023 2024 2025
uv run python -m app.cli ingest-all --season 2026 --week 1
uv run python -m app.cli predict-week --season 2026 --week 1
Cloud routine scope boundary: .github/workflows/routine.yml keeps
production data fresh (ingest/predict/grade/recalibrate/parlay-log) on the
same cadence as the local routine (3x/day, 4x on game days -- reuses
is-game-day), but does NOT include the Claude-invoked qualitative
analysis or self-disable steps -- those need the claude CLI and an auth
token, a meaningfully bigger lift to run unattended in Actions (the token
would need to be a repo secret exposed to every run). That stays a
local-Mac-only feature for now.