This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
IMPORTANT: At the start of each conversation, automatically check for open issues and milestones in the Gogs repository:
Check Milestones: Fetch from https://git.mrbamm.xyz/api/v1/repos/blance/absRecommend/milestones?token=bf7d69fd1c0c918719e842c8f8aea97df30aba60
Check Open Issues: Fetch from https://git.mrbamm.xyz/api/v1/repos/blance/absRecommend/issues?state=open&token=bf7d69fd1c0c918719e842c8f8aea97df30aba60
Working Priority:
When Completing Issues:
Audiobookshelf Recommendation System - A FastAPI web application that syncs with Audiobookshelf to track listening history and provide AI-powered book recommendations using Google Gemini.
# 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).
# Install/update dependencies
./venv/bin/pip install -r requirements.txt
# Upgrade specific packages
./venv/bin/pip install --upgrade google-generativeai
The application uses SQLite with async support via aiosqlite. Database is auto-initialized on startup.
# Database file location
./absrecommend.db
# To reset database, simply delete the file
rm absrecommend.db
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
Async-First Design: The entire application uses async/await with:
AsyncSession for database operationshttpx.AsyncClient for HTTP requests to AudiobookshelfDependency Injection: FastAPI dependencies are used for:
get_db() - Provides database sessions to routesget_settings() with cachingSingle-User Architecture (Current State):
AudiobookshelfClient and BookRecommender are initialized once at startupData Flow for Sync Operation:
/api/sync endpointmediaProgress from Audiobookshelf /api/me endpointBook records (shared across all data)ListeningSession records with timestamps and progressstarted_at and finished_at from Audiobookshelf (millisecond timestamps converted to datetime)AI Recommendation Flow:
models/gemini-2.5-flash) with structured promptRecommendation recordsBook - Shared book metadata from Audiobookshelf
id (Audiobookshelf book ID)ListeningSession - User progress tracking
book_idprogress (0.0-1.0), current_time (seconds), is_finishedstarted_at, finished_at, last_updaterating field exists but not currently populatedRecommendation - AI-generated suggestions
dismissed flag to hide recommendationsAudiobookshelf API (app/abs_client.py):
GET /api/me - User info with mediaProgress array (all listening history)GET /api/items/{id} - Full book detailsGET /api/libraries - Available librariesGemini API (app/recommender.py):
models/gemini-2.5-flashgoogle.generativeai (version >=0.8.0)google.generativeai package - migration to google.genai may be needed in futureEnvironment variables loaded via Pydantic settings (app/config.py):
Required:
ABS_URL - Audiobookshelf server URLABS_API_TOKEN - Audiobookshelf API tokenGEMINI_API_KEY - Google Gemini API keyOptional (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)Timestamp Handling: Audiobookshelf returns timestamps in milliseconds. The sync operation converts these:
datetime.fromtimestamp(timestamp_ms / 1000)
JSON Fields: genres and tags are stored as JSON strings in the database and must be serialized/deserialized:
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:
async with async_session() as session:
# operations
app/main.pyDepends(get_db) for database accessJSONResponse for API endpoints or HTMLResponse with templatesapp/models.pyrm absrecommend.dbEdit app/recommender.py:
generate_recommendations() methodTemplates use Jinja2 with server-side rendering:
app/templates/app/static/css/app/static/js//static/ pathRepository is configured with Gogs at https://git.mrbamm.xyz/blance/absRecommend
Authentication uses personal access token in remote URL.
google.generativeai which is deprecated in favor of google.genaiA comprehensive plan exists at /home/blance/.claude/plans/golden-snuggling-ullman.md for adding:
When implementing these features, follow the phased approach documented in the plan file.