@@ -496,8 +496,12 @@ static bool common_download_model(
496496 LOG_ERR (" %s: invalid model url\n " , __func__);
497497 return false ;
498498 }
499+ if (model.paths .size () != 1 ) {
500+ LOG_ERR (" %s: model url can only be specified with one path\n " , __func__);
501+ return false ;
502+ }
499503
500- if (!common_download_file_single (model.url , model.path , bearer_token, offline)) {
504+ if (!common_download_file_single (model.url , model.paths [ 0 ] , bearer_token, offline)) {
501505 return false ;
502506 }
503507
@@ -508,9 +512,9 @@ static bool common_download_model(
508512 /* .no_alloc = */ true ,
509513 /* .ctx = */ NULL ,
510514 };
511- auto * ctx_gguf = gguf_init_from_file (model.path .c_str (), gguf_params);
515+ auto * ctx_gguf = gguf_init_from_file (model.paths [ 0 ] .c_str (), gguf_params);
512516 if (!ctx_gguf) {
513- LOG_ERR (" \n %s: failed to load input GGUF from %s\n " , __func__, model.path .c_str ());
517+ LOG_ERR (" \n %s: failed to load input GGUF from %s\n " , __func__, model.paths [ 0 ] .c_str ());
514518 return false ;
515519 }
516520
@@ -529,8 +533,8 @@ static bool common_download_model(
529533 // Verify the first split file format
530534 // and extract split URL and PATH prefixes
531535 {
532- if (!llama_split_prefix (split_prefix, sizeof (split_prefix), model.path .c_str (), 0 , n_split)) {
533- LOG_ERR (" \n %s: unexpected model file name: %s n_split=%d\n " , __func__, model.path .c_str (), n_split);
536+ if (!llama_split_prefix (split_prefix, sizeof (split_prefix), model.paths [ 0 ] .c_str (), 0 , n_split)) {
537+ LOG_ERR (" \n %s: unexpected model file name: %s n_split=%d\n " , __func__, model.paths [ 0 ] .c_str (), n_split);
534538 return false ;
535539 }
536540
@@ -548,7 +552,7 @@ static bool common_download_model(
548552 char split_url[LLAMA_CURL_MAX_URL_LENGTH] = {0 };
549553 llama_split_path (split_url, sizeof (split_url), split_url_prefix, idx, n_split);
550554
551- if (std::string (split_path) == model.path ) {
555+ if (std::string (split_path) == model.paths [ 0 ] ) {
552556 continue ; // skip the already downloaded file
553557 }
554558
@@ -798,7 +802,7 @@ static handle_model_result common_params_handle_model(
798802 if (!model.hf_repo .empty ()) {
799803 // short-hand to avoid specifying --hf-file -> default it to --model
800804 if (model.hf_file .empty ()) {
801- if (model.path .empty ()) {
805+ if (model.paths .empty ()) {
802806 auto auto_detected = common_get_hf_file (model.hf_repo , bearer_token, offline);
803807 if (auto_detected.repo .empty () || auto_detected.ggufFile .empty ()) {
804808 exit (1 ); // built without CURL, error message already printed
@@ -811,30 +815,30 @@ static handle_model_result common_params_handle_model(
811815 result.mmproj .hf_file = auto_detected.mmprojFile ;
812816 }
813817 } else {
814- model.hf_file = model.path ;
818+ model.hf_file = model.paths [ 0 ] ;
815819 }
816820 }
817821
818822 std::string model_endpoint = get_model_endpoint ();
819823 model.url = model_endpoint + model.hf_repo + " /resolve/main/" + model.hf_file ;
820824 // make sure model path is present (for caching purposes)
821- if (model.path .empty ()) {
825+ if (model.paths .empty ()) {
822826 // this is to avoid different repo having same file name, or same file name in different subdirs
823827 std::string filename = model.hf_repo + " _" + model.hf_file ;
824828 // to make sure we don't have any slashes in the filename
825829 string_replace_all (filename, " /" , " _" );
826- model.path = fs_get_cache_file (filename);
830+ model.paths . push_back ( fs_get_cache_file (filename) );
827831 }
828832
829833 } else if (!model.url .empty ()) {
830- if (model.path .empty ()) {
834+ if (model.paths .empty ()) {
831835 auto f = string_split<std::string>(model.url , ' #' ).front ();
832836 f = string_split<std::string>(f, ' ?' ).front ();
833- model.path = fs_get_cache_file (string_split<std::string>(f, ' /' ).back ());
837+ model.paths . push_back ( fs_get_cache_file (string_split<std::string>(f, ' /' ).back () ));
834838 }
835839
836- } else if (model.path .empty ()) {
837- model.path = model_path_default;
840+ } else if (model.paths . empty () && !model_path_default .empty ()) {
841+ model.paths . push_back ( model_path_default) ;
838842 }
839843 }
840844
@@ -986,7 +990,7 @@ static bool common_params_parse_ex(int argc, char ** argv, common_params_context
986990 auto res = common_params_handle_model (params.model , params.hf_token , DEFAULT_MODEL_PATH, params.offline );
987991 if (params.no_mmproj ) {
988992 params.mmproj = {};
989- } else if (res.found_mmproj && params.mmproj .path .empty () && params.mmproj .url .empty ()) {
993+ } else if (res.found_mmproj && params.mmproj .paths .empty () && params.mmproj .url .empty ()) {
990994 // optionally, handle mmproj model when -hf is specified
991995 params.mmproj = res.mmproj ;
992996 }
@@ -2285,7 +2289,11 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
22852289 " path to a multimodal projector file. see tools/mtmd/README.md\n "
22862290 " note: if -hf is used, this argument can be omitted" ,
22872291 [](common_params & params, const std::string & value) {
2288- params.mmproj .path = value;
2292+ if (params.mmproj .paths .empty ()) {
2293+ params.mmproj .paths .push_back (value);
2294+ } else {
2295+ params.mmproj .paths [0 ] = value;
2296+ }
22892297 }
22902298 ).set_examples (mmproj_examples).set_env (" LLAMA_ARG_MMPROJ" ));
22912299 add_opt (common_arg (
@@ -2597,7 +2605,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
25972605 " or `--model-url` if set, otherwise %s)" , DEFAULT_MODEL_PATH
25982606 ),
25992607 [](common_params & params, const std::string & value) {
2600- params.model .path = value;
2608+ params.model .paths . push_back ( value) ;
26012609 }
26022610 ).set_examples ({LLAMA_EXAMPLE_COMMON, LLAMA_EXAMPLE_EXPORT_LORA}).set_env (" LLAMA_ARG_MODEL" ));
26032611 add_opt (common_arg (
@@ -3330,7 +3338,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
33303338 {" -md" , " --model-draft" }, " FNAME" ,
33313339 " draft model for speculative decoding (default: unused)" ,
33323340 [](common_params & params, const std::string & value) {
3333- params.speculative .model .path = value;
3341+ params.speculative .model .paths . push_back ( value) ;
33343342 }
33353343 ).set_examples ({LLAMA_EXAMPLE_SPECULATIVE, LLAMA_EXAMPLE_SERVER}).set_env (" LLAMA_ARG_MODEL_DRAFT" ));
33363344 add_opt (common_arg (
@@ -3371,7 +3379,7 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
33713379 {" -mv" , " --model-vocoder" }, " FNAME" ,
33723380 " vocoder model for audio generation (default: unused)" ,
33733381 [](common_params & params, const std::string & value) {
3374- params.vocoder .model .path = value;
3382+ params.vocoder .model .paths . push_back ( value) ;
33753383 }
33763384 ).set_examples ({LLAMA_EXAMPLE_TTS, LLAMA_EXAMPLE_SERVER}));
33773385 add_opt (common_arg (
0 commit comments