2626#include < cstdarg>
2727#include < filesystem>
2828#include < fstream>
29+ #include < future>
2930#include < list>
3031#include < regex>
3132#include < set>
3839#if defined(LLAMA_USE_CURL)
3940#include < curl/curl.h>
4041#include < curl/easy.h>
41- #include < future>
4242#endif
4343
44+ #ifdef __linux__
45+ #include < linux/limits.h>
46+ #elif defined(_WIN32)
47+ # if !defined(PATH_MAX)
48+ # define PATH_MAX MAX_PATH
49+ # endif
50+ #elif defined(_AIX)
51+ #include < sys/limits.h>
52+ #else
53+ #include < sys/syslimits.h>
54+ #endif
55+ #define LLAMA_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
56+
4457using json = nlohmann::ordered_json;
4558
4659std::initializer_list<enum llama_example> mmproj_examples = {
@@ -210,19 +223,6 @@ bool common_has_curl() {
210223 return true ;
211224}
212225
213- #ifdef __linux__
214- #include < linux/limits.h>
215- #elif defined(_WIN32)
216- # if !defined(PATH_MAX)
217- # define PATH_MAX MAX_PATH
218- # endif
219- #elif defined(_AIX)
220- #include < sys/limits.h>
221- #else
222- #include < sys/syslimits.h>
223- #endif
224- #define LLAMA_CURL_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
225-
226226//
227227// CURL utils
228228//
@@ -370,10 +370,9 @@ static bool common_download_head(CURL * curl,
370370}
371371
372372// download one single file from remote URL to local path
373- static bool common_download_file_single (const std::string & url,
374- const std::string & path,
375- const std::string & bearer_token,
376- bool offline) {
373+ static bool common_download_file_single_online (const std::string & url,
374+ const std::string & path,
375+ const std::string & bearer_token) {
377376 // If the file exists, check its JSON metadata companion file.
378377 std::string metadata_path = path + " .json" ;
379378 static const int max_attempts = 3 ;
@@ -386,10 +385,6 @@ static bool common_download_file_single(const std::string & url,
386385 // Check if the file already exists locally
387386 const auto file_exists = std::filesystem::exists (path);
388387 if (file_exists) {
389- if (offline) {
390- LOG_INF (" %s: using cached file (offline mode): %s\n " , __func__, path.c_str ());
391- return true ; // skip verification/downloading
392- }
393388 // Try and read the JSON metadata file (note: stream autoclosed upon exiting this block).
394389 std::ifstream metadata_in (metadata_path);
395390 if (metadata_in.good ()) {
@@ -409,10 +404,6 @@ static bool common_download_file_single(const std::string & url,
409404 }
410405 // if we cannot open the metadata file, we assume that the downloaded file is not valid (etag and last-modified are left empty, so we will download it again)
411406 } else {
412- if (offline) {
413- LOG_ERR (" %s: required file is not available in cache (offline mode): %s\n " , __func__, path.c_str ());
414- return false ;
415- }
416407 LOG_INF (" %s: no previous model file found %s\n " , __func__, path.c_str ());
417408 }
418409
@@ -532,6 +523,89 @@ static bool common_download_file_single(const std::string & url,
532523 return true ;
533524}
534525
526+ std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params & params) {
527+ curl_ptr curl (curl_easy_init (), &curl_easy_cleanup);
528+ curl_slist_ptr http_headers;
529+ std::vector<char > res_buffer;
530+
531+ curl_easy_setopt (curl.get (), CURLOPT_URL, url.c_str ());
532+ curl_easy_setopt (curl.get (), CURLOPT_NOPROGRESS, 1L );
533+ curl_easy_setopt (curl.get (), CURLOPT_FOLLOWLOCATION, 1L );
534+ curl_easy_setopt (curl.get (), CURLOPT_VERBOSE, 1L );
535+ typedef size_t (*CURLOPT_WRITEFUNCTION_PTR)(void * ptr, size_t size, size_t nmemb, void * data);
536+ auto write_callback = [](void * ptr, size_t size, size_t nmemb, void * data) -> size_t {
537+ auto data_vec = static_cast <std::vector<char > *>(data);
538+ data_vec->insert (data_vec->end (), (char *)ptr, (char *)ptr + size * nmemb);
539+ return size * nmemb;
540+ };
541+ curl_easy_setopt (curl.get (), CURLOPT_WRITEFUNCTION, static_cast <CURLOPT_WRITEFUNCTION_PTR>(write_callback));
542+ curl_easy_setopt (curl.get (), CURLOPT_WRITEDATA, &res_buffer);
543+ #if defined(_WIN32)
544+ curl_easy_setopt (curl.get (), CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
545+ #endif
546+ if (params.timeout > 0 ) {
547+ curl_easy_setopt (curl.get (), CURLOPT_TIMEOUT, params.timeout );
548+ }
549+ if (params.max_size > 0 ) {
550+ curl_easy_setopt (curl.get (), CURLOPT_MAXFILESIZE, params.max_size );
551+ }
552+ http_headers.ptr = curl_slist_append (http_headers.ptr , " User-Agent: llama-cpp" );
553+ for (const auto & header : params.headers ) {
554+ http_headers.ptr = curl_slist_append (http_headers.ptr , header.c_str ());
555+ }
556+ curl_easy_setopt (curl.get (), CURLOPT_HTTPHEADER, http_headers.ptr );
557+
558+ CURLcode res = curl_easy_perform (curl.get ());
559+
560+ if (res != CURLE_OK) {
561+ std::string error_msg = curl_easy_strerror (res);
562+ throw std::runtime_error (" error: cannot make GET request: " + error_msg);
563+ }
564+
565+ long res_code;
566+ curl_easy_getinfo (curl.get (), CURLINFO_RESPONSE_CODE, &res_code);
567+
568+ return { res_code, std::move (res_buffer) };
569+ }
570+
571+ #else
572+
573+ bool common_has_curl () {
574+ return false ;
575+ }
576+
577+ static bool common_download_file_single_online (const std::string &, const std::string &, const std::string &) {
578+ LOG_ERR (" error: built without CURL, cannot download model from internet\n " );
579+ return false ;
580+ }
581+
582+ std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params &) {
583+ if (!url.empty ()) {
584+ throw std::runtime_error (" error: built without CURL, cannot download model from the internet" );
585+ }
586+
587+ return {};
588+ }
589+
590+ #endif // LLAMA_USE_CURL
591+
592+ static bool common_download_file_single (const std::string & url,
593+ const std::string & path,
594+ const std::string & bearer_token,
595+ bool offline) {
596+ if (!offline) {
597+ return common_download_file_single_online (url, path, bearer_token);
598+ }
599+
600+ if (!std::filesystem::exists (path)) {
601+ LOG_ERR (" %s: required file is not available in cache (offline mode): %s\n " , __func__, path.c_str ());
602+ return false ;
603+ }
604+
605+ LOG_INF (" %s: using cached file (offline mode): %s\n " , __func__, path.c_str ());
606+ return true ;
607+ }
608+
535609// download multiple files from remote URLs to local paths
536610// the input is a vector of pairs <url, path>
537611static bool common_download_file_multiple (const std::vector<std::pair<std::string, std::string>> & urls, const std::string & bearer_token, bool offline) {
@@ -590,7 +664,7 @@ static bool common_download_model(
590664
591665 if (n_split > 1 ) {
592666 char split_prefix[PATH_MAX] = {0 };
593- char split_url_prefix[LLAMA_CURL_MAX_URL_LENGTH ] = {0 };
667+ char split_url_prefix[LLAMA_MAX_URL_LENGTH ] = {0 };
594668
595669 // Verify the first split file format
596670 // and extract split URL and PATH prefixes
@@ -611,7 +685,7 @@ static bool common_download_model(
611685 char split_path[PATH_MAX] = {0 };
612686 llama_split_path (split_path, sizeof (split_path), split_prefix, idx, n_split);
613687
614- char split_url[LLAMA_CURL_MAX_URL_LENGTH ] = {0 };
688+ char split_url[LLAMA_MAX_URL_LENGTH ] = {0 };
615689 llama_split_path (split_url, sizeof (split_url), split_url_prefix, idx, n_split);
616690
617691 if (std::string (split_path) == model.path ) {
@@ -628,50 +702,6 @@ static bool common_download_model(
628702 return true ;
629703}
630704
631- std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params & params) {
632- curl_ptr curl (curl_easy_init (), &curl_easy_cleanup);
633- curl_slist_ptr http_headers;
634- std::vector<char > res_buffer;
635-
636- curl_easy_setopt (curl.get (), CURLOPT_URL, url.c_str ());
637- curl_easy_setopt (curl.get (), CURLOPT_NOPROGRESS, 1L );
638- curl_easy_setopt (curl.get (), CURLOPT_FOLLOWLOCATION, 1L );
639- typedef size_t (*CURLOPT_WRITEFUNCTION_PTR)(void * ptr, size_t size, size_t nmemb, void * data);
640- auto write_callback = [](void * ptr, size_t size, size_t nmemb, void * data) -> size_t {
641- auto data_vec = static_cast <std::vector<char > *>(data);
642- data_vec->insert (data_vec->end (), (char *)ptr, (char *)ptr + size * nmemb);
643- return size * nmemb;
644- };
645- curl_easy_setopt (curl.get (), CURLOPT_WRITEFUNCTION, static_cast <CURLOPT_WRITEFUNCTION_PTR>(write_callback));
646- curl_easy_setopt (curl.get (), CURLOPT_WRITEDATA, &res_buffer);
647- #if defined(_WIN32)
648- curl_easy_setopt (curl.get (), CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
649- #endif
650- if (params.timeout > 0 ) {
651- curl_easy_setopt (curl.get (), CURLOPT_TIMEOUT, params.timeout );
652- }
653- if (params.max_size > 0 ) {
654- curl_easy_setopt (curl.get (), CURLOPT_MAXFILESIZE, params.max_size );
655- }
656- http_headers.ptr = curl_slist_append (http_headers.ptr , " User-Agent: llama-cpp" );
657- for (const auto & header : params.headers ) {
658- http_headers.ptr = curl_slist_append (http_headers.ptr , header.c_str ());
659- }
660- curl_easy_setopt (curl.get (), CURLOPT_HTTPHEADER, http_headers.ptr );
661-
662- CURLcode res = curl_easy_perform (curl.get ());
663-
664- if (res != CURLE_OK) {
665- std::string error_msg = curl_easy_strerror (res);
666- throw std::runtime_error (" error: cannot make GET request: " + error_msg);
667- }
668-
669- long res_code;
670- curl_easy_getinfo (curl.get (), CURLINFO_RESPONSE_CODE, &res_code);
671-
672- return { res_code, std::move (res_buffer) };
673- }
674-
675705/* *
676706 * Allow getting the HF file from the HF repo with tag (like ollama), for example:
677707 * - bartowski/Llama-3.2-3B-Instruct-GGUF:q4
@@ -738,21 +768,17 @@ static struct common_hf_file_res common_get_hf_file(const std::string & hf_repo_
738768 std::string mmprojFile;
739769
740770 if (res_code == 200 || res_code == 304 ) {
741- // extract ggufFile.rfilename in json, using regex
742- {
743- std::regex pattern (" \" ggufFile\" [\\ s\\ S]*?\" rfilename\"\\ s*:\\ s*\" ([^\" ]+)\" " );
744- std::smatch match;
745- if (std::regex_search (res_str, match, pattern)) {
746- ggufFile = match[1 ].str ();
771+ try {
772+ auto j = json::parse (res_str);
773+
774+ if (j.contains (" ggufFile" ) && j[" ggufFile" ].contains (" rfilename" )) {
775+ ggufFile = j[" ggufFile" ][" rfilename" ].get <std::string>();
747776 }
748- }
749- // extract mmprojFile.rfilename in json, using regex
750- {
751- std::regex pattern (" \" mmprojFile\" [\\ s\\ S]*?\" rfilename\"\\ s*:\\ s*\" ([^\" ]+)\" " );
752- std::smatch match;
753- if (std::regex_search (res_str, match, pattern)) {
754- mmprojFile = match[1 ].str ();
777+ if (j.contains (" mmprojFile" ) && j[" mmprojFile" ].contains (" rfilename" )) {
778+ mmprojFile = j[" mmprojFile" ][" rfilename" ].get <std::string>();
755779 }
780+ } catch (const std::exception & e) {
781+ throw std::runtime_error (std::string (" error parsing manifest JSON: " ) + e.what ());
756782 }
757783 if (!use_cache) {
758784 // if not using cached response, update the cache file
@@ -772,45 +798,6 @@ static struct common_hf_file_res common_get_hf_file(const std::string & hf_repo_
772798 return { hf_repo, ggufFile, mmprojFile };
773799}
774800
775- #else
776-
777- bool common_has_curl () {
778- return false ;
779- }
780-
781- static bool common_download_file_single (const std::string &, const std::string &, const std::string &, bool ) {
782- LOG_ERR (" error: built without CURL, cannot download model from internet\n " );
783- return false ;
784- }
785-
786- static bool common_download_file_multiple (const std::vector<std::pair<std::string, std::string>> &, const std::string &, bool ) {
787- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
788- return false ;
789- }
790-
791- static bool common_download_model (
792- const common_params_model &,
793- const std::string &,
794- bool ) {
795- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
796- return false ;
797- }
798-
799- static struct common_hf_file_res common_get_hf_file (const std::string &, const std::string &, bool ) {
800- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
801- return {};
802- }
803-
804- std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params &) {
805- if (!url.empty ()) {
806- throw std::runtime_error (" error: built without CURL, cannot download model from the internet" );
807- }
808-
809- return {};
810- }
811-
812- #endif // LLAMA_USE_CURL
813-
814801//
815802// Docker registry functions
816803//
@@ -1070,8 +1057,6 @@ static std::string get_all_kv_cache_types() {
10701057//
10711058
10721059static bool common_params_parse_ex (int argc, char ** argv, common_params_context & ctx_arg) {
1073- std::string arg;
1074- const std::string arg_prefix = " --" ;
10751060 common_params & params = ctx_arg.params ;
10761061
10771062 std::unordered_map<std::string, common_arg *> arg_to_options;
0 commit comments