2025-12-24 07:50:09 +01:00
2025-12-27 20:07:48 +01:00
2025-12-24 07:50:09 +01:00
2025-12-27 02:30:14 +01:00
2025-12-27 20:07:48 +01:00
2026-01-01 03:08:22 +01:00
2025-12-24 07:50:09 +01:00

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:

  1. Add as OpenAI-compatible endpoint: http://localhost:8000/v1
  2. Model name: agent-media
  3. 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_HOST in .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 install to ensure dependencies are up to date
  • Check logs for specific error messages

Contributing

Contributions are welcome!

Development Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/my-feature
  3. Make your changes
  4. Run tests: poetry run pytest
  5. Run linting: poetry run ruff check . && poetry run black .
  6. Commit: git commit -m "Add my feature"
  7. Push: git push origin feature/my-feature
  8. Create a Pull Request

Documentation

License

MIT License - see LICENSE file for details.

Acknowledgments

Support


Made with ❤️ by Francwa

Description
Alfred media organizer
Readme 1.4 MiB
Languages
Python 98.1%
Makefile 1.1%
Dockerfile 0.8%