|
1 | 1 | #include "model_service.h"
|
2 | 2 | #include <filesystem>
|
3 | 3 | #include <iostream>
|
| 4 | +#include <ostream> |
4 | 5 | #include "commands/cmd_info.h"
|
5 | 6 | #include "utils/cortexso_parser.h"
|
6 | 7 | #include "utils/file_manager_utils.h"
|
| 8 | +#include "utils/huggingface_utils.h" |
7 | 9 | #include "utils/logging_utils.h"
|
8 | 10 | #include "utils/model_callback_utils.h"
|
9 |
| -#include "utils/url_parser.h" |
| 11 | + |
| 12 | +void PrintMenu(const std::vector<std::string>& options) { |
| 13 | + auto index{1}; |
| 14 | + for (const auto& option : options) { |
| 15 | + std::cout << index << ". " << option << "\n"; |
| 16 | + index++; |
| 17 | + } |
| 18 | + std::endl(std::cout); |
| 19 | +} |
| 20 | + |
| 21 | +std::optional<std::string> PrintSelection( |
| 22 | + const std::vector<std::string>& options) { |
| 23 | + std::string selection{""}; |
| 24 | + PrintMenu(options); |
| 25 | + std::cin >> selection; |
| 26 | + |
| 27 | + if (selection.empty()) { |
| 28 | + return std::nullopt; |
| 29 | + } |
| 30 | + |
| 31 | + // std::cout << "Selection: " << selection << "\n"; |
| 32 | + // std::cout << "Int representaion: " << std::stoi(selection) << "\n"; |
| 33 | + if (std::stoi(selection) > options.size() || std::stoi(selection) < 1) { |
| 34 | + return std::nullopt; |
| 35 | + } |
| 36 | + |
| 37 | + return options[std::stoi(selection) - 1]; |
| 38 | +} |
10 | 39 |
|
11 | 40 | void ModelService::DownloadModel(const std::string& input) {
|
12 | 41 | if (input.empty()) {
|
13 | 42 | throw std::runtime_error(
|
14 | 43 | "Input must be Cortex Model Hub handle or HuggingFace url!");
|
15 | 44 | }
|
16 | 45 |
|
17 |
| - // case input is a direct url |
18 |
| - auto url_obj = url_parser::FromUrlString(input); |
19 |
| - // TODO: handle case user paste url from cortexso |
20 |
| - if (url_obj.protocol == "https") { |
21 |
| - if (url_obj.host != kHuggingFaceHost) { |
22 |
| - CLI_LOG("Only huggingface.co is supported for now"); |
| 46 | + if (input.starts_with("https://")) { |
| 47 | + return DownloadModelByDirectUrl(input); |
| 48 | + } |
| 49 | + |
| 50 | + // if input contains / then handle it differently |
| 51 | + if (input.find("/") != std::string::npos) { |
| 52 | + // TODO: what if we have more than one /? |
| 53 | + // TODO: what if the left size of / is cortexso? |
| 54 | + |
| 55 | + // split by /. TODO: Move this function to somewhere else |
| 56 | + std::string model_input = input; |
| 57 | + std::string delimiter{"/"}; |
| 58 | + std::string token{""}; |
| 59 | + std::vector<std::string> parsed{}; |
| 60 | + std::string author{""}; |
| 61 | + std::string model_name{""}; |
| 62 | + while (token != model_input) { |
| 63 | + token = model_input.substr(0, model_input.find_first_of("/")); |
| 64 | + model_input = model_input.substr(model_input.find_first_of("/") + 1); |
| 65 | + std::string new_str{token}; |
| 66 | + parsed.push_back(new_str); |
| 67 | + } |
| 68 | + |
| 69 | + author = parsed[0]; |
| 70 | + model_name = parsed[1]; |
| 71 | + auto repo_info = |
| 72 | + huggingface_utils::GetHuggingFaceModelRepoInfo(author, model_name); |
| 73 | + if (!repo_info.has_value()) { |
| 74 | + // throw is better? |
| 75 | + CTL_ERR("Model not found"); |
23 | 76 | return;
|
24 | 77 | }
|
25 |
| - return DownloadModelByDirectUrl(input); |
26 |
| - } else { |
27 |
| - commands::CmdInfo ci(input); |
28 |
| - return DownloadModelFromCortexso(ci.model_name, ci.branch); |
| 78 | + |
| 79 | + if (!repo_info->gguf.has_value()) { |
| 80 | + throw std::runtime_error( |
| 81 | + "Not a GGUF model. Currently, only GGUF single file is supported."); |
| 82 | + } |
| 83 | + |
| 84 | + std::vector<std::string> options{}; |
| 85 | + for (const auto& sibling : repo_info->siblings) { |
| 86 | + if (sibling.rfilename.ends_with(".gguf")) { |
| 87 | + options.push_back(sibling.rfilename); |
| 88 | + } |
| 89 | + } |
| 90 | + auto selection = PrintSelection(options); |
| 91 | + std::cout << "Selected: " << selection.value() << std::endl; |
| 92 | + |
| 93 | + auto download_url = huggingface_utils::GetDownloadableUrl( |
| 94 | + author, model_name, selection.value()); |
| 95 | + |
| 96 | + std::cout << "Download url: " << download_url << std::endl; |
| 97 | + // TODO: split to this function |
| 98 | + // DownloadHuggingFaceGgufModel(author, model_name, nullptr); |
| 99 | + return; |
29 | 100 | }
|
| 101 | + |
| 102 | + // user just input a text, seems like a model name only, maybe comes with a branch, using : as delimeter |
| 103 | + // handle cortexso here |
| 104 | + // separate into another function and the above can route to it if we regconize a cortexso url |
30 | 105 | }
|
31 | 106 |
|
32 | 107 | std::optional<config::ModelConfig> ModelService::GetDownloadedModel(
|
@@ -114,3 +189,23 @@ void ModelService::DownloadModelFromCortexso(const std::string& name,
|
114 | 189 | CTL_ERR("Model not found");
|
115 | 190 | }
|
116 | 191 | }
|
| 192 | + |
| 193 | +void ModelService::DownloadHuggingFaceGgufModel( |
| 194 | + const std::string& author, const std::string& modelName, |
| 195 | + std::optional<std::string> fileName) { |
| 196 | + std::cout << author << std::endl; |
| 197 | + std::cout << modelName << std::endl; |
| 198 | + // if we don't have file name, we must display a list for user to pick |
| 199 | + // auto repo_info = |
| 200 | + // huggingface_utils::GetHuggingFaceModelRepoInfo(author, modelName); |
| 201 | + // |
| 202 | + // if (!repo_info.has_value()) { |
| 203 | + // // throw is better? |
| 204 | + // CTL_ERR("Model not found"); |
| 205 | + // return; |
| 206 | + // } |
| 207 | + // |
| 208 | + // for (const auto& sibling : repo_info->siblings) { |
| 209 | + // std::cout << sibling.rfilename << "\n"; |
| 210 | + // } |
| 211 | +} |
0 commit comments