https://github.com/jrhahn/ai-trainer
AI-powered cycling coach with Strava integration, RAG-based training knowledge, and support for OpenAI & Gemini — built with FastAPI + React.
https://github.com/jrhahn/ai-trainer
ai coaching cycling fastapi gemini llm openai python rag sports sports-analytics
Last synced: 1 day ago
JSON representation
AI-powered cycling coach with Strava integration, RAG-based training knowledge, and support for OpenAI & Gemini — built with FastAPI + React.
- Host: GitHub
- URL: https://github.com/jrhahn/ai-trainer
- Owner: jrhahn
- License: agpl-3.0
- Created: 2026-04-10T15:26:34.000Z (2 months ago)
- Default Branch: develop
- Last Pushed: 2026-06-14T20:50:26.000Z (2 days ago)
- Last Synced: 2026-06-14T21:05:41.634Z (2 days ago)
- Topics: ai, coaching, cycling, fastapi, gemini, llm, openai, python, rag, sports, sports-analytics
- Language: Python
- Homepage: http://trainlikea.pro
- Size: 2.67 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# AI Trainer — Smart Cycling Coach
[](https://codecov.io/gh/jrhahn/ai-trainer)
[](https://codecov.io/gh/jrhahn/ai-trainer)
A smart cycling training app powered by AI (OpenAI or Google Gemini) with Strava integration.
## Repository structure
```
ai-trainer/
├── frontend/ # Vite + React + TypeScript SPA
└── backend/ # Python FastAPI server (Strava OAuth)
```
## Quick start
### Docker Compose
```bash
cp .env.example .env
# fill in the secrets you want to use
docker compose up -d
```
This starts:
- frontend on
- backend on
- traefik reverse proxy on and
- postgres inside the compose network with a persistent named volume (`postgres_data`)
- authelia for SSO/session-based user management (state persisted in `authelia/`)
The backend can boot with placeholder AI and Strava credentials, but those
features will only work after you set real values in `.env`.
Before first deploy, replace the placeholder Authelia user in
`authelia/users_database.yml` with your real admin account.
Authelia is the file-backed user store for production registration and login,
while the app uses its own JWT for API authorization after sign-in. Local Compose keeps
Authelia notifications in `/data/notification.txt` for password reset and future
identity-verification flows.
### Backend (Strava OAuth)
```bash
cd backend
cp .env.example .env # fill in STRAVA_CLIENT_ID + STRAVA_CLIENT_SECRET
uv sync
uv run uvicorn main:app --reload --port 8000
```
See [`backend/README.md`](backend/README.md) for full setup instructions.
### Frontend
```bash
cd frontend
cp .env.example .env.local # set VITE_BACKEND_URL=http://localhost:8000
npm install
npm run dev
```
The app will be available at .
## How it works
```
Strava API ──► FastAPI backend ──► AI coaching response
│
▼
pgvector (PostgreSQL)
cycling science knowledge base
(RAG via text-embedding-3-small)
```
The coaching assistant combines two sources of context before calling the LLM:
1. **Retrieval-Augmented Generation (RAG)** — a cycling science knowledge base
(`backend/knowledge/`) is chunked, embedded with `text-embedding-3-small`, and
stored in PostgreSQL via `pgvector`. At query time the most relevant chunks are
retrieved by cosine similarity and injected into the prompt.
2. **Athlete context** — real activity data pulled from the Strava API (power,
heart rate, elevation, cadence streams) is analysed and summarised alongside
the user's training plan and feedback history.
The LLM (OpenAI GPT-4o or Google Gemini, switchable via `AI_PROVIDER` env var)
receives both sources and returns structured coaching advice. The prompt
engineering layer lives in `backend/services/prompts.py`.
See [`docs/update_rag.md`](docs/update_rag.md) for how to refresh the knowledge base.
## Features
- **AI-powered training plans** — generate and adapt cycling plans via OpenAI or Google Gemini
- **Strava integration** — connect your Strava account to pull in real activity data
- **RAG knowledge base** — responses grounded in cycling science literature via pgvector
- **Local-first** — all user data (profile, plan, feedback) persisted in browser `localStorage` via Zustand
## Building for production
```bash
cd frontend
npm run build # outputs to frontend/dist/
```
## Deployment (Hetzner)
This repository includes Ansible-based deployment for a Debian Hetzner VPS:
- Playbook: `deploy/ansible/deploy.yml`
- Workflow: `.github/workflows/deploy.yml`
The deployment workflow is tied to the `production` environment. If that
environment is configured with required reviewers, deployment waits for manual
maintainer approval. If required reviewers are not available (for example on
free plans), deployment runs automatically after pushes to `develop`.
Traefik is configured as the public reverse proxy with Let's Encrypt TLS:
- `trainlikea.pro` and `train-like-a.pro` (and any subdomain) route to the frontend
- backend API routes (`/api`, `/healthz`) are proxied through the same domains
- `auth.trainlikea.pro` and `auth.train-like-a.pro` route to Authelia
DNS records must point to the server:
- `A/AAAA trainlikea.pro`
- `A/AAAA *.trainlikea.pro`
- `A/AAAA train-like-a.pro`
- `A/AAAA *.train-like-a.pro`
Set `ACME_EMAIL` in `.env` (or deployment vars) to receive certificate notices.