Skip to content

Commit efe5463

Browse files
committed
Merge branch 'upstream' into concedo_experimental
# Conflicts: # .github/workflows/build.yml # CODEOWNERS # CONTRIBUTING.md # README.md # ci/run.sh # examples/embedding/README.md # tests/test-backend-ops.cpp
2 parents 59b6a09 + 37a23c1 commit efe5463

File tree

9 files changed

+395
-206
lines changed

9 files changed

+395
-206
lines changed

common/arg.cpp

Lines changed: 111 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <cstdarg>
2727
#include <filesystem>
2828
#include <fstream>
29+
#include <future>
2930
#include <list>
3031
#include <regex>
3132
#include <set>
@@ -38,9 +39,21 @@
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+
4457
using json = nlohmann::ordered_json;
4558

4659
std::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>
537611
static 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

10721059
static 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

Comments
 (0)