# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview Audiobookshelf Recommendation System - A FastAPI web application that syncs with Audiobookshelf to track listening history and provide AI-powered book recommendations using Google Gemini. ## Development Commands ### Running the Application ```bash # Start the development server (with auto-reload) python main.py # Or using uvicorn directly ./venv/bin/python main.py ``` The application runs on `http://0.0.0.0:8000` by default (configurable via `.env`). ### Dependency Management ```bash # Install/update dependencies ./venv/bin/pip install -r requirements.txt # Upgrade specific packages ./venv/bin/pip install --upgrade google-generativeai ``` ### Database The application uses SQLite with async support via `aiosqlite`. Database is auto-initialized on startup. ```bash # Database file location ./absrecommend.db # To reset database, simply delete the file rm absrecommend.db ``` ## Architecture ### Application Structure ``` app/ ├── main.py # FastAPI routes and application setup ├── models.py # SQLAlchemy ORM models (Book, ListeningSession, Recommendation) ├── database.py # Database initialization and session management ├── config.py # Pydantic settings (loads from .env) ├── abs_client.py # Audiobookshelf API client ├── recommender.py # AI recommendation engine (Gemini integration) ├── templates/ # Jinja2 HTML templates └── static/ # CSS and JavaScript files ``` ### Key Architectural Patterns **Async-First Design**: The entire application uses async/await with: - `AsyncSession` for database operations - `httpx.AsyncClient` for HTTP requests to Audiobookshelf - FastAPI's async route handlers **Dependency Injection**: FastAPI dependencies are used for: - `get_db()` - Provides database sessions to routes - Configuration loaded via `get_settings()` with caching **Single-User Architecture (Current State)**: - Application uses a single global Audiobookshelf API token from environment - All data is shared (no user isolation) - `AudiobookshelfClient` and `BookRecommender` are initialized once at startup **Data Flow for Sync Operation**: 1. User triggers `/api/sync` endpoint 2. Fetches user's `mediaProgress` from Audiobookshelf `/api/me` endpoint 3. For each book with progress, fetches full item details 4. Creates/updates `Book` records (shared across all data) 5. Creates/updates `ListeningSession` records with timestamps and progress 6. Stores `started_at` and `finished_at` from Audiobookshelf (millisecond timestamps converted to datetime) **AI Recommendation Flow**: 1. Query finished books from database (top 20 by finish date) 2. Format reading history with title, author, genres, finish status 3. Send to Gemini (`models/gemini-2.5-flash`) with structured prompt 4. Parse JSON response into `Recommendation` records 5. Store recommendations in database ### Database Models **Book** - Shared book metadata from Audiobookshelf - Primary key: `id` (Audiobookshelf book ID) - Stores metadata: title, author, narrator, description, genres (JSON), tags (JSON), duration, cover URL - No user association (shared across all users) **ListeningSession** - User progress tracking - Links to Book via `book_id` - Progress tracking: `progress` (0.0-1.0), `current_time` (seconds), `is_finished` - Timestamps: `started_at`, `finished_at`, `last_update` - `rating` field exists but not currently populated **Recommendation** - AI-generated suggestions - Fields: title, author, description, reason (explanation), genres (JSON) - `dismissed` flag to hide recommendations - Currently no user association ### External API Integration **Audiobookshelf API** (`app/abs_client.py`): - Authentication: Bearer token in Authorization header - Key endpoints used: - `GET /api/me` - User info with `mediaProgress` array (all listening history) - `GET /api/items/{id}` - Full book details - `GET /api/libraries` - Available libraries - All timestamps from API are in milliseconds since epoch **Gemini API** (`app/recommender.py`): - Model: `models/gemini-2.5-flash` - SDK: `google.generativeai` (version >=0.8.0) - Generates structured JSON responses for book recommendations - Note: Deprecated `google.generativeai` package - migration to `google.genai` may be needed in future ### Configuration Environment variables loaded via Pydantic settings (`app/config.py`): **Required**: - `ABS_URL` - Audiobookshelf server URL - `ABS_API_TOKEN` - Audiobookshelf API token - `GEMINI_API_KEY` - Google Gemini API key **Optional** (with defaults): - `DATABASE_URL` - SQLite database path (default: `sqlite:///./absrecommend.db`) - `SECRET_KEY` - Application secret key (default provided but should be changed) - `HOST` - Server bind address (default: `0.0.0.0`) - `PORT` - Server port (default: `8000`) ### Important Implementation Details **Timestamp Handling**: Audiobookshelf returns timestamps in milliseconds. The sync operation converts these: ```python datetime.fromtimestamp(timestamp_ms / 1000) ``` **JSON Fields**: `genres` and `tags` are stored as JSON strings in the database and must be serialized/deserialized: ```python genres=json.dumps(metadata.get("genres", [])) # Later: json.loads(book.genres) ``` **Book Filtering**: Sync only processes items where `mediaItemType == "book"` (excludes podcast episodes). **Session Management**: Database uses async context managers. Always use: ```python async with async_session() as session: # operations ``` ## Common Development Tasks ### Adding New API Endpoints 1. Add route handler in `app/main.py` 2. Use `Depends(get_db)` for database access 3. Use async/await throughout 4. Return `JSONResponse` for API endpoints or `HTMLResponse` with templates ### Modifying Database Schema 1. Update models in `app/models.py` 2. Delete existing database file: `rm absrecommend.db` 3. Restart application (database auto-initializes) 4. Note: No migration system currently in place ### Updating AI Prompts Edit `app/recommender.py`: - Modify prompt in `generate_recommendations()` method - Ensure prompt requests JSON format for parsing - Handle JSON parse errors with fallback extraction ### Frontend Changes Templates use Jinja2 with server-side rendering: - HTML: `app/templates/` - CSS: `app/static/css/` - JavaScript: `app/static/js/` - Static files served at `/static/` path ## Git Integration Repository is configured with Gogs at `https://git.mrbamm.xyz/blance/absRecommend` Authentication uses personal access token in remote URL. ## Known Limitations - **Single-user only**: No authentication or multi-user support - **No migration system**: Schema changes require manual database reset - **Manual sync**: No automatic background syncing from Audiobookshelf - **Basic error handling**: API errors may not be gracefully handled in all cases - **Deprecated AI SDK**: Using `google.generativeai` which is deprecated in favor of `google.genai` ## Future Enhancement Plan A comprehensive plan exists at `/home/blance/.claude/plans/golden-snuggling-ullman.md` for adding: - Multi-user authentication (per-user API tokens) - Reading log with statistics (finish dates, listening duration, ratings) - User management (login, registration, settings) - Enhanced UI with separate reading log page When implementing these features, follow the phased approach documented in the plan file.