Updated README and did a little bit of cleanup

This commit is contained in:
2025-12-09 04:24:16 +01:00
parent 0c48640412
commit 6940c76e58
11 changed files with 1718 additions and 910 deletions

367
docs/class_diagram.md Normal file
View File

@@ -0,0 +1,367 @@
# Class Diagram - Agent Media
```mermaid
classDiagram
direction TB
%% ===========================================
%% MEMORY SYSTEM
%% ===========================================
class Memory {
+Path storage_dir
+Path ltm_file
+LongTermMemory ltm
+ShortTermMemory stm
+EpisodicMemory episodic
+__init__(storage_dir: str)
+save() void
+get_context_for_prompt() Dict
+get_full_state() Dict
+clear_session() void
}
class LongTermMemory {
+Dict config
+Dict preferences
+Dict~str, List~ library
+List~Dict~ following
+get_config(key: str) Any
+set_config(key: str, value: Any) void
+has_config(key: str) bool
+add_to_library(media_type: str, media: Dict) void
+get_library(media_type: str) List
+follow_show(show: Dict) void
+to_dict() Dict
+from_dict(data: Dict)$ LongTermMemory
}
class ShortTermMemory {
+List~Dict~ conversation_history
+Dict current_workflow
+Dict extracted_entities
+str current_topic
+int max_history
+add_message(role: str, content: str) void
+get_recent_history(n: int) List
+start_workflow(type: str, target: Dict) void
+update_workflow_stage(stage: str) void
+end_workflow() void
+set_entity(key: str, value: Any) void
+get_entity(key: str) Any
+clear() void
+to_dict() Dict
}
class EpisodicMemory {
+Dict last_search_results
+List~Dict~ active_downloads
+List~Dict~ recent_errors
+Dict pending_question
+List~Dict~ background_events
+store_search_results(query: str, results: List) void
+get_result_by_index(index: int) Dict
+get_search_results() Dict
+add_active_download(download: Dict) void
+complete_download(task_id: str, path: str) Dict
+add_error(action: str, error: str) void
+set_pending_question(question: str, options: List) void
+resolve_pending_question(index: int) Dict
+add_background_event(type: str, data: Dict) void
+get_unread_events() List
+clear() void
+to_dict() Dict
}
Memory *-- LongTermMemory : ltm
Memory *-- ShortTermMemory : stm
Memory *-- EpisodicMemory : episodic
%% ===========================================
%% AGENT SYSTEM
%% ===========================================
class Agent {
+LLMClient llm
+Memory memory
+Dict~str, Tool~ tools
+PromptBuilder prompt_builder
+int max_tool_iterations
+__init__(llm: LLMClient, memory: Memory)
+step(user_input: str) str
-_parse_intent(text: str) Dict
-_execute_action(intent: Dict) Dict
-_check_unread_events() str
}
class LLMClient {
<<Protocol>>
+complete(messages: List) str
}
class DeepSeekClient {
+str api_key
+str model
+str base_url
+complete(messages: List) str
}
class OllamaClient {
+str base_url
+str model
+complete(messages: List) str
}
class PromptBuilder {
+Dict~str, Tool~ tools
+__init__(tools: Dict)
+build_system_prompt(memory: Memory) str
-_format_tools_description() str
-_format_episodic_context(memory: Memory) str
-_format_stm_context(memory: Memory) str
}
class Tool {
<<dataclass>>
+str name
+str description
+Callable func
+Dict parameters
}
Agent --> LLMClient : uses
Agent --> Memory : uses
Agent --> PromptBuilder : uses
Agent --> Tool : executes
DeepSeekClient ..|> LLMClient
OllamaClient ..|> LLMClient
PromptBuilder --> Tool : formats
%% ===========================================
%% DOMAIN - MOVIES
%% ===========================================
class Movie {
<<Entity>>
+ImdbId imdb_id
+MovieTitle title
+ReleaseYear release_year
+Quality quality
+FilePath file_path
+FileSize file_size
+int tmdb_id
+datetime added_at
}
class MovieTitle {
<<ValueObject>>
+str value
+__init__(value: str)
}
class ReleaseYear {
<<ValueObject>>
+int value
+__init__(value: int)
}
class Quality {
<<ValueObject>>
+str value
+__init__(value: str)
}
class MovieRepository {
<<Interface>>
+save(movie: Movie) void
+find_by_imdb_id(imdb_id: ImdbId) Movie
+find_all() List~Movie~
+delete(imdb_id: ImdbId) bool
+exists(imdb_id: ImdbId) bool
}
Movie --> MovieTitle
Movie --> ReleaseYear
Movie --> Quality
Movie --> ImdbId
%% ===========================================
%% DOMAIN - TV SHOWS
%% ===========================================
class TVShow {
<<Entity>>
+ImdbId imdb_id
+str title
+int seasons_count
+ShowStatus status
+int tmdb_id
+str first_air_date
+datetime added_at
}
class ShowStatus {
<<Enum>>
CONTINUING
ENDED
UNKNOWN
+from_string(value: str)$ ShowStatus
}
class TVShowRepository {
<<Interface>>
+save(show: TVShow) void
+find_by_imdb_id(imdb_id: ImdbId) TVShow
+find_all() List~TVShow~
+delete(imdb_id: ImdbId) bool
}
TVShow --> ShowStatus
TVShow --> ImdbId
%% ===========================================
%% DOMAIN - SHARED
%% ===========================================
class ImdbId {
<<ValueObject>>
+str value
+__init__(value: str)
+__str__() str
}
class FilePath {
<<ValueObject>>
+str value
+__init__(value: str)
}
class FileSize {
<<ValueObject>>
+int bytes
+__init__(bytes: int)
+to_human_readable() str
}
%% ===========================================
%% INFRASTRUCTURE - PERSISTENCE
%% ===========================================
class JsonMovieRepository {
+Memory memory
+__init__(memory: Memory)
+save(movie: Movie) void
+find_by_imdb_id(imdb_id: ImdbId) Movie
+find_all() List~Movie~
+delete(imdb_id: ImdbId) bool
}
class JsonTVShowRepository {
+Memory memory
+__init__(memory: Memory)
+save(show: TVShow) void
+find_by_imdb_id(imdb_id: ImdbId) TVShow
+find_all() List~TVShow~
+delete(imdb_id: ImdbId) bool
}
JsonMovieRepository ..|> MovieRepository
JsonTVShowRepository ..|> TVShowRepository
JsonMovieRepository --> Memory
JsonTVShowRepository --> Memory
%% ===========================================
%% INFRASTRUCTURE - API CLIENTS
%% ===========================================
class TMDBClient {
+str api_key
+str base_url
+search_movie(title: str) TMDBSearchResult
+search_tv(title: str) TMDBSearchResult
+get_external_ids(tmdb_id: int) Dict
}
class KnabenClient {
+str base_url
+search(query: str, limit: int) List~TorrentResult~
}
class QBittorrentClient {
+str host
+str username
+str password
+add_torrent(magnet: str) bool
+get_torrents() List
}
%% ===========================================
%% INFRASTRUCTURE - FILESYSTEM
%% ===========================================
class FileManager {
+Memory memory
+__init__(memory: Memory)
+set_folder_path(name: str, path: str) Dict
+list_folder(type: str, path: str) Dict
+move_file(source: str, dest: str) Dict
}
FileManager --> Memory
%% ===========================================
%% APPLICATION - USE CASES
%% ===========================================
class SearchMovieUseCase {
+TMDBClient tmdb_client
+execute(title: str) SearchMovieResponse
}
class SearchTorrentsUseCase {
+KnabenClient knaben_client
+execute(title: str, limit: int) SearchTorrentsResponse
}
class AddTorrentUseCase {
+QBittorrentClient qbittorrent_client
+execute(magnet: str) AddTorrentResponse
}
class SetFolderPathUseCase {
+FileManager file_manager
+execute(folder_name: str, path: str) SetFolderPathResponse
}
class ListFolderUseCase {
+FileManager file_manager
+execute(folder_type: str, path: str) ListFolderResponse
}
SearchMovieUseCase --> TMDBClient
SearchTorrentsUseCase --> KnabenClient
AddTorrentUseCase --> QBittorrentClient
SetFolderPathUseCase --> FileManager
ListFolderUseCase --> FileManager
```
## Legend
| Symbol | Meaning |
|--------|---------|
| `<<Entity>>` | Domain entity with identity |
| `<<ValueObject>>` | Immutable value object |
| `<<Interface>>` | Abstract interface/protocol |
| `<<Enum>>` | Enumeration |
| `<<dataclass>>` | Python dataclass |
| `<<Protocol>>` | Python Protocol (structural typing) |
| `*--` | Composition (owns) |
| `-->` | Association (uses) |
| `..\|>` | Implementation |
## Architecture Layers
1. **Domain Layer** - Business entities and rules (Movie, TVShow, ValueObjects)
2. **Application Layer** - Use cases orchestrating business logic
3. **Infrastructure Layer** - External services (APIs, filesystem, persistence)
4. **Agent Layer** - AI agent, LLM clients, tools, prompts