Skip to content

Commit eef1c6e

Browse files
committed
support login
1 parent 47672e5 commit eef1c6e

File tree

3 files changed

+116
-1
lines changed

3 files changed

+116
-1
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,20 @@ The [Hugging Face](https://huggingface.co) platform hosts a [number of LLMs](htt
265265

266266
You can either manually download the GGUF file or directly use any `llama.cpp`-compatible models from Hugging Face by using this CLI argument: `-hf <user>/<model>[:quant]`
267267

268+
llama.cpp also supports downloading and running models from [ModelScope](https://www.modelscope.cn/home), just add an env variable: `LLAMACPP_USE_MODELSCOPE=True` to your command with the same arguments(like `-hf <user>/<model>[:quant]`).
269+
270+
```shell
271+
LLAMACPP_USE_MODELSCOPE=True llama-cli -hf Qwen/QwQ-32B-GGUF
272+
```
273+
274+
Pay attention to change the model repo to the **existing repo** of ModelScope. If you want to use a private repo, please make sure you have the rights of the repo and run with the `--hf_token` argument:
275+
276+
```shell
277+
LLAMACPP_USE_MODELSCOPE=True llama-cli -hf Qwen/QwQ-32B-GGUF --hf_token xxx
278+
```
279+
280+
> You can change the endpoint of ModelScope by using `MODELSCOPE_DOMAIN=xxx`(like MODELSCOPE_DOMAIN=www.modelscope.ai).
281+
268282
After downloading a model, use the CLI tools to run it locally - see below.
269283

270284
`llama.cpp` requires the model to be stored in the [GGUF](https://github.com/ggml-org/ggml/blob/master/docs/gguf.md) file format. Models in other data formats can be converted to GGUF using the `convert_*.py` Python scripts in this repo.

common/common.cpp

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1196,6 +1196,30 @@ static bool curl_perform_with_retry(const std::string & url, CURL * curl, int ma
11961196
return false;
11971197
}
11981198

1199+
std::filesystem::path create_credential_path() {
1200+
const char* home_dir = nullptr;
1201+
#ifdef _WIN32
1202+
home_dir = getenv("USERPROFILE");
1203+
if (!home_dir) {
1204+
const char* homeDrive = getenv("HOMEDRIVE");
1205+
const char* homePath = getenv("HOMEPATH");
1206+
if (homeDrive && homePath) return std::string(homeDrive) + homePath;
1207+
char documentsPath[MAX_PATH];
1208+
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentsPath))) return std::string(documentsPath);
1209+
}
1210+
#else
1211+
home_dir = getenv("HOME");
1212+
#endif
1213+
if (home_dir == nullptr) {
1214+
return std::string("");
1215+
}
1216+
const std::filesystem::path credentials_path = std::filesystem::path(home_dir) / ".modelscope" / "credentials";
1217+
if (!exists(credentials_path)) {
1218+
create_directories(credentials_path);
1219+
}
1220+
return credentials_path;
1221+
}
1222+
11991223
static bool common_download_file(const std::string & url, const std::string & path, const std::string & hf_token) {
12001224
// Initialize libcurl
12011225
curl_ptr curl(curl_easy_init(), &curl_easy_cleanup);
@@ -1330,6 +1354,8 @@ static bool common_download_file(const std::string & url, const std::string & pa
13301354
}
13311355
} else {
13321356
should_download = !file_exists;
1357+
const std::filesystem::path cookie_file = create_credential_path() / "cookies";
1358+
curl_easy_setopt(curl.get(), CURLOPT_COOKIEFILE, cookie_file.c_str());
13331359
}
13341360
}
13351361

@@ -1521,6 +1547,71 @@ struct llama_model * common_load_model_from_hf(
15211547
return common_load_model_from_url(model_url, local_path, hf_token, params);
15221548
}
15231549

