@@ -455,40 +455,79 @@ impl Default for ModelDatabase {
455455 }
456456}
457457
458+ /// Normalize a model name/ID to a canonical slug for deduplication.
459+ ///
460+ /// Strips the `org/` prefix, lowercases, and collapses `-`/`_`/`.` so that
461+ /// `meta-llama/Llama-3.1-8B` and `meta-llama/llama-3.1-8b` compare equal.
462+ pub ( crate ) fn canonical_slug ( name : & str ) -> String {
463+ let slug = name. split ( '/' ) . last ( ) . unwrap_or ( name) ;
464+ slug. to_lowercase ( ) . replace ( [ '-' , '_' , '.' ] , "" )
465+ }
466+
467+ /// Parse the compile-time embedded JSON into a flat `Vec<LlmModel>`.
468+ fn load_embedded ( ) -> Vec < LlmModel > {
469+ let entries: Vec < HfModelEntry > =
470+ serde_json:: from_str ( HF_MODELS_JSON ) . expect ( "Failed to parse embedded hf_models.json" ) ;
471+ entries
472+ . into_iter ( )
473+ . map ( |e| {
474+ let mut model = LlmModel {
475+ name : e. name ,
476+ provider : e. provider ,
477+ parameter_count : e. parameter_count ,
478+ parameters_raw : e. parameters_raw ,
479+ min_ram_gb : e. min_ram_gb ,
480+ recommended_ram_gb : e. recommended_ram_gb ,
481+ min_vram_gb : e. min_vram_gb ,
482+ quantization : e. quantization ,
483+ context_length : e. context_length ,
484+ use_case : e. use_case ,
485+ is_moe : e. is_moe ,
486+ num_experts : e. num_experts ,
487+ active_experts : e. active_experts ,
488+ active_parameters : e. active_parameters ,
489+ release_date : e. release_date ,
490+ gguf_sources : e. gguf_sources ,
491+ capabilities : e. capabilities ,
492+ format : e. format ,
493+ num_attention_heads : None ,
494+ num_key_value_heads : None ,
495+ } ;
496+ model. capabilities = Capability :: infer ( & model) ;
497+ model
498+ } )
499+ . collect ( )
500+ }
501+
458502impl ModelDatabase {
503+ /// Load only the compile-time embedded model list (no cache).
504+ /// Used internally by the updater to determine which models are already known.
505+ pub fn embedded ( ) -> Self {
506+ ModelDatabase {
507+ models : load_embedded ( ) ,
508+ }
509+ }
510+
511+ /// Load the embedded model list **and** merge any locally cached models.
512+ ///
513+ /// Cached models are appended after the embedded ones; if an ID already
514+ /// exists in the embedded list it is skipped to avoid duplication.
515+ /// Silently ignores a missing or corrupt cache file.
459516 pub fn new ( ) -> Self {
460- let entries: Vec < HfModelEntry > =
461- serde_json:: from_str ( HF_MODELS_JSON ) . expect ( "Failed to parse embedded hf_models.json" ) ;
462-
463- let models = entries
464- . into_iter ( )
465- . map ( |e| {
466- let mut model = LlmModel {
467- name : e. name ,
468- provider : e. provider ,
469- parameter_count : e. parameter_count ,
470- parameters_raw : e. parameters_raw ,
471- min_ram_gb : e. min_ram_gb ,
472- recommended_ram_gb : e. recommended_ram_gb ,
473- min_vram_gb : e. min_vram_gb ,
474- quantization : e. quantization ,
475- context_length : e. context_length ,
476- use_case : e. use_case ,
477- is_moe : e. is_moe ,
478- num_experts : e. num_experts ,
479- active_experts : e. active_experts ,
480- active_parameters : e. active_parameters ,
481- release_date : e. release_date ,
482- gguf_sources : e. gguf_sources ,
483- capabilities : e. capabilities ,
484- format : e. format ,
485- num_attention_heads : None ,
486- num_key_value_heads : None ,
487- } ;
488- model. capabilities = Capability :: infer ( & model) ;
489- model
490- } )
491- . collect ( ) ;
517+ let mut models = load_embedded ( ) ;
518+
519+ // Merge cached models (from `llmfit update`) without duplicating.
520+ // canonical_slug normalizes org/ prefix, case, and separators so that
521+ // e.g. `meta-llama/Llama-3.1-8B` and `meta-llama/llama-3.1-8b` are
522+ // treated as the same model.
523+ let embedded_keys: std:: collections:: HashSet < String > =
524+ models. iter ( ) . map ( |m| canonical_slug ( & m. name ) ) . collect ( ) ;
525+
526+ for cached in crate :: update:: load_cache ( ) {
527+ if !embedded_keys. contains ( & canonical_slug ( & cached. name ) ) {
528+ models. push ( cached) ;
529+ }
530+ }
492531
493532 ModelDatabase { models }
494533 }
0 commit comments