|
6 | 6 | #include "log.h" |
7 | 7 | #include "sampling.h" |
8 | 8 | #include "download.h" |
| 9 | +#include "preset.h" |
9 | 10 |
|
10 | 11 | // fix problem with std::min and std::max |
11 | 12 | #if defined(_WIN32) |
@@ -268,6 +269,46 @@ static void parse_tensor_buffer_overrides(const std::string & value, std::vector |
268 | 269 | } |
269 | 270 | } |
270 | 271 |
|
| 272 | +static std::string clean_file_name(const std::string & fname) { |
| 273 | + std::string clean_fname = fname; |
| 274 | + string_replace_all(clean_fname, "\\", "_"); |
| 275 | + string_replace_all(clean_fname, "/", "_"); |
| 276 | + return clean_fname; |
| 277 | +} |
| 278 | + |
| 279 | +static bool common_params_handle_remote_preset(common_params & params, llama_example ex) { |
| 280 | + GGML_ASSERT(!params.model.hf_repo.empty()); |
| 281 | + |
| 282 | + const bool offline = params.offline; |
| 283 | + std::string model_endpoint = get_model_endpoint(); |
| 284 | + auto preset_url = model_endpoint + params.model.hf_repo + "/resolve/main/preset.ini"; |
| 285 | + |
| 286 | + // prepare local path for caching |
| 287 | + auto preset_fname = clean_file_name(params.model.hf_repo + "_preset.ini"); |
| 288 | + auto preset_path = fs_get_cache_file(preset_fname); |
| 289 | + const int status = common_download_file_single(preset_url, preset_path, params.hf_token, offline); |
| 290 | + const bool has_preset = status >= 200 && status < 400; |
| 291 | + |
| 292 | + // remote preset is optional, so we don't error out if not found |
| 293 | + if (has_preset) { |
| 294 | + LOG_INF("applying remote preset from %s\n", preset_url.c_str()); |
| 295 | + common_preset_context ctx(ex, /* only_remote_allowed */ true); |
| 296 | + common_preset global; // unused for now |
| 297 | + auto remote_presets = ctx.load_from_ini(preset_path, global); |
| 298 | + if (remote_presets.find(COMMON_PRESET_DEFAULT_NAME) != remote_presets.end()) { |
| 299 | + common_preset & preset = remote_presets.at(COMMON_PRESET_DEFAULT_NAME); |
| 300 | + LOG_INF("\n%s", preset.to_ini().c_str()); // to_ini already added trailing newline |
| 301 | + preset.apply_to_params(params); |
| 302 | + } else { |
| 303 | + throw std::runtime_error("Remote preset.ini does not contain [" + std::string(COMMON_PRESET_DEFAULT_NAME) + "] section"); |
| 304 | + } |
| 305 | + } else { |
| 306 | + LOG_INF("%s", "no remote preset found, skipping\n"); |
| 307 | + } |
| 308 | + |
| 309 | + return has_preset; |
| 310 | +} |
| 311 | + |
271 | 312 | struct handle_model_result { |
272 | 313 | bool found_mmproj = false; |
273 | 314 | common_params_model mmproj; |
@@ -309,9 +350,7 @@ static handle_model_result common_params_handle_model( |
309 | 350 | // make sure model path is present (for caching purposes) |
310 | 351 | if (model.path.empty()) { |
311 | 352 | // this is to avoid different repo having same file name, or same file name in different subdirs |
312 | | - std::string filename = model.hf_repo + "_" + model.hf_file; |
313 | | - // to make sure we don't have any slashes in the filename |
314 | | - string_replace_all(filename, "/", "_"); |
| 353 | + std::string filename = clean_file_name(model.hf_repo + "_" + model.hf_file); |
315 | 354 | model.path = fs_get_cache_file(filename); |
316 | 355 | } |
317 | 356 |
|
@@ -425,61 +464,87 @@ static bool common_params_parse_ex(int argc, char ** argv, common_params_context |
425 | 464 | } |
426 | 465 | }; |
427 | 466 |
|
428 | | - std::set<std::string> seen_args; |
| 467 | + auto parse_cli_args = [&]() { |
| 468 | + std::set<std::string> seen_args; |
429 | 469 |
|
430 | | - for (int i = 1; i < argc; i++) { |
431 | | - const std::string arg_prefix = "--"; |
| 470 | + for (int i = 1; i < argc; i++) { |
| 471 | + const std::string arg_prefix = "--"; |
432 | 472 |
|
433 | | - std::string arg = argv[i]; |
434 | | - if (arg.compare(0, arg_prefix.size(), arg_prefix) == 0) { |
435 | | - std::replace(arg.begin(), arg.end(), '_', '-'); |
436 | | - } |
437 | | - if (arg_to_options.find(arg) == arg_to_options.end()) { |
438 | | - throw std::invalid_argument(string_format("error: invalid argument: %s", arg.c_str())); |
439 | | - } |
440 | | - if (!seen_args.insert(arg).second) { |
441 | | - LOG_WRN("DEPRECATED: argument '%s' specified multiple times, use comma-separated values instead (only last value will be used)\n", arg.c_str()); |
442 | | - } |
443 | | - auto & tmp = arg_to_options[arg]; |
444 | | - auto opt = *tmp.first; |
445 | | - bool is_positive = tmp.second; |
446 | | - if (opt.has_value_from_env()) { |
447 | | - fprintf(stderr, "warn: %s environment variable is set, but will be overwritten by command line argument %s\n", opt.env, arg.c_str()); |
448 | | - } |
449 | | - try { |
450 | | - if (opt.handler_void) { |
451 | | - opt.handler_void(params); |
452 | | - continue; |
| 473 | + std::string arg = argv[i]; |
| 474 | + if (arg.compare(0, arg_prefix.size(), arg_prefix) == 0) { |
| 475 | + std::replace(arg.begin(), arg.end(), '_', '-'); |
453 | 476 | } |
454 | | - if (opt.handler_bool) { |
455 | | - opt.handler_bool(params, is_positive); |
456 | | - continue; |
| 477 | + if (arg_to_options.find(arg) == arg_to_options.end()) { |
| 478 | + throw std::invalid_argument(string_format("error: invalid argument: %s", arg.c_str())); |
457 | 479 | } |
458 | | - |
459 | | - // arg with single value |
460 | | - check_arg(i); |
461 | | - std::string val = argv[++i]; |
462 | | - if (opt.handler_int) { |
463 | | - opt.handler_int(params, std::stoi(val)); |
464 | | - continue; |
| 480 | + if (!seen_args.insert(arg).second) { |
| 481 | + LOG_WRN("DEPRECATED: argument '%s' specified multiple times, use comma-separated values instead (only last value will be used)\n", arg.c_str()); |
| 482 | + } |
| 483 | + auto & tmp = arg_to_options[arg]; |
| 484 | + auto opt = *tmp.first; |
| 485 | + bool is_positive = tmp.second; |
| 486 | + if (opt.has_value_from_env()) { |
| 487 | + fprintf(stderr, "warn: %s environment variable is set, but will be overwritten by command line argument %s\n", opt.env, arg.c_str()); |
465 | 488 | } |
466 | | - if (opt.handler_string) { |
467 | | - opt.handler_string(params, val); |
468 | | - continue; |
| 489 | + try { |
| 490 | + if (opt.handler_void) { |
| 491 | + opt.handler_void(params); |
| 492 | + continue; |
| 493 | + } |
| 494 | + if (opt.handler_bool) { |
| 495 | + opt.handler_bool(params, is_positive); |
| 496 | + continue; |
| 497 | + } |
| 498 | + |
| 499 | + // arg with single value |
| 500 | + check_arg(i); |
| 501 | + std::string val = argv[++i]; |
| 502 | + if (opt.handler_int) { |
| 503 | + opt.handler_int(params, std::stoi(val)); |
| 504 | + continue; |
| 505 | + } |
| 506 | + if (opt.handler_string) { |
| 507 | + opt.handler_string(params, val); |
| 508 | + continue; |
| 509 | + } |
| 510 | + |
| 511 | + // arg with 2 values |
| 512 | + check_arg(i); |
| 513 | + std::string val2 = argv[++i]; |
| 514 | + if (opt.handler_str_str) { |
| 515 | + opt.handler_str_str(params, val, val2); |
| 516 | + continue; |
| 517 | + } |
| 518 | + } catch (std::exception & e) { |
| 519 | + throw std::invalid_argument(string_format( |
| 520 | + "error while handling argument \"%s\": %s\n\n" |
| 521 | + "usage:\n%s\n\nto show complete usage, run with -h", |
| 522 | + arg.c_str(), e.what(), opt.to_string().c_str())); |
469 | 523 | } |
| 524 | + } |
| 525 | + }; |
470 | 526 |
|
471 | | - // arg with 2 values |
472 | | - check_arg(i); |
473 | | - std::string val2 = argv[++i]; |
474 | | - if (opt.handler_str_str) { |
475 | | - opt.handler_str_str(params, val, val2); |
476 | | - continue; |
477 | | - } |
478 | | - } catch (std::exception & e) { |
479 | | - throw std::invalid_argument(string_format( |
480 | | - "error while handling argument \"%s\": %s\n\n" |
481 | | - "usage:\n%s\n\nto show complete usage, run with -h", |
482 | | - arg.c_str(), e.what(), opt.to_string().c_str())); |
| 527 | + // parse the first time to get -hf option (used for remote preset) |
| 528 | + parse_cli_args(); |
| 529 | + |
| 530 | + // maybe handle remote preset |
| 531 | + if (!params.model.hf_repo.empty()) { |
| 532 | + std::string cli_hf_repo = params.model.hf_repo; |
| 533 | + bool has_preset = common_params_handle_remote_preset(params, ctx_arg.ex); |
| 534 | + |
| 535 | + // special case: if hf_repo explicitly set by preset, we need to preserve it (ignore CLI value) |
| 536 | + // this is useful when we have one HF repo pointing to other HF repos (one model - multiple GGUFs) |
| 537 | + std::string preset_hf_repo = params.model.hf_repo; |
| 538 | + bool preset_has_hf_repo = preset_hf_repo != cli_hf_repo; |
| 539 | + |
| 540 | + if (has_preset) { |
| 541 | + // re-parse CLI args to override preset values |
| 542 | + parse_cli_args(); |
| 543 | + } |
| 544 | + |
| 545 | + // preserve hf_repo from preset if needed |
| 546 | + if (preset_has_hf_repo) { |
| 547 | + params.model.hf_repo = preset_hf_repo; |
483 | 548 | } |
484 | 549 | } |
485 | 550 |
|
|
0 commit comments