gglib_core/ports/
model_registrar.rs

1//! Model registrar port definition.
2//!
3//! This port defines the interface for registering downloaded models
4//! in the database. It breaks the circular dependency between download
5//! and core services by allowing the download crate to depend on a trait
6//! rather than concrete `AppCore`.
7
8use async_trait::async_trait;
9use std::path::Path;
10
11use super::RepositoryError;
12use super::download::ResolvedFile;
13use crate::domain::Model;
14use crate::download::Quantization;
15
16/// Information about a completed download for model registration.
17///
18/// This is a pure data transfer object containing all information
19/// needed to register a model after download completes.
20#[derive(Debug, Clone)]
21pub struct CompletedDownload {
22    /// Path to the primary downloaded file (first shard for sharded models).
23    pub primary_path: std::path::PathBuf,
24    /// All downloaded file paths (multiple for sharded models).
25    pub all_paths: Vec<std::path::PathBuf>,
26    /// The resolved quantization.
27    pub quantization: Quantization,
28    /// Repository ID (e.g., "unsloth/Llama-3-GGUF").
29    pub repo_id: String,
30    /// Commit SHA at time of download.
31    pub commit_sha: String,
32    /// Whether this was a sharded download.
33    pub is_sharded: bool,
34    /// Total bytes downloaded.
35    pub total_bytes: u64,
36    /// Ordered list of all file paths for sharded models (None for single-file models).
37    pub file_paths: Option<Vec<std::path::PathBuf>>,
38    /// `HuggingFace` tags for the model.
39    pub hf_tags: Vec<String>,
40    /// File entries with OIDs from `HuggingFace` (for `model_files` table).
41    pub hf_file_entries: Vec<ResolvedFile>,
42}
43
44impl CompletedDownload {
45    /// Get the primary file path for database registration.
46    ///
47    /// For sharded models, this returns the first shard path
48    /// (required by llama-server for loading split models).
49    pub fn db_path(&self) -> &Path {
50        &self.primary_path
51    }
52}
53
54/// Port for registering downloaded models in the database.
55///
56/// This trait is implemented by core services and injected into
57/// the download manager, allowing model registration without
58/// coupling to `AppCore` directly.
59///
60/// # Usage
61///
62/// ```ignore
63/// let registrar: Arc<dyn ModelRegistrarPort> = /* ... */;
64/// let download = CompletedDownload { ... };
65/// let model = registrar.register_model(&download).await?;
66/// ```
67#[async_trait]
68pub trait ModelRegistrarPort: Send + Sync {
69    /// Register a downloaded model in the database.
70    ///
71    /// Parses GGUF metadata from the downloaded file and creates a database entry.
72    /// For sharded models, the primary (first shard) path is used for registration.
73    ///
74    /// # Arguments
75    ///
76    /// * `download` - The completed download information
77    ///
78    /// # Returns
79    ///
80    /// Returns the created `Model` on success.
81    async fn register_model(&self, download: &CompletedDownload) -> Result<Model, RepositoryError>;
82
83    /// Register a model using raw path parameters.
84    ///
85    /// This is a simpler interface for cases where you have the file path
86    /// but not the full download metadata.
87    ///
88    /// # Arguments
89    ///
90    /// * `repo_id` - `HuggingFace` repository ID
91    /// * `commit_sha` - Git commit SHA
92    /// * `file_path` - Path to the GGUF file
93    /// * `quantization` - Quantization type as string
94    ///
95    /// # Returns
96    ///
97    /// Returns the created `Model` on success.
98    async fn register_model_from_path(
99        &self,
100        repo_id: &str,
101        commit_sha: &str,
102        file_path: &Path,
103        quantization: &str,
104    ) -> Result<Model, RepositoryError>;
105}