Skip to content

Commit 3cc5c17

Browse files
authored
Merge pull request #2028 from janhq/s/chore/sync-dev-to-main
chore: sync dev to main
2 parents 23a4b7d + cbca628 commit 3cc5c17

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+936
-367
lines changed

.github/workflows/cortex-cpp-quality-gate.yml

+8-8
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ jobs:
168168
cp build/cortex build/cortex-beta
169169
python -m pip install --upgrade pip
170170
python -m pip install -r e2e-test/requirements.txt
171-
python e2e-test/main.py
171+
python e2e-test/runner/main.py
172172
rm build/cortex-nightly
173173
rm build/cortex-beta
174174
env:
@@ -182,7 +182,7 @@ jobs:
182182
cp build/cortex.exe build/cortex-beta.exe
183183
python -m pip install --upgrade pip
184184
python -m pip install -r e2e-test/requirements.txt
185-
python e2e-test/main.py
185+
python e2e-test/runner/main.py
186186
rm build/cortex-nightly.exe
187187
rm build/cortex-beta.exe
188188
env:
@@ -196,7 +196,7 @@ jobs:
196196
cp build/cortex build/cortex-beta
197197
python -m pip install --upgrade pip
198198
python -m pip install -r e2e-test/requirements.txt
199-
python e2e-test/cortex-llamacpp-e2e-nightly.py
199+
python e2e-test/runner/cortex-llamacpp-e2e-nightly.py
200200
rm build/cortex-nightly
201201
rm build/cortex-beta
202202
env:
@@ -210,7 +210,7 @@ jobs:
210210
cp build/cortex.exe build/cortex-beta.exe
211211
python -m pip install --upgrade pip
212212
python -m pip install -r e2e-test/requirements.txt
213-
python e2e-test/cortex-llamacpp-e2e-nightly.py
213+
python e2e-test/runner/cortex-llamacpp-e2e-nightly.py
214214
rm build/cortex-nightly.exe
215215
rm build/cortex-beta.exe
216216
env:
@@ -443,7 +443,7 @@ jobs:
443443
cp build/cortex build/cortex-beta
444444
python -m pip install --upgrade pip
445445
python -m pip install -r e2e-test/requirements.txt
446-
python e2e-test/main.py
446+
python e2e-test/runner/main.py
447447
rm build/cortex-nightly
448448
rm build/cortex-beta
449449
env:
@@ -457,7 +457,7 @@ jobs:
457457
cp build/cortex.exe build/cortex-beta.exe
458458
python -m pip install --upgrade pip
459459
python -m pip install -r e2e-test/requirements.txt
460-
python e2e-test/main.py
460+
python e2e-test/runner/main.py
461461
rm build/cortex-nightly.exe
462462
rm build/cortex-beta.exe
463463
env:
@@ -471,7 +471,7 @@ jobs:
471471
cp build/cortex build/cortex-beta
472472
python -m pip install --upgrade pip
473473
python -m pip install -r e2e-test/requirements.txt
474-
python e2e-test/cortex-llamacpp-e2e-nightly.py
474+
python e2e-test/runner/cortex-llamacpp-e2e-nightly.py
475475
rm build/cortex-nightly
476476
rm build/cortex-beta
477477
env:
@@ -485,7 +485,7 @@ jobs:
485485
cp build/cortex.exe build/cortex-beta.exe
486486
python -m pip install --upgrade pip
487487
python -m pip install -r e2e-test/requirements.txt
488-
python e2e-test/cortex-llamacpp-e2e-nightly.py
488+
python e2e-test/runner/cortex-llamacpp-e2e-nightly.py
489489
rm build/cortex-nightly.exe
490490
rm build/cortex-beta.exe
491491
env:

docs/static/openapi/cortex.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -5356,7 +5356,7 @@
53565356
"type": "string",
53575357
"description": "The identifier or URL of the model to use. It can be a model ID on Cortexso (https://huggingface.co/cortexso) or a HuggingFace URL pointing to the model file. For example: 'gpt2' or 'https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.1-GGUF/blob/main/mistral-7b-instruct-v0.1.Q2_K.gguf'",
53585358
"examples": [
5359-
"tinyllama:gguf",
5359+
"tinyllama:1b",
53605360
"https://huggingface.co/TheBloke/Mistral-7B-Instruct-v0.1-GGUF/blob/main/mistral-7b-instruct-v0.1.Q2_K.gguf"
53615361
]
53625362
},

engine/common/download_task_queue.h

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include <algorithm>
12
#include <condition_variable>
23
#include <deque>
34
#include <mutex>

engine/controllers/models.cc

+7-2
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,10 @@ void Models::UpdateModel(const HttpRequestPtr& req,
385385
message = "Successfully update model ID '" + model_id +
386386
"': " + json_body.toStyledString();
387387
} else if (model_config.engine == kPythonEngine) {
388+
// Block changes to `command`
389+
if (json_body.isMember("command")) {
390+
json_body.removeMember("command");
391+
}
388392
config::PythonModelConfig python_model_config;
389393
python_model_config.ReadFromYaml(yaml_fp.string());
390394
python_model_config.FromJson(json_body);
@@ -859,10 +863,11 @@ void Models::GetModelSource(
859863
void Models::GetRepositoryList(
860864
const HttpRequestPtr& req,
861865
std::function<void(const HttpResponsePtr&)>&& callback,
862-
std::optional<std::string> author) {
866+
std::optional<std::string> author, std::optional<std::string> tag) {
863867
if (!author.has_value())
864868
author = "cortexso";
865-
auto res = model_src_svc_->GetRepositoryList(author.value());
869+
auto res =
870+
model_src_svc_->GetRepositoryList(author.value(), tag.value_or(""));
866871
if (res.has_error()) {
867872
Json::Value ret;
868873
ret["message"] = res.error();

engine/controllers/models.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class Models : public drogon::HttpController<Models, false> {
4444
ADD_METHOD_TO(Models::DeleteModelSource, "/v1/models/sources", Delete);
4545
ADD_METHOD_TO(Models::GetModelSources, "/v1/models/sources", Get);
4646
ADD_METHOD_TO(Models::GetModelSource, "/v1/models/sources/{src}", Get);
47-
ADD_METHOD_TO(Models::GetRepositoryList, "/v1/models/hub?author={author}",
48-
Get);
47+
ADD_METHOD_TO(Models::GetRepositoryList,
48+
"/v1/models/hub?author={author}&tag={tag}", Get);
4949
METHOD_LIST_END
5050

5151
explicit Models(std::shared_ptr<DatabaseService> db_service,
@@ -115,7 +115,8 @@ class Models : public drogon::HttpController<Models, false> {
115115

116116
void GetRepositoryList(const HttpRequestPtr& req,
117117
std::function<void(const HttpResponsePtr&)>&& callback,
118-
std::optional<std::string> author);
118+
std::optional<std::string> author,
119+
std::optional<std::string> tag);
119120

120121
private:
121122
std::shared_ptr<DatabaseService> db_service_;

engine/e2e-test/test_api_engine.py engine/e2e-test/api/engines/test_api_engine.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import pytest
22
import requests
33
import time
4-
from test_runner import (
4+
from utils.test_runner import (
55
start_server,
66
stop_server,
77
wait_for_websocket_download_success_event,

engine/e2e-test/test_api_engine_install_nightly.py engine/e2e-test/api/engines/test_api_engine_install_nightly.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22
import requests
3-
from test_runner import start_server, stop_server, get_latest_pre_release_tag
3+
from utils.test_runner import start_server, stop_server, get_latest_pre_release_tag
44

55
latest_pre_release_tag = get_latest_pre_release_tag("janhq", "cortex.llamacpp")
66

engine/e2e-test/test_api_engine_update.py engine/e2e-test/api/engines/test_api_engine_update.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22
import requests
3-
from test_runner import (
3+
from utils.test_runner import (
44
start_server,
55
stop_server,
66
wait_for_websocket_download_success_event,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import pytest
2+
import requests
3+
from utils.test_runner import start_server, stop_server
4+
import jsonschema
5+
from tenacity import retry, wait_exponential, stop_after_attempt
6+
from utils.logger import log_response
7+
from utils.assertion import assert_equal
8+
9+
10+
class TestApiDefaultEngine:
11+
12+
@pytest.fixture(autouse=True)
13+
def setup_and_teardown(self):
14+
# Setup
15+
success = start_server()
16+
if not success:
17+
raise Exception("Failed to start server")
18+
19+
yield
20+
21+
# Teardown
22+
stop_server()
23+
24+
def test_api_get_default_engine_successfully(self):
25+
# Data test
26+
engine= "llama-cpp"
27+
name= "linux-amd64-avx-cuda-11-7"
28+
version= "v0.1.35-27.10.24"
29+
30+
data = {"version": version, "variant": name}
31+
post_install_url = f"http://localhost:3928/v1/engines/{engine}/install"
32+
response = requests.post(
33+
post_install_url, json=data
34+
)
35+
assert_equal(response.status_code,200)
36+
log_response(response.json(), "test_api_get_default_engine_successfully")
37+
38+
get_list_url = f"http://localhost:3928/v1/engines/{engine}"
39+
get_default_url = f"http://localhost:3928/v1/engines/{engine}/default"
40+
41+
@retry(
42+
wait=wait_exponential(multiplier=2, min=2, max=30),
43+
stop=stop_after_attempt(5)
44+
)
45+
def get_request(url):
46+
response = requests.get(url)
47+
assert len(response.json()) > 0
48+
49+
get_request(get_list_url)
50+
51+
response_default_engine = requests.get(get_default_url)
52+
json_data = response_default_engine.json()
53+
54+
log_response(json_data, "test_api_get_default_engine_successfully")
55+
assert_equal(response_default_engine.status_code, 200)
56+
57+
schema = {
58+
"type": "object",
59+
"properties": {
60+
"engine": {"type": "string"},
61+
"variant": {"type": "string"},
62+
"version": {"type": "string"}
63+
},
64+
"required": ["engine", "variant", "version"]
65+
}
66+
67+
# Validate response schema
68+
jsonschema.validate(instance=json_data, schema=schema)
69+
70+
def test_api_get_default_engine_failed_invalid_engine(self):
71+
# Data test
72+
engine= "invalid"
73+
74+
get_default_url = f"http://localhost:3928/v1/engines/{engine}/default"
75+
76+
response_default_engine = requests.get(get_default_url)
77+
json_data_get_default = response_default_engine.json()
78+
79+
log_response(json_data_get_default, "test_api_get_default_engine_failed_invalid_engine")
80+
assert_equal(response_default_engine.status_code, 400)
81+
82+
assert_equal(json_data_get_default["message"], f"Engine {engine} is not supported yet!")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import pytest
2+
import requests
3+
from utils.test_runner import start_server, stop_server
4+
import jsonschema
5+
from tenacity import retry, wait_exponential, stop_after_attempt
6+
from utils.logger import log_response
7+
from utils.assertion import assert_equal, assert_contains
8+
9+
10+
class TestApiEngineRelease:
11+
12+
@pytest.fixture(autouse=True)
13+
def setup_and_teardown(self):
14+
# Setup
15+
success = start_server()
16+
if not success:
17+
raise Exception("Failed to start server")
18+
19+
yield
20+
21+
# Teardown
22+
stop_server()
23+
24+
def test_api_get_engine_release_successfully(self):
25+
# Data test
26+
engine= "llama-cpp"
27+
get_release_url = f"http://localhost:3928/v1/engines/{engine}/releases"
28+
29+
@retry(
30+
wait=wait_exponential(multiplier=2, min=2, max=30),
31+
stop=stop_after_attempt(5)
32+
)
33+
def get_request(url):
34+
response = requests.get(url)
35+
assert len(response.json()) > 0
36+
37+
get_request(get_release_url)
38+
39+
response_engine_release = requests.get(get_release_url)
40+
json_data = response_engine_release.json()
41+
42+
log_response(json_data, "test_api_get_engine_release_successfully")
43+
assert_equal(response_engine_release.status_code, 200)
44+
45+
schema = {
46+
"$schema": "http://json-schema.org/draft-07/schema#",
47+
"type": "array",
48+
"items": {
49+
"type": "object",
50+
"properties": {
51+
"draft": { "type": "boolean" },
52+
"name": { "type": "string" },
53+
"prerelease": { "type": "boolean" },
54+
"published_at": { "type": "string", "format": "date-time" },
55+
"url": { "type": "string", "format": "uri" }
56+
},
57+
"required": ["draft", "name", "prerelease", "published_at", "url"]
58+
}
59+
}
60+
61+
# Validate response schema
62+
jsonschema.validate(instance=json_data, schema=schema)
63+
64+
def test_api_ge_engine_release_failed_invalid_engine(self):
65+
# Data test
66+
engine= "invalid"
67+
68+
get_default_url = f"http://localhost:3928/v1/engines/{engine}/releases"
69+
70+
response_default_engine = requests.get(get_default_url)
71+
json_data_get_default = response_default_engine.json()
72+
73+
log_response(json_data_get_default, "test_api_ge_engine_release_failed_invalid_engine")
74+
assert_equal(response_default_engine.status_code, 400)
75+
76+
assert_contains(json_data_get_default["message"], "Not Found")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import pytest
2+
import requests
3+
from utils.test_runner import start_server, stop_server
4+
import jsonschema
5+
from tenacity import retry, wait_exponential, stop_after_attempt
6+
from utils.logger import log_response
7+
from utils.assertion import assert_equal, assert_contains
8+
9+
10+
class TestApiEngineReleaseLatest:
11+
12+
@pytest.fixture(autouse=True)
13+
def setup_and_teardown(self):
14+
# Setup
15+
success = start_server()
16+
if not success:
17+
raise Exception("Failed to start server")
18+
19+
yield
20+
21+
# Teardown
22+
stop_server()
23+
24+
def test_api_get_engine_release_latest_successfully(self):
25+
# Data test
26+
engine= "llama-cpp"
27+
get_release_url = f"http://localhost:3928/v1/engines/{engine}/releases/latest"
28+
29+
@retry(
30+
wait=wait_exponential(multiplier=2, min=2, max=30),
31+
stop=stop_after_attempt(5)
32+
)
33+
def get_request(url):
34+
response = requests.get(url)
35+
assert len(response.json()) > 0
36+
37+
get_request(get_release_url)
38+
39+
response_engine_release = requests.get(get_release_url)
40+
json_data = response_engine_release.json()
41+
42+
log_response(json_data, "test_api_get_engine_release_latest_successfully")
43+
assert_equal(response_engine_release.status_code, 200)
44+
45+
schema = {
46+
"$schema": "https://json-schema.org/draft/2020-12/schema",
47+
"type": "array",
48+
"items": {
49+
"type": "object",
50+
"properties": {
51+
"created_at": {
52+
"type": "string",
53+
"format": "date-time"
54+
},
55+
"download_count": {
56+
"type": "integer",
57+
"minimum": 0
58+
},
59+
"name": {
60+
"type": "string"
61+
},
62+
"size": {
63+
"type": "integer",
64+
"minimum": 0
65+
}
66+
},
67+
"required": ["created_at", "download_count", "name", "size"]
68+
}
69+
}
70+
71+
72+
# Validate response schema
73+
jsonschema.validate(instance=json_data, schema=schema)

0 commit comments

Comments
 (0)