3d5de06b44
AI-powered web app that recommends unwatched movies from a Jellyfin library based on natural language mood input. Jellyfin auth, modular LLM backend (Claude/OpenAI/Ollama), two-tier pre-filter + AI ranking, mobile-responsive dark theme UI with poster cards and deep links. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
96 lines
4.3 KiB
Markdown
96 lines
4.3 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
"Movie Night" — an AI-powered media discovery web app for a household with ~53TB of movies on a self-hosted Jellyfin media server. Users describe their mood ("pizza night with the kids", "light fun movie after a hard week") and get AI-ranked recommendations from their unwatched library, with posters and one-click deep links to Jellyfin.
|
|
|
|
**Users:** Kenny and his wife — the primary use case is "what should we watch tonight?"
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Frontend (Tailwind + vanilla JS) → FastAPI backend → LLM (Claude/OpenAI/Ollama)
|
|
↓
|
|
Jellyfin API → SQLite cache
|
|
```
|
|
|
|
- **Backend:** Python 3.12 + FastAPI (app/)
|
|
- **Frontend:** Single-page HTML/CSS/JS with Tailwind CDN (app/static/)
|
|
- **LLM:** Modular provider — Anthropic Claude, OpenAI, or Ollama (app/services/llm/)
|
|
- **Auth:** Jellyfin credentials (like Jellyseerr) — no separate user database
|
|
- **Data:** SQLite cache of movie metadata synced from Jellyfin, persisted at /data/library.db
|
|
- **Deployment:** Docker Compose on bondelie-media (192.168.5.254), port 5210
|
|
|
|
## Key Files
|
|
|
|
- `app/main.py` — FastAPI app entry, lifespan (DB init + background sync), poster proxy, static mount
|
|
- `app/config.py` — Settings via pydantic-settings (env vars)
|
|
- `app/database.py` — SQLite schema and query helpers
|
|
- `app/routers/auth.py` — Jellyfin-based login/logout/session management
|
|
- `app/routers/mood.py` — POST /api/mood — the core recommendation flow
|
|
- `app/services/jellyfin.py` — Jellyfin API client (auth, library fetch, watch state, posters)
|
|
- `app/services/prefilter.py` — Tier-1 keyword/genre scoring to narrow candidates before LLM
|
|
- `app/services/llm/` — Modular LLM providers (anthropic, openai, ollama)
|
|
- `app/services/library_sync.py` — Background sync of movie metadata + watch state
|
|
- `app/static/index.html` — Frontend: login, mood input, result cards
|
|
- `app/static/app.js` — Frontend logic
|
|
|
|
## Related Infrastructure
|
|
|
|
Integrates with the media server documented in `../media-server-migration/`:
|
|
|
|
| Service | Port | Purpose |
|
|
|-------------|-------|--------------------------------------------|
|
|
| Jellyfin | 8096 | Library metadata, watch state, posters |
|
|
| Movie Night | 5210 | This app |
|
|
|
|
**Server:** bondelie-media (192.168.5.254) — Ubuntu 24.04 LTS
|
|
**Proxy:** `movienight.internal.bondelie.net`
|
|
|
|
## Recommendation Flow
|
|
|
|
1. User types mood text
|
|
2. Backend fetches unwatched movies from SQLite cache (filtered by selected users' watch state)
|
|
3. `prefilter.py` scores movies by genre/keyword match, returns top 200 candidates
|
|
4. LLM provider ranks candidates and returns top 6 with reasoning (structured JSON)
|
|
5. Backend validates jellyfin_ids, enriches with poster URLs and deep links
|
|
6. Frontend renders movie cards with posters, metadata, reasoning, and "Watch" button
|
|
|
|
## Secrets
|
|
|
|
Store in `.env` (gitignored), never commit:
|
|
- `JELLYFIN_API_KEY` — Jellyfin API key (Settings → API Keys)
|
|
- `LLM_API_KEY` — Anthropic/OpenAI API key (not needed for Ollama)
|
|
- `SESSION_SECRET` — Random string for cookie signing
|
|
|
|
## Development Commands
|
|
|
|
```bash
|
|
# Local development (requires Python 3.12+)
|
|
pip install -r requirements.txt
|
|
cp .env.example .env # then fill in API keys
|
|
uvicorn app.main:app --reload --port 5210
|
|
|
|
# Docker build and run
|
|
docker compose up --build
|
|
|
|
# Deploy to bondelie-media
|
|
scp -r . kenny@192.168.5.254:/srv/stacks/movie-night/
|
|
ssh kenny@192.168.5.254 "cd /srv/stacks/movie-night && docker compose up --build -d"
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
| Variable | Required | Default | Description |
|
|
|----------|----------|---------|-------------|
|
|
| JELLYFIN_URL | Yes | http://192.168.5.254:8096 | Jellyfin server URL |
|
|
| JELLYFIN_API_KEY | Yes | — | Jellyfin API key |
|
|
| JELLYFIN_EXTERNAL_URL | Yes | https://jellyfin.internal.bondelie.net | URL for deep links |
|
|
| LLM_PROVIDER | No | anthropic | anthropic, openai, or ollama |
|
|
| LLM_API_KEY | Yes* | — | API key (*not needed for ollama) |
|
|
| LLM_MODEL | No | varies by provider | Model name override |
|
|
| LLM_BASE_URL | No | — | Base URL override (for ollama) |
|
|
| SESSION_SECRET | Yes | — | Random string for sessions |
|