pub struct ModelService {
repo: Arc<dyn ModelRepository>,
}Expand description
Service for model operations.
This service provides high-level model management by delegating
to the injected ModelRepository. It adds no business logic
beyond what the repository provides - it’s a thin facade.
Fields§
§repo: Arc<dyn ModelRepository>Implementations§
Source§impl ModelService
impl ModelService
Sourcepub fn new(repo: Arc<dyn ModelRepository>) -> Self
pub fn new(repo: Arc<dyn ModelRepository>) -> Self
Create a new model service with the given repository.
Sourcepub async fn get(&self, identifier: &str) -> Result<Option<Model>, CoreError>
pub async fn get(&self, identifier: &str) -> Result<Option<Model>, CoreError>
Get a model by its identifier (numeric database id, then exact name).
Thin wrapper over ModelRepository::get_by_identifier, which owns the
lookup-key policy so this service and the ModelCatalogPort adapter
cannot disagree about what a given string resolves to.
Sourcepub async fn get_by_id(&self, id: i64) -> Result<Option<Model>, CoreError>
pub async fn get_by_id(&self, id: i64) -> Result<Option<Model>, CoreError>
Get a model by its database ID.
Sourcepub async fn get_by_name(&self, name: &str) -> Result<Option<Model>, CoreError>
pub async fn get_by_name(&self, name: &str) -> Result<Option<Model>, CoreError>
Get a model by name.
Sourcepub async fn find_by_identifier(
&self,
identifier: &str,
) -> Result<Model, CoreError>
pub async fn find_by_identifier( &self, identifier: &str, ) -> Result<Model, CoreError>
Find a model by identifier (id, name, or HF ID). Returns error if not found.
Sourcepub async fn import_from_file(
&self,
file_path: &Path,
gguf_parser: &dyn GgufParserPort,
param_count_override: Option<f64>,
) -> Result<Model, CoreError>
pub async fn import_from_file( &self, file_path: &Path, gguf_parser: &dyn GgufParserPort, param_count_override: Option<f64>, ) -> Result<Model, CoreError>
Import a model from a local GGUF file with full metadata extraction.
Validates file, parses GGUF metadata, detects capabilities, and registers with rich metadata. This is the canonical way to add local models.
§Arguments
file_path- Absolute path to the GGUF filegguf_parser- Parser implementation for metadata extractionparam_count_override- Optional user override for parameter count
§Returns
Returns the registered Model with full metadata, or validation error.
§Design
This method validates and parses the GGUF file, then delegates
naming, capability detection, and tag generation to
build_new_model — the construction path shared with the
HuggingFace download path — before persisting the result.
Sourcepub async fn remove(&self, identifier: &str) -> Result<Model, CoreError>
pub async fn remove(&self, identifier: &str) -> Result<Model, CoreError>
Remove a model by identifier. Returns the removed model.
List all unique tags used across all models.
Sourcepub async fn add_tag(&self, model_id: i64, tag: String) -> Result<(), CoreError>
pub async fn add_tag(&self, model_id: i64, tag: String) -> Result<(), CoreError>
Add a tag to a model.
If the tag already exists on the model, this is a no-op.
Sourcepub async fn remove_tag(
&self,
model_id: i64,
tag: &str,
) -> Result<(), CoreError>
pub async fn remove_tag( &self, model_id: i64, tag: &str, ) -> Result<(), CoreError>
Remove a tag from a model.
If the tag doesn’t exist on the model, this is a no-op. System tags
(see crate::domain::is_system_tag) are protected and cannot be
removed through this API — use Self::remove_tag_force for
admin/debug paths that intentionally need to drop them.
Sourcepub async fn remove_tag_force(
&self,
model_id: i64,
tag: &str,
) -> Result<(), CoreError>
pub async fn remove_tag_force( &self, model_id: i64, tag: &str, ) -> Result<(), CoreError>
Force-remove a tag from a model, including system tags.
Bypasses the system-tag protection enforced by Self::remove_tag.
Intended for admin/debug paths (e.g. the gglib model retag --full
rebuild) where the caller intentionally needs to drop a format:*
tag before re-detecting capabilities.
Get all tags for a specific model.
Sourcepub async fn get_by_tag(&self, tag: &str) -> Result<Vec<Model>, CoreError>
pub async fn get_by_tag(&self, tag: &str) -> Result<Vec<Model>, CoreError>
Get all models that have a specific tag.
Sourcepub async fn get_filter_options(&self) -> Result<ModelFilterOptions, CoreError>
pub async fn get_filter_options(&self) -> Result<ModelFilterOptions, CoreError>
Get filter options aggregated from all models.
Returns distinct quantizations, parameter count range, and context length range for use in the GUI filter popover.
Note: Uses in-memory aggregation for simplicity. This is acceptable for typical model libraries (<100 models). Revisit if libraries grow large.
Sourcepub async fn bootstrap_capabilities(&self) -> Result<(), CoreError>
pub async fn bootstrap_capabilities(&self) -> Result<(), CoreError>
Backfill capabilities for models that don’t have them set.
This runs on startup to handle models with unknown capabilities. Only infers if capabilities are empty (0/unknown).
§INVARIANT
Never overwrite explicitly-set capabilities. Only infer when unknown.
Sourcepub async fn retag_model(
&self,
model_id: i64,
gguf_parser: &dyn GgufParserPort,
full: bool,
) -> Result<Option<RetagDiff>, CoreError>
pub async fn retag_model( &self, model_id: i64, gguf_parser: &dyn GgufParserPort, full: bool, ) -> Result<Option<RetagDiff>, CoreError>
Re-derive auto-tags for a single model from its persisted GGUF metadata.
full = false (default) is additive: any newly-detected tag that
isn’t already present is appended; nothing is ever removed. This is
the safe path for backfilling format:* tags on models imported
before format-tag detection landed.
full = true performs a full rebuild: every previously auto-generated
tag (the predefined capability tag namespace plus every existing
format:* tag) is dropped and the freshly-detected set is added in
its place. User-curated tags outside that namespace are preserved.
Returns None when the tag set is unchanged (no write occurred) and
Some(diff) when the model was updated, carrying the full added/removed
delta.