1550+
bool ms_login(const std::string & token) {
1551+
if (token.empty()) {
1552+
return false;
1553+
}
1554+
1555+
auto credentials_path = create_credential_path();
1556+
1557+
const std::filesystem::path user_file = credentials_path / "user";
1558+
const std::filesystem::path git_token_file = credentials_path / "git_token";
1559+
const std::filesystem::path cookie_file = credentials_path / "cookies";
1560+
std::string url = MODELSCOPE_DOMAIN_DEFINITION + "/api/v1/login";
1561+
json request_body;
1562+
request_body["AccessToken"] = token;
1563+
std::string request_body_str = request_body.dump();
1564+
1565+
curl_ptr curl(curl_easy_init(), &curl_easy_cleanup);
1566+
std::string response_string;
1567+
struct curl_slist* headers = nullptr;
1568+
headers = curl_slist_append(headers, "User-Agent: llama-cpp");
1569+
headers = curl_slist_append(headers, "Content-Type: application/json");
1570+
1571+
auto save_to_file = [](const std::string& filename, const std::string& data) {
1572+
std::ofstream ofs(filename, std::ios::binary);
1573+
if (!ofs) {
1574+
throw std::runtime_error("Cannot write to: " + filename);
1575+
}
1576+
ofs << data;
1577+
ofs.close();
1578+
};
1579+
1580+
curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str());
1581+
curl_easy_setopt(curl.get(), CURLOPT_POST, 1L);
1582+
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, request_body_str.c_str());
1583+
curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDSIZE, request_body_str.size());
1584+
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headers);
1585+
typedef size_t(*CURLOPT_WRITEFUNCTION_PTR)(void * ptr, size_t size, size_t nmemb, void * data);
1586+
auto write_callback = [](void * ptr, size_t size, size_t nmemb, void * data) -> size_t {
1587+
static_cast<std::string *>(data)->append((char * ) ptr, size * nmemb);
1588+
return size * nmemb;
1589+
};
1590+
curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, static_cast<CURLOPT_WRITEFUNCTION_PTR>(write_callback));
1591+
curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response_string);
1592+
curl_easy_setopt(curl.get(), CURLOPT_COOKIEJAR, cookie_file.c_str());
1593+
curl_easy_setopt(curl.get(), CURLOPT_COOKIEFILE, cookie_file.c_str());
1594+
1595+
if (CURLcode res = curl_easy_perform(curl.get()); res != CURLE_OK) {
1596+
curl_slist_free_all(headers);
1597+
return false;
1598+
}
1599+
1600+
long http_code = 0;
1601+
curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &http_code);
1602+
if (http_code != 200) {
1603+
return false;
1604+
}
1605+
1606+
curl_slist_free_all(headers);
1607+
json response_json = json::parse(response_string);
1608+
json data = response_json["Data"];
1609+
auto access_token = data["AccessToken"].get<std::string>();
1610+
save_to_file(git_token_file.c_str(), access_token);
1611+
save_to_file(user_file.c_str(), data["Username"].get<std::string>() + ":" + data["Email"].get<std::string>());
1612+
return true;
1613+
}
1614+
15241615
struct llama_model * common_load_model_from_ms(
15251616
const std::string & repo,
15261617
const std::string & remote_path,
@@ -1531,7 +1622,9 @@ struct llama_model * common_load_model_from_ms(
15311622
model_url += repo;
15321623
model_url += "/resolve/master/";
15331624
model_url += remote_path;
1534-
// modelscope does not support token in header
1625+
if (!ms_token.empty()) {
1626+
ms_login(ms_token);
1627+
}
15351628
return common_load_model_from_url(model_url, local_path, "", params);
15361629
}
15371630

@@ -1616,6 +1709,9 @@ std::pair<std::string, std::string> common_get_ms_file(const std::string & ms_re
16161709
if (string_split<std::string>(hf_repo, '/').size() != 2) {
16171710
throw std::invalid_argument("error: invalid HF repo format, expected <user>/<model>[:quant]\n");
16181711
}
1712+
if (!ms_token.empty()) {
1713+
ms_login(ms_token);
1714+
}
16191715

16201716
// fetch model info from Hugging Face Hub API
16211717
json model_info;
@@ -1642,6 +1738,9 @@ std::pair<std::string, std::string> common_get_ms_file(const std::string & ms_re
16421738
http_headers.ptr = curl_slist_append(http_headers.ptr, "Accept: application/json");
16431739
curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, http_headers.ptr);
16441740

1741+
const std::filesystem::path cookie_file = create_credential_path() / "cookies";
1742+
curl_easy_setopt(curl.get(), CURLOPT_COOKIEFILE, cookie_file.c_str());
1743+
16451744
CURLcode res = curl_easy_perform(curl.get());
16461745

16471746
if (res != CURLE_OK) {

common/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ std::pair<std::string, std::string> common_get_hf_file(
590590
const std::string & hf_repo_with_tag,
591591
const std::string & hf_token);
592592

593+
bool ms_login(const std::string & token);
594+
593595
std::pair<std::string, std::string> common_get_ms_file(
594596
const std::string & ms_repo_with_tag,
595597
const std::string & ms_token);

0 commit comments

Comments
 (0)