Generate AI-powered notes from YouTube videos with automatic transcription, summarization, and organization.
- FastAPI backend
- PostgreSQL database
- Redis for caching and rate-limiting
- Uvicorn for running the app in Docker
- Docker & Docker Compose
- Python 3.13 (for local dev virtualenv tasks)
- Copy environment example and customize values:
cp .env.example .env
# Edit .env to set secrets and credentials- Start services:
docker-compose up -d --build- Run database migrations (inside the web container):
docker-compose exec web uv run alembic upgrade head- Open the app at
http://localhost:8000.
- Create and activate a virtual environment:
python -m venv .venv
source .venv/bin/activate- Install dependencies (using
uv):
uv sync-
Set
DATABASE_URLin.envto a local Postgres or use Docker DB above. -
Run locally:
uv run uvicorn main:app --reload --host 0.0.0.0 --port 8000DATABASE_URL- e.g.postgresql://user:pass@db:5432/dbname(used by the app)POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_DB- used by the Postgres container to initialise the DBREDIS_URL- Redis connection stringGOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET- Google OAuthOPENAI_API_KEY- OpenAI API keyJWT_SECRET,SECRET- application secretsPADDLE_API_KEY,PADDLE_WEBHOOK_SECRET- Paddle payment keys
Add more variables in .env as necessary (see .env file for full list).
In Google Cloud Console, add the exact Google Sheets callback URI to the OAuth
client's Authorized redirect URIs. For a local server this is
http://localhost:8000/auth/google_sheets/callback; for production it is
https://<your-domain>/auth/google_sheets/callback. The scheme, domain, path,
and port must match exactly.
Enable both Google Sheets API and Google Drive API for the same Google Cloud project. Formdata uses the Drive API only to locate an already-created Formdata spreadsheet before retrying, preventing duplicate sheets.
- Follow container logs:
docker-compose logs -f web- The app also writes to
logs/app.login the project root. To tail it:
tail -f logs/app.log- List tables using
psqlinside the DB container:
docker-compose exec db psql -U $POSTGRES_USER -d $POSTGRES_DB -c "\dt"-
Couldn't connect to localhost:8000:- Ensure
docker-compose psshowswebrunning and ports mapped (0.0.0.0:8000->8000/tcp). - Inspect logs:
docker-compose logs -f webandtail -f logs/app.log.
- Ensure
-
DATABASE_URLmissing in settings:- Ensure
DATABASE_URLexists in.env. The app reads the env file using Pydantic settings.
- Ensure
-
Port conflicts (6379 or 5432):
- Stop local services using those ports or change ports in
docker-compose.yml.
- Stop local services using those ports or change ports in
# Start services in background
docker-compose up -d
# Stop and remove containers
docker-compose down
# Remove volumes (clears DB) and restart
docker-compose down -v
docker-compose up -d
# Run migrations inside container
docker-compose exec web uv run alembic upgrade head
# Run tests
pytest- This repository runs the app with Uvicorn inside Docker for simplicity. For production use, consider adding a reverse proxy and process manager.
If you'd like, I can commit this README update and also add a Makefile with shortcuts for the commands above.
my_project/ ├── app/ │ ├── api/ # Presentation Layer: FastAPI routers │ ├── core/ # Config, security, global dependencies │ ├── database/ # DB engine, session setup, migrations │ ├── domain/ # Business Layer: Services, domain exceptions │ ├── repositories/ # Data Access Layer: CRUD & queries │ ├── models/ # SQLAlchemy schemas (DB representation) │ ├── schemas/ # Pydantic schemas (Data validation) │ └── templates/ # HTML fragments/layouts (HTMX) ├── tests/ # Pytest suites (unit, integration, e2e) └── main.py # Application entry point
my_project/ ├── app/ │ ├── api/ # 1. Presentation Layer (Routers) │ ├── core/ # 2. Cross-cutting concerns (Exceptions, Config) │ ├── database/ # 3. DB session management │ ├── domain/ # 4. Business Logic (Services) │ ├── models/ # 5. Database Tables (SQLAlchemy) │ ├── repositories/ # 6. Data Access Layer (SQL Queries) │ └── schemas/ # 7. Data Validation (Pydantic) ├── templates/ # HTML templates (HTMX partials) └── main.py # App entry point