Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit 082635e

Browse files
committed
fix: update download api
1 parent fcee871 commit 082635e

File tree

12 files changed

+268
-117
lines changed

12 files changed

+268
-117
lines changed

docs/static/openapi/jan.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,15 @@
16511651
"value": "https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.1-GGUF/blob/main/mistral-7b-instruct-v0.1.Q2_K.gguf"
16521652
}
16531653
]
1654+
},
1655+
"id": {
1656+
"type": "string",
1657+
"description": "The id which will be used to register the model.",
1658+
"examples": [
1659+
{
1660+
"value": "my-custom-model-id"
1661+
}
1662+
]
16541663
}
16551664
}
16561665
},

engine/cli/commands/model_list_cmd.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ using namespace tabulate;
1717
using Row_t =
1818
std::vector<variant<std::string, const char*, string_view, Table>>;
1919

20-
void ModelListCmd::Exec(const std::string& host, int port, std::string filter,
21-
bool display_engine, bool display_version) {
20+
void ModelListCmd::Exec(const std::string& host, int port,
21+
const std::string& filter, bool display_engine,
22+
bool display_version) {
2223
// Start server if server is not started yet
2324
if (!commands::IsServerAlive(host, port)) {
2425
CLI_LOG("Starting server ...");

engine/cli/commands/model_list_cmd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace commands {
66

77
class ModelListCmd {
88
public:
9-
void Exec(const std::string& host, int port, std::string filter,
9+
void Exec(const std::string& host, int port, const std::string& filter,
1010
bool display_engine = false, bool display_version = false);
1111
};
1212
} // namespace commands

engine/common/download_task.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
#include <string>
88

99
enum class DownloadType { Model, Engine, Miscellaneous, CudaToolkit, Cortex };
10+
1011
using namespace nlohmann;
1112

1213
struct DownloadItem {
14+
1315
std::string id;
1416

1517
std::string downloadUrl;
@@ -54,8 +56,12 @@ inline std::string DownloadTypeToString(DownloadType type) {
5456
}
5557

5658
struct DownloadTask {
59+
enum class Status { Pending, InProgress, Completed, Cancelled, Error };
60+
5761
std::string id;
5862

63+
Status status;
64+
5965
DownloadType type;
6066

6167
std::vector<DownloadItem> items;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#include <condition_variable>
2+
#include <deque>
3+
#include <mutex>
4+
#include <optional>
5+
#include <shared_mutex>
6+
#include <string>
7+
#include <unordered_map>
8+
#include "common/download_task.h"
9+
10+
class DownloadTaskQueue {
11+
private:
12+
std::deque<DownloadTask> taskQueue;
13+
std::unordered_map<std::string, typename std::deque<DownloadTask>::iterator>
14+
taskMap;
15+
mutable std::shared_mutex mutex;
16+
std::condition_variable_any cv;
17+
18+
public:
19+
void push(DownloadTask task) {
20+
std::unique_lock lock(mutex);
21+
taskQueue.push_back(std::move(task));
22+
taskMap[taskQueue.back().id] = std::prev(taskQueue.end());
23+
cv.notify_one();
24+
}
25+
26+
std::optional<DownloadTask> pop() {
27+
std::unique_lock lock(mutex);
28+
if (taskQueue.empty()) {
29+
return std::nullopt;
30+
}
31+
DownloadTask task = std::move(taskQueue.front());
32+
taskQueue.pop_front();
33+
taskMap.erase(task.id);
34+
return task;
35+
}
36+
37+
bool cancelTask(const std::string& taskId) {
38+
std::unique_lock lock(mutex);
39+
auto it = taskMap.find(taskId);
40+
if (it != taskMap.end()) {
41+
it->second->status = DownloadTask::Status::Cancelled;
42+
taskQueue.erase(it->second);
43+
taskMap.erase(it);
44+
return true;
45+
}
46+
return false;
47+
}
48+
49+
bool updateTaskStatus(const std::string& taskId,
50+
DownloadTask::Status newStatus) {
51+
std::unique_lock lock(mutex);
52+
auto it = taskMap.find(taskId);
53+
if (it != taskMap.end()) {
54+
it->second->status = newStatus;
55+
if (newStatus == DownloadTask::Status::Cancelled ||
56+
newStatus == DownloadTask::Status::Error) {
57+
taskQueue.erase(it->second);
58+
taskMap.erase(it);
59+
}
60+
return true;
61+
}
62+
return false;
63+
}
64+
65+
std::optional<DownloadTask> getNextPendingTask() {
66+
std::shared_lock lock(mutex);
67+
auto it = std::find_if(
68+
taskQueue.begin(), taskQueue.end(), [](const DownloadTask& task) {
69+
return task.status == DownloadTask::Status::Pending;
70+
});
71+
72+
if (it != taskQueue.end()) {
73+
return *it;
74+
}
75+
return std::nullopt;
76+
}
77+
};

engine/controllers/models.cc

Lines changed: 10 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "database/models.h"
22
#include <drogon/HttpTypes.h>
3+
#include <optional>
34
#include "config/gguf_parser.h"
45
#include "config/yaml_config.h"
56
#include "models.h"
@@ -26,15 +27,22 @@ void Models::PullModel(const HttpRequestPtr& req,
2627
return;
2728
}
2829

30+
std::optional<std::string> desired_model_id = std::nullopt;
31+
auto id = (*(req->getJsonObject())).get("id", "").asString();
32+
if (!id.empty()) {
33+
desired_model_id = id;
34+
}
35+
2936
auto handle_model_input =
3037
[&, model_handle]() -> cpp::result<DownloadTask, std::string> {
3138
CTL_INF("Handle model input, model handle: " + model_handle);
3239
if (string_utils::StartsWith(model_handle, "https")) {
33-
return model_service_->HandleDownloadUrlAsync(model_handle);
40+
return model_service_->HandleDownloadUrlAsync(model_handle,
41+
desired_model_id);
3442
} else if (model_handle.find(":") != std::string::npos) {
3543
auto model_and_branch = string_utils::SplitBy(model_handle, ":");
3644
return model_service_->DownloadModelFromCortexsoAsync(
37-
model_and_branch[0], model_and_branch[1]);
45+
model_and_branch[0], model_and_branch[1], desired_model_id);
3846
}
3947

4048
return cpp::fail("Invalid model handle or not supported!");
@@ -107,7 +115,6 @@ void Models::ListModel(
107115
auto list_entry = modellist_handler.LoadModelList();
108116
if (list_entry) {
109117
for (const auto& model_entry : list_entry.value()) {
110-
// auto model_entry = modellist_handler.GetModelInfo(model_handle);
111118
try {
112119
yaml_handler.ModelConfigFromFile(
113120
fmu::ToAbsoluteCortexDataPath(
@@ -116,7 +123,6 @@ void Models::ListModel(
116123
auto model_config = yaml_handler.GetModelConfig();
117124
Json::Value obj = model_config.ToJson();
118125
obj["id"] = model_entry.model;
119-
obj["model_alias"] = model_entry.model_alias;
120126
obj["model"] = model_entry.model;
121127
data.append(std::move(obj));
122128
yaml_handler.Reset();
@@ -333,71 +339,6 @@ void Models::ImportModel(
333339
}
334340
}
335341

336-
void Models::SetModelAlias(
337-
const HttpRequestPtr& req,
338-
std::function<void(const HttpResponsePtr&)>&& callback) const {
339-
if (!http_util::HasFieldInReq(req, callback, "model") ||
340-
!http_util::HasFieldInReq(req, callback, "modelAlias")) {
341-
return;
342-
}
343-
auto model_handle = (*(req->getJsonObject())).get("model", "").asString();
344-
auto model_alias = (*(req->getJsonObject())).get("modelAlias", "").asString();
345-
LOG_DEBUG << "GetModel, Model handle: " << model_handle
346-
<< ", Model alias: " << model_alias;
347-
348-
cortex::db::Models modellist_handler;
349-
try {
350-
auto result = modellist_handler.UpdateModelAlias(model_handle, model_alias);
351-
if (result.has_error()) {
352-
std::string message = result.error();
353-
LOG_ERROR << message;
354-
Json::Value ret;
355-
ret["result"] = "Set alias failed!";
356-
ret["modelHandle"] = model_handle;
357-
ret["message"] = message;
358-
auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
359-
resp->setStatusCode(k400BadRequest);
360-
callback(resp);
361-
} else {
362-
if (result.value()) {
363-
std::string message = "Successfully set model alias '" + model_alias +
364-
"' for modeID '" + model_handle + "'.";
365-
LOG_INFO << message;
366-
Json::Value ret;
367-
ret["result"] = "OK";
368-
ret["modelHandle"] = model_handle;
369-
ret["message"] = message;
370-
auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
371-
resp->setStatusCode(k200OK);
372-
callback(resp);
373-
} else {
374-
std::string message = "Unable to set model alias for modelID '" +
375-
model_handle + "': model alias '" + model_alias +
376-
"' is not unique!";
377-
LOG_ERROR << message;
378-
Json::Value ret;
379-
ret["result"] = "Set alias failed!";
380-
ret["modelHandle"] = model_handle;
381-
ret["message"] = message;
382-
auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
383-
resp->setStatusCode(k400BadRequest);
384-
callback(resp);
385-
}
386-
}
387-
} catch (const std::exception& e) {
388-
std::string message = "Error when setting model alias ('" + model_alias +
389-
"') for modelID '" + model_handle + "':" + e.what();
390-
LOG_ERROR << message;
391-
Json::Value ret;
392-
ret["result"] = "Set alias failed!";
393-
ret["modelHandle"] = model_handle;
394-
ret["message"] = message;
395-
auto resp = cortex_utils::CreateCortexHttpJsonResponse(ret);
396-
resp->setStatusCode(k400BadRequest);
397-
callback(resp);
398-
}
399-
}
400-
401342
void Models::StartModel(
402343
const HttpRequestPtr& req,
403344
std::function<void(const HttpResponsePtr&)>&& callback) {

engine/controllers/models.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ class Models : public drogon::HttpController<Models, false> {
1616
METHOD_ADD(Models::UpdateModel, "/{1}", Patch);
1717
METHOD_ADD(Models::ImportModel, "/import", Post);
1818
METHOD_ADD(Models::DeleteModel, "/{1}", Delete);
19-
METHOD_ADD(Models::SetModelAlias, "/alias", Post);
2019
METHOD_ADD(Models::StartModel, "/start", Post);
2120
METHOD_ADD(Models::StopModel, "/stop", Post);
2221
METHOD_ADD(Models::GetModelStatus, "/status/{1}", Get);
@@ -28,7 +27,6 @@ class Models : public drogon::HttpController<Models, false> {
2827
ADD_METHOD_TO(Models::UpdateModel, "/v1/models/{1}", Patch);
2928
ADD_METHOD_TO(Models::ImportModel, "/v1/models/import", Post);
3029
ADD_METHOD_TO(Models::DeleteModel, "/v1/models/{1}", Delete);
31-
ADD_METHOD_TO(Models::SetModelAlias, "/v1/models/alias", Post);
3230
ADD_METHOD_TO(Models::StartModel, "/v1/models/start", Post);
3331
ADD_METHOD_TO(Models::StopModel, "/v1/models/stop", Post);
3432
ADD_METHOD_TO(Models::GetModelStatus, "/v1/models/status/{1}", Get);

engine/e2e-test/test_api_model_alias.py

Lines changed: 0 additions & 24 deletions
This file was deleted.

engine/e2e-test/test_api_model_start.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ def setup_and_teardown(self):
1212
success = start_server()
1313
if not success:
1414
raise Exception("Failed to start server")
15-
16-
# TODO: using pull with branch for easy testing tinyllama:gguf for example
15+
run("Install Engine", ["engines", "install", "llama-cpp"], timeout=None)
1716
run("Delete model", ["models", "delete", "tinyllama:gguf"])
1817
run("Pull model", ["pull", "tinyllama:gguf"], timeout=None,)
1918

0 commit comments

Comments
 (0)