24
24
#include < cstdarg>
25
25
#include < filesystem>
26
26
#include < fstream>
27
+ #include < future>
27
28
#include < list>
28
29
#include < regex>
29
30
#include < set>
36
37
#if defined(LLAMA_USE_CURL)
37
38
#include < curl/curl.h>
38
39
#include < curl/easy.h>
39
- #include < future>
40
40
#endif
41
41
42
+ #ifdef __linux__
43
+ #include < linux/limits.h>
44
+ #elif defined(_WIN32)
45
+ # if !defined(PATH_MAX)
46
+ # define PATH_MAX MAX_PATH
47
+ # endif
48
+ #elif defined(_AIX)
49
+ #include < sys/limits.h>
50
+ #else
51
+ #include < sys/syslimits.h>
52
+ #endif
53
+ #define LLAMA_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
54
+
42
55
using json = nlohmann::ordered_json;
43
56
44
57
std::initializer_list<enum llama_example> mmproj_examples = {
@@ -208,19 +221,6 @@ bool common_has_curl() {
208
221
return true ;
209
222
}
210
223
211
- #ifdef __linux__
212
- #include < linux/limits.h>
213
- #elif defined(_WIN32)
214
- # if !defined(PATH_MAX)
215
- # define PATH_MAX MAX_PATH
216
- # endif
217
- #elif defined(_AIX)
218
- #include < sys/limits.h>
219
- #else
220
- #include < sys/syslimits.h>
221
- #endif
222
- #define LLAMA_CURL_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
223
-
224
224
//
225
225
// CURL utils
226
226
//
@@ -368,10 +368,9 @@ static bool common_download_head(CURL * curl,
368
368
}
369
369
370
370
// download one single file from remote URL to local path
371
- static bool common_download_file_single (const std::string & url,
372
- const std::string & path,
373
- const std::string & bearer_token,
374
- bool offline) {
371
+ static bool common_download_file_single_online (const std::string & url,
372
+ const std::string & path,
373
+ const std::string & bearer_token) {
375
374
// If the file exists, check its JSON metadata companion file.
376
375
std::string metadata_path = path + " .json" ;
377
376
static const int max_attempts = 3 ;
@@ -384,10 +383,6 @@ static bool common_download_file_single(const std::string & url,
384
383
// Check if the file already exists locally
385
384
const auto file_exists = std::filesystem::exists (path);
386
385
if (file_exists) {
387
- if (offline) {
388
- LOG_INF (" %s: using cached file (offline mode): %s\n " , __func__, path.c_str ());
389
- return true ; // skip verification/downloading
390
- }
391
386
// Try and read the JSON metadata file (note: stream autoclosed upon exiting this block).
392
387
std::ifstream metadata_in (metadata_path);
393
388
if (metadata_in.good ()) {
@@ -407,10 +402,6 @@ static bool common_download_file_single(const std::string & url,
407
402
}
408
403
// 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)
409
404
} else {
410
- if (offline) {
411
- LOG_ERR (" %s: required file is not available in cache (offline mode): %s\n " , __func__, path.c_str ());
412
- return false ;
413
- }
414
405
LOG_INF (" %s: no previous model file found %s\n " , __func__, path.c_str ());
415
406
}
416
407
@@ -530,6 +521,89 @@ static bool common_download_file_single(const std::string & url,
530
521
return true ;
531
522
}
532
523
524
+ std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params & params) {
525
+ curl_ptr curl (curl_easy_init (), &curl_easy_cleanup);
526
+ curl_slist_ptr http_headers;
527
+ std::vector<char > res_buffer;
528
+
529
+ curl_easy_setopt (curl.get (), CURLOPT_URL, url.c_str ());
530
+ curl_easy_setopt (curl.get (), CURLOPT_NOPROGRESS, 1L );
531
+ curl_easy_setopt (curl.get (), CURLOPT_FOLLOWLOCATION, 1L );
532
+ curl_easy_setopt (curl.get (), CURLOPT_VERBOSE, 1L );
533
+ typedef size_t (*CURLOPT_WRITEFUNCTION_PTR)(void * ptr, size_t size, size_t nmemb, void * data);
534
+ auto write_callback = [](void * ptr, size_t size, size_t nmemb, void * data) -> size_t {
535
+ auto data_vec = static_cast <std::vector<char > *>(data);
536
+ data_vec->insert (data_vec->end (), (char *)ptr, (char *)ptr + size * nmemb);
537
+ return size * nmemb;
538
+ };
539
+ curl_easy_setopt (curl.get (), CURLOPT_WRITEFUNCTION, static_cast <CURLOPT_WRITEFUNCTION_PTR>(write_callback));
540
+ curl_easy_setopt (curl.get (), CURLOPT_WRITEDATA, &res_buffer);
541
+ #if defined(_WIN32)
542
+ curl_easy_setopt (curl.get (), CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
543
+ #endif
544
+ if (params.timeout > 0 ) {
545
+ curl_easy_setopt (curl.get (), CURLOPT_TIMEOUT, params.timeout );
546
+ }
547
+ if (params.max_size > 0 ) {
548
+ curl_easy_setopt (curl.get (), CURLOPT_MAXFILESIZE, params.max_size );
549
+ }
550
+ http_headers.ptr = curl_slist_append (http_headers.ptr , " User-Agent: llama-cpp" );
551
+ for (const auto & header : params.headers ) {
552
+ http_headers.ptr = curl_slist_append (http_headers.ptr , header.c_str ());
553
+ }
554
+ curl_easy_setopt (curl.get (), CURLOPT_HTTPHEADER, http_headers.ptr );
555
+
556
+ CURLcode res = curl_easy_perform (curl.get ());
557
+
558
+ if (res != CURLE_OK) {
559
+ std::string error_msg = curl_easy_strerror (res);
560
+ throw std::runtime_error (" error: cannot make GET request: " + error_msg);
561
+ }
562
+
563
+ long res_code;
564
+ curl_easy_getinfo (curl.get (), CURLINFO_RESPONSE_CODE, &res_code);
565
+
566
+ return { res_code, std::move (res_buffer) };
567
+ }
568
+
569
+ #else
570
+
571
+ bool common_has_curl () {
572
+ return false ;
573
+ }
574
+
575
+ static bool common_download_file_single_online (const std::string &, const std::string &, const std::string &) {
576
+ LOG_ERR (" error: built without CURL, cannot download model from internet\n " );
577
+ return false ;
578
+ }
579
+
580
+ std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params &) {
581
+ if (!url.empty ()) {
582
+ throw std::runtime_error (" error: built without CURL, cannot download model from the internet" );
583
+ }
584
+
585
+ return {};
586
+ }
587
+
588
+ #endif // LLAMA_USE_CURL
589
+
590
+ static bool common_download_file_single (const std::string & url,
591
+ const std::string & path,
592
+ const std::string & bearer_token,
593
+ bool offline) {
594
+ if (!offline) {
595
+ return common_download_file_single_online (url, path, bearer_token);
596
+ }
597
+
598
+ if (!std::filesystem::exists (path)) {
599
+ LOG_ERR (" %s: required file is not available in cache (offline mode): %s\n " , __func__, path.c_str ());
600
+ return false ;
601
+ }
602
+
603
+ LOG_INF (" %s: using cached file (offline mode): %s\n " , __func__, path.c_str ());
604
+ return true ;
605
+ }
606
+
533
607
// download multiple files from remote URLs to local paths
534
608
// the input is a vector of pairs <url, path>
535
609
static bool common_download_file_multiple (const std::vector<std::pair<std::string, std::string>> & urls, const std::string & bearer_token, bool offline) {
@@ -588,7 +662,7 @@ static bool common_download_model(
588
662
589
663
if (n_split > 1 ) {
590
664
char split_prefix[PATH_MAX] = {0 };
591
- char split_url_prefix[LLAMA_CURL_MAX_URL_LENGTH ] = {0 };
665
+ char split_url_prefix[LLAMA_MAX_URL_LENGTH ] = {0 };
592
666
593
667
// Verify the first split file format
594
668
// and extract split URL and PATH prefixes
@@ -609,7 +683,7 @@ static bool common_download_model(
609
683
char split_path[PATH_MAX] = {0 };
610
684
llama_split_path (split_path, sizeof (split_path), split_prefix, idx, n_split);
611
685
612
- char split_url[LLAMA_CURL_MAX_URL_LENGTH ] = {0 };
686
+ char split_url[LLAMA_MAX_URL_LENGTH ] = {0 };
613
687
llama_split_path (split_url, sizeof (split_url), split_url_prefix, idx, n_split);
614
688
615
689
if (std::string (split_path) == model.path ) {
@@ -626,50 +700,6 @@ static bool common_download_model(
626
700
return true ;
627
701
}
628
702
629
- std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params & params) {
630
- curl_ptr curl (curl_easy_init (), &curl_easy_cleanup);
631
- curl_slist_ptr http_headers;
632
- std::vector<char > res_buffer;
633
-
634
- curl_easy_setopt (curl.get (), CURLOPT_URL, url.c_str ());
635
- curl_easy_setopt (curl.get (), CURLOPT_NOPROGRESS, 1L );
636
- curl_easy_setopt (curl.get (), CURLOPT_FOLLOWLOCATION, 1L );
637
- typedef size_t (*CURLOPT_WRITEFUNCTION_PTR)(void * ptr, size_t size, size_t nmemb, void * data);
638
- auto write_callback = [](void * ptr, size_t size, size_t nmemb, void * data) -> size_t {
639
- auto data_vec = static_cast <std::vector<char > *>(data);
640
- data_vec->insert (data_vec->end (), (char *)ptr, (char *)ptr + size * nmemb);
641
- return size * nmemb;
642
- };
643
- curl_easy_setopt (curl.get (), CURLOPT_WRITEFUNCTION, static_cast <CURLOPT_WRITEFUNCTION_PTR>(write_callback));
644
- curl_easy_setopt (curl.get (), CURLOPT_WRITEDATA, &res_buffer);
645
- #if defined(_WIN32)
646
- curl_easy_setopt (curl.get (), CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
647
- #endif
648
- if (params.timeout > 0 ) {
649
- curl_easy_setopt (curl.get (), CURLOPT_TIMEOUT, params.timeout );
650
- }
651
- if (params.max_size > 0 ) {
652
- curl_easy_setopt (curl.get (), CURLOPT_MAXFILESIZE, params.max_size );
653
- }
654
- http_headers.ptr = curl_slist_append (http_headers.ptr , " User-Agent: llama-cpp" );
655
- for (const auto & header : params.headers ) {
656
- http_headers.ptr = curl_slist_append (http_headers.ptr , header.c_str ());
657
- }
658
- curl_easy_setopt (curl.get (), CURLOPT_HTTPHEADER, http_headers.ptr );
659
-
660
- CURLcode res = curl_easy_perform (curl.get ());
661
-
662
- if (res != CURLE_OK) {
663
- std::string error_msg = curl_easy_strerror (res);
664
- throw std::runtime_error (" error: cannot make GET request: " + error_msg);
665
- }
666
-
667
- long res_code;
668
- curl_easy_getinfo (curl.get (), CURLINFO_RESPONSE_CODE, &res_code);
669
-
670
- return { res_code, std::move (res_buffer) };
671
- }
672
-
673
703
/* *
674
704
* Allow getting the HF file from the HF repo with tag (like ollama), for example:
675
705
* - bartowski/Llama-3.2-3B-Instruct-GGUF:q4
@@ -736,21 +766,17 @@ static struct common_hf_file_res common_get_hf_file(const std::string & hf_repo_
736
766
std::string mmprojFile;
737
767
738
768
if (res_code == 200 || res_code == 304 ) {
739
- // extract ggufFile.rfilename in json, using regex
740
- {
741
- std::regex pattern (" \" ggufFile\" [\\ s\\ S]*?\" rfilename\"\\ s*:\\ s*\" ([^\" ]+)\" " );
742
- std::smatch match;
743
- if (std::regex_search (res_str, match, pattern)) {
744
- ggufFile = match[1 ].str ();
769
+ try {
770
+ auto j = json::parse (res_str);
771
+
772
+ if (j.contains (" ggufFile" ) && j[" ggufFile" ].contains (" rfilename" )) {
773
+ ggufFile = j[" ggufFile" ][" rfilename" ].get <std::string>();
745
774
}
746
- }
747
- // extract mmprojFile.rfilename in json, using regex
748
- {
749
- std::regex pattern (" \" mmprojFile\" [\\ s\\ S]*?\" rfilename\"\\ s*:\\ s*\" ([^\" ]+)\" " );
750
- std::smatch match;
751
- if (std::regex_search (res_str, match, pattern)) {
752
- mmprojFile = match[1 ].str ();
775
+ if (j.contains (" mmprojFile" ) && j[" mmprojFile" ].contains (" rfilename" )) {
776
+ mmprojFile = j[" mmprojFile" ][" rfilename" ].get <std::string>();
753
777
}
778
+ } catch (const std::exception & e) {
779
+ throw std::runtime_error (std::string (" error parsing manifest JSON: " ) + e.what ());
754
780
}
755
781
if (!use_cache) {
756
782
// if not using cached response, update the cache file
@@ -770,45 +796,6 @@ static struct common_hf_file_res common_get_hf_file(const std::string & hf_repo_
770
796
return { hf_repo, ggufFile, mmprojFile };
771
797
}
772
798
773
- #else
774
-
775
- bool common_has_curl () {
776
- return false ;
777
- }
778
-
779
- static bool common_download_file_single (const std::string &, const std::string &, const std::string &, bool ) {
780
- LOG_ERR (" error: built without CURL, cannot download model from internet\n " );
781
- return false ;
782
- }
783
-
784
- static bool common_download_file_multiple (const std::vector<std::pair<std::string, std::string>> &, const std::string &, bool ) {
785
- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
786
- return false ;
787
- }
788
-
789
- static bool common_download_model (
790
- const common_params_model &,
791
- const std::string &,
792
- bool ) {
793
- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
794
- return false ;
795
- }
796
-
797
- static struct common_hf_file_res common_get_hf_file (const std::string &, const std::string &, bool ) {
798
- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
799
- return {};
800
- }
801
-
802
- std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params &) {
803
- if (!url.empty ()) {
804
- throw std::runtime_error (" error: built without CURL, cannot download model from the internet" );
805
- }
806
-
807
- return {};
808
- }
809
-
810
- #endif // LLAMA_USE_CURL
811
-
812
799
//
813
800
// Docker registry functions
814
801
//
0 commit comments