253903a1e579e4161afe3e8bba8139fb0529b2bc
Agent Media 🎬
An AI-powered agent for managing your local media library with natural language. Search, download, and organize movies and TV shows effortlessly.
Features
- 🤖 Natural Language Interface: Talk to your media library in plain language
- 🔍 Smart Search: Find movies and TV shows via TMDB
- 📥 Torrent Integration: Search and download via qBittorrent
- 🧠 Contextual Memory: Remembers your preferences and conversation history
- 📁 Auto-Organization: Keeps your media library tidy
- 🌐 API Compatible: OpenAI-compatible API for easy integration
Architecture
Built with Domain-Driven Design (DDD) principles:
agent_media/
├── agent/ # AI agent orchestration
├── application/ # Use cases & DTOs
├── domain/ # Business logic & entities
└── infrastructure/ # External services & persistence
See architecture_diagram.md for architectural details.
Quick Start
Prerequisites
- Python 3.12+
- Poetry
- qBittorrent (optional, for downloads)
- API Keys:
- DeepSeek API key (or Ollama for local LLM)
- TMDB API key
Installation
# Clone the repository
git clone https://github.com/your-username/agent-media.git
cd agent-media
# Install dependencies
poetry install
# Copy environment template
cp .env.example .env
# Edit .env with your API keys
nano .env
Configuration
Edit .env:
# LLM Provider (deepseek or ollama)
LLM_PROVIDER=deepseek
DEEPSEEK_API_KEY=your-api-key-here
# TMDB (for movie/TV show metadata)
TMDB_API_KEY=your-tmdb-key-here
# qBittorrent (optional)
QBITTORRENT_HOST=http://localhost:8080
QBITTORRENT_USERNAME=admin
QBITTORRENT_PASSWORD=adminadmin
Run
# Start the API server
poetry run uvicorn app:app --reload
# Or with Docker
docker-compose up
The API will be available at http://localhost:8000
Usage
Via API
# Health check
curl http://localhost:8000/health
# Chat with the agent
curl -X POST http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "agent-media",
"messages": [
{"role": "user", "content": "Find Inception 1080p"}
]
}'
Via OpenWebUI
Agent Media is compatible with OpenWebUI:
- Add as OpenAI-compatible endpoint:
http://localhost:8000/v1 - Model name:
agent-media - Start chatting!
Example Conversations
You: Find Inception in 1080p
Agent: I found 3 torrents for Inception:
1. Inception.2010.1080p.BluRay.x264 (150 seeders)
2. Inception.2010.1080p.WEB-DL.x265 (80 seeders)
3. Inception.2010.720p.BluRay (45 seeders)
You: Download the first one
Agent: Added to qBittorrent! Download started.
You: List my downloads
Agent: You have 1 active download:
- Inception.2010.1080p.BluRay.x264 (45% complete)
Available Tools
The agent has access to these tools:
| Tool | Description |
|---|---|
find_media_imdb_id |
Search for movies/TV shows on TMDB |
find_torrents |
Search for torrents |
get_torrent_by_index |
Get torrent details by index |
add_torrent_by_index |
Download torrent by index |
add_torrent_to_qbittorrent |
Add torrent via magnet link |
set_path_for_folder |
Configure folder paths |
list_folder |
List folder contents |
Memory System
Agent Media uses a three-tier memory system:
Long-Term Memory (LTM)
- Persistent (saved to JSON)
- Configuration, preferences, media library
- Survives restarts
Short-Term Memory (STM)
- Session-based (RAM only)
- Conversation history, current workflow
- Cleared on restart
Episodic Memory
- Transient (RAM only)
- Search results, active downloads, recent errors
- Cleared frequently
Development
Project Structure
agent_media/
├── agent/
│ ├── agent.py # Main agent orchestrator
│ ├── prompts.py # System prompt builder
│ ├── registry.py # Tool registration
│ ├── tools/ # Tool implementations
│ └── llm/ # LLM clients (DeepSeek, Ollama)
├── application/
│ ├── movies/ # Movie use cases
│ ├── torrents/ # Torrent use cases
│ └── filesystem/ # Filesystem use cases
├── domain/
│ ├── movies/ # Movie entities & value objects
│ ├── tv_shows/ # TV show entities
│ ├── subtitles/ # Subtitle entities
│ └── shared/ # Shared value objects
├── infrastructure/
│ ├── api/ # External API clients
│ │ ├── tmdb/ # TMDB client
│ │ ├── knaben/ # Torrent search
│ │ └── qbittorrent/ # qBittorrent client
│ ├── filesystem/ # File operations
│ └── persistence/ # Memory & repositories
├── tests/ # Test suite (~500 tests)
└── docs/ # Documentation
Running Tests
# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov
# Run specific test file
poetry run pytest tests/test_agent.py
# Run specific test
poetry run pytest tests/test_agent.py::TestAgent::test_step
Code Quality
# Linting
poetry run ruff check .
# Formatting
poetry run black .
# Type checking (if mypy is installed)
poetry run mypy .
Adding a New Tool
Quick example:
# 1. Create the tool function in agent/tools/api.py
def my_new_tool(param: str) -> Dict[str, Any]:
"""Tool description."""
memory = get_memory()
# Implementation
return {"status": "ok", "data": "result"}
# 2. Register in agent/registry.py
Tool(
name="my_new_tool",
description="What this tool does",
func=api_tools.my_new_tool,
parameters={
"type": "object",
"properties": {
"param": {"type": "string", "description": "Parameter description"},
},
"required": ["param"],
},
),
Docker
Build
docker build -t agent-media .
Run
docker run -p 8000:8000 \
-e DEEPSEEK_API_KEY=your-key \
-e TMDB_API_KEY=your-key \
-v $(pwd)/memory_data:/app/memory_data \
agent-media
Docker Compose
# Start all services (agent + qBittorrent)
docker-compose up -d
# View logs
docker-compose logs -f
# Stop
docker-compose down
API Documentation
Endpoints
GET /health
Health check endpoint.
Response:
{
"status": "healthy",
"version": "0.2.0"
}
GET /v1/models
List available models (OpenAI-compatible).
POST /v1/chat/completions
Chat with the agent (OpenAI-compatible).
Request:
{
"model": "agent-media",
"messages": [
{"role": "user", "content": "Find Inception"}
],
"stream": false
}
Response:
{
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1234567890,
"model": "agent-media",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "I found Inception (2010)..."
},
"finish_reason": "stop"
}]
}
GET /memory/state
View full memory state (debug).
POST /memory/clear-session
Clear session memories (STM + Episodic).
Troubleshooting
Agent doesn't respond
- Check API keys in
.env - Verify LLM provider is running (Ollama) or accessible (DeepSeek)
- Check logs:
docker-compose logs agent-media
qBittorrent connection failed
- Verify qBittorrent is running
- Check
QBITTORRENT_HOSTin.env - Ensure Web UI is enabled in qBittorrent settings
Memory not persisting
- Check
memory_data/directory exists and is writable - Verify volume mounts in Docker
Tests failing
- Run
poetry installto ensure dependencies are up to date - Check logs for specific error messages
Contributing
Contributions are welcome!
Development Workflow
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run tests:
poetry run pytest - Run linting:
poetry run ruff check . && poetry run black . - Commit:
git commit -m "Add my feature" - Push:
git push origin feature/my-feature - Create a Pull Request
Documentation
- Architecture Diagram - System architecture overview
- Class Diagram - Class structure and relationships
- Component Diagram - Component interactions
- Sequence Diagram - Sequence flows
- Flowchart - System flowcharts
License
MIT License - see LICENSE file for details.
Acknowledgments
- DeepSeek - LLM provider
- TMDB - Movie database
- qBittorrent - Torrent client
- FastAPI - Web framework
Support
- 📧 Email: francois.hodiaumont@gmail.com
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
Made with ❤️ by Francwa
Description
Languages
Python
98.1%
Makefile
1.1%
Dockerfile
0.8%