Skip to content

Commit

Permalink
Merge branch 'dev' of https://github.com/janhq/cortex into feat/amd
Browse files Browse the repository at this point in the history
  • Loading branch information
sangjanai committed Dec 18, 2024
2 parents 5d270af + b0b8bec commit 72aa7a7
Show file tree
Hide file tree
Showing 30 changed files with 528 additions and 453 deletions.
51 changes: 28 additions & 23 deletions docs/static/openapi/cortex.json
Original file line number Diff line number Diff line change
Expand Up @@ -2522,26 +2522,31 @@
"default": "llama-cpp"
},
"description": "The type of engine"
},
{
"name": "version",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "The version of the engine variant"
},
{
"name": "variant",
"in": "query",
"required": true,
"schema": {
"type": "string"
},
"description": "The variant of the engine"
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["version", "variant"],
"properties": {
"version": {
"type": "string",
"description": "The version of the engine variant",
"example": "0.1.34"
},
"variant": {
"type": "string",
"description": "The variant of the engine",
"example": "mac-arm64"
}
}
}
}
}
},
"responses": {
"200": {
"description": "Successful response",
Expand Down Expand Up @@ -3087,7 +3092,7 @@
"items": {
"type": "string"
},
"example": ["http://localhost:39281", "https://cortex.so"]
"example": ["http://127.0.0.1:39281", "https://cortex.so"]
},
"cors": {
"type": "boolean",
Expand Down Expand Up @@ -3134,7 +3139,7 @@
},
"example": {
"allowed_origins": [
"http://localhost:39281",
"http://127.0.0.1:39281",
"https://cortex.so"
],
"cors": false,
Expand Down Expand Up @@ -3175,7 +3180,7 @@
"type": "string"
},
"description": "List of allowed origins.",
"example": ["http://localhost:39281", "https://cortex.so"]
"example": ["http://127.0.0.1:39281", "https://cortex.so"]
},
"proxy_username": {
"type": "string",
Expand Down Expand Up @@ -3244,7 +3249,7 @@
"type": "string"
},
"example": [
"http://localhost:39281",
"http://127.0.0.1:39281",
"https://cortex.so"
]
},
Expand Down Expand Up @@ -6277,7 +6282,7 @@
},
"required": ["available", "total", "type"]
},
"Storage": {
"StorageDto": {
"type": "object",
"properties": {
"available": {
Expand Down
2 changes: 0 additions & 2 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,6 @@ add_executable(${TARGET_NAME} main.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/file_logger.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/dylib_path_manager.cc
${CMAKE_CURRENT_SOURCE_DIR}/extensions/remote-engine/remote_engine.cc
${CMAKE_CURRENT_SOURCE_DIR}/extensions/remote-engine/openai_engine.cc
${CMAKE_CURRENT_SOURCE_DIR}/extensions/remote-engine/anthropic_engine.cc
${CMAKE_CURRENT_SOURCE_DIR}/extensions/remote-engine/template_renderer.cc
)

Expand Down
2 changes: 0 additions & 2 deletions engine/cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,6 @@ add_executable(${TARGET_NAME} main.cc
${CMAKE_CURRENT_SOURCE_DIR}/../services/inference_service.cc
${CMAKE_CURRENT_SOURCE_DIR}/../services/hardware_service.cc
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/remote-engine/remote_engine.cc
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/remote-engine/openai_engine.cc
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/remote-engine/anthropic_engine.cc
${CMAKE_CURRENT_SOURCE_DIR}/../extensions/remote-engine/template_renderer.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/easywsclient.cc
${CMAKE_CURRENT_SOURCE_DIR}/utils/download_progress.cc
Expand Down
2 changes: 2 additions & 0 deletions engine/common/engine_servicei.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,6 @@ class EngineServiceI {
GetEngineByNameAndVariant(
const std::string& engine_name,
const std::optional<std::string> variant = std::nullopt) = 0;

virtual bool IsRemoteEngine(const std::string& engine_name) = 0;
};
21 changes: 21 additions & 0 deletions engine/common/message.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,27 @@ struct Message : JsonSerializable {
if (root["content"].isArray() && !root["content"].empty()) {
if (root["content"][0]["type"].asString() == "text") {
message.content = ParseContents(std::move(root["content"])).value();
} else if (root["content"][0]["type"].asString() == "image") {
// deprecated, for supporting jan and should be removed in the future
auto text_str = root["content"][0]["text"]["value"].asString();
auto img_url =
root["content"][0]["text"]["annotations"][0].asString();
auto text_content = std::make_unique<OpenAi::TextContent>();
{
auto text = OpenAi::Text();
auto empty_annotations =
std::vector<std::unique_ptr<Annotation>>();
text.value = std::move(text_str);
text.annotations = std::move(empty_annotations);
text_content->text = std::move(text);
}

auto image_url_obj = OpenAi::ImageUrl(img_url, "auto");
auto image_url_content = std::make_unique<OpenAi::ImageUrlContent>(
"image_url", std::move(image_url_obj));

message.content.push_back(std::move(text_content));
message.content.push_back(std::move(image_url_content));
} else {
// deprecated, for supporting jan and should be removed in the future
// check if annotations is empty
Expand Down
42 changes: 30 additions & 12 deletions engine/common/message_content_image_url.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@

namespace OpenAi {

struct ImageUrl {
// The external URL of the image, must be a supported image types: jpeg, jpg, png, gif, webp.
struct ImageUrl : public JsonSerializable {
/**
* The external URL of the image, must be a supported image types:
* jpeg, jpg, png, gif, webp.
*/
std::string url;

// Specifies the detail level of the image. low uses fewer tokens, you can opt in to high resolution using high. Default value is auto
/**
* Specifies the detail level of the image. low uses fewer tokens, you
* can opt in to high resolution using high. Default value is auto
*/
std::string detail;

ImageUrl() = default;
ImageUrl(const std::string& url, const std::string& detail = "auto")
: url{url}, detail{detail} {}

ImageUrl(ImageUrl&&) noexcept = default;

Expand All @@ -20,13 +27,25 @@ struct ImageUrl {
ImageUrl(const ImageUrl&) = delete;

ImageUrl& operator=(const ImageUrl&) = delete;

cpp::result<Json::Value, std::string> ToJson() override {
try {
Json::Value root;
root["url"] = url;
root["detail"] = detail;
return root;
} catch (const std::exception& e) {
return cpp::fail(std::string("ToJson failed: ") + e.what());
}
}
};

// References an image URL in the content of a message.
struct ImageUrlContent : Content {

// The type of the content part.
ImageUrlContent(const std::string& type) : Content(type) {}
explicit ImageUrlContent(const std::string& type, ImageUrl&& image_url)
: Content(type), image_url{std::move(image_url)} {}

ImageUrlContent(ImageUrlContent&&) noexcept = default;

Expand All @@ -38,18 +57,18 @@ struct ImageUrlContent : Content {

ImageUrl image_url;

~ImageUrlContent() override = default;

static cpp::result<ImageUrlContent, std::string> FromJson(
Json::Value&& json) {
if (json.empty()) {
return cpp::fail("Json string is empty");
}

try {
ImageUrlContent content{"image_url"};
ImageUrl image_url;
image_url.url = std::move(json["image_url"]["url"].asString());
image_url.detail = std::move(json["image_url"]["detail"].asString());
content.image_url = std::move(image_url);
auto image_url = ImageUrl(json["image_url"]["url"].asString(),
json["image_url"]["detail"].asString());
ImageUrlContent content{"image_url", std::move(image_url)};
return content;
} catch (const std::exception& e) {
return cpp::fail(std::string("FromJson failed: ") + e.what());
Expand All @@ -60,8 +79,7 @@ struct ImageUrlContent : Content {
try {
Json::Value json;
json["type"] = type;
json["image_url"]["url"] = image_url.url;
json["image_url"]["detail"] = image_url.detail;
json["image_url"] = image_url.ToJson().value();
return json;
} catch (const std::exception& e) {
return cpp::fail(std::string("ToJson failed: ") + e.what());
Expand Down
3 changes: 2 additions & 1 deletion engine/common/message_content_text.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ struct FilePathWrapper : Annotation {

struct Text : JsonSerializable {
// The data that makes up the text.

Text() = default;

Text(Text&&) noexcept = default;
Expand Down Expand Up @@ -214,6 +213,8 @@ struct TextContent : Content {

Text text;

~TextContent() override = default;

static cpp::result<TextContent, std::string> FromJson(Json::Value&& json) {
if (json.empty()) {
return cpp::fail("Json string is empty");
Expand Down
43 changes: 2 additions & 41 deletions engine/config/model_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,12 @@
#include <stdexcept>
#include <string>
#include <vector>
#include "config/remote_template.h"
#include "utils/format_utils.h"
#include "utils/remote_models_utils.h"

namespace config {

namespace {
const std::string kOpenAITransformReqTemplate =
R"({ {% set first = true %} {% for key, value in input_request %} {% if key == \"messages\" or key == \"model\" or key == \"temperature\" or key == \"store\" or key == \"max_tokens\" or key == \"stream\" or key == \"presence_penalty\" or key == \"metadata\" or key == \"frequency_penalty\" or key == \"tools\" or key == \"tool_choice\" or key == \"logprobs\" or key == \"top_logprobs\" or key == \"logit_bias\" or key == \"n\" or key == \"modalities\" or key == \"prediction\" or key == \"response_format\" or key == \"service_tier\" or key == \"seed\" or key == \"stop\" or key == \"stream_options\" or key == \"top_p\" or key == \"parallel_tool_calls\" or key == \"user\" %} {% if not first %},{% endif %} \"{{ key }}\": {{ tojson(value) }} {% set first = false %} {% endif %} {% endfor %} })";
const std::string kOpenAITransformRespTemplate =
R"({ {%- set first = true -%} {%- for key, value in input_request -%} {%- if key == \"id\" or key == \"choices\" or key == \"created\" or key == \"model\" or key == \"service_tier\" or key == \"system_fingerprint\" or key == \"object\" or key == \"usage\" -%} {%- if not first -%},{%- endif -%} \"{{ key }}\": {{ tojson(value) }} {%- set first = false -%} {%- endif -%} {%- endfor -%} })";
const std::string kAnthropicTransformReqTemplate =
R"({ {% set first = true %} {% for key, value in input_request %} {% if key == \"system\" or key == \"messages\" or key == \"model\" or key == \"temperature\" or key == \"store\" or key == \"max_tokens\" or key == \"stream\" or key == \"presence_penalty\" or key == \"metadata\" or key == \"frequency_penalty\" or key == \"tools\" or key == \"tool_choice\" or key == \"logprobs\" or key == \"top_logprobs\" or key == \"logit_bias\" or key == \"n\" or key == \"modalities\" or key == \"prediction\" or key == \"response_format\" or key == \"service_tier\" or key == \"seed\" or key == \"stop\" or key == \"stream_options\" or key == \"top_p\" or key == \"parallel_tool_calls\" or key == \"user\" %} {% if not first %},{% endif %} \"{{ key }}\": {{ tojson(value) }} {% set first = false %} {% endif %} {% endfor %} })";
const std::string kAnthropicTransformRespTemplate = R"({
"id": "{{ input_request.id }}",
"created": null,
"object": "chat.completion",
"model": "{{ input_request.model }}",
"choices": [
{
"index": 0,
"message": {
"role": "{{ input_request.role }}",
"content": "{% if input_request.content and input_request.content.0.type == "text" %} {{input_request.content.0.text}} {% endif %}",
"refusal": null
},
"logprobs": null,
"finish_reason": "{{ input_request.stop_reason }}"
}
],
"usage": {
"prompt_tokens": {{ input_request.usage.input_tokens }},
"completion_tokens": {{ input_request.usage.output_tokens }},
"total_tokens": {{ input_request.usage.input_tokens + input_request.usage.output_tokens }},
"prompt_tokens_details": {
"cached_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"system_fingerprint": "fp_6b68a8204b"
})";
} // namespace

struct RemoteModelConfig {
std::string model;
std::string api_key_template;
Expand Down Expand Up @@ -108,6 +68,7 @@ struct RemoteModelConfig {
kOpenAITransformRespTemplate;
}
}

metadata = json.get("metadata", metadata);
}

Expand Down
66 changes: 66 additions & 0 deletions engine/config/remote_template.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <string>

namespace config {
const std::string kOpenAITransformReqTemplate =
R"({ {% set first = true %} {% for key, value in input_request %} {% if key == "messages" or key == "model" or key == "temperature" or key == "store" or key == "max_tokens" or key == "stream" or key == "presence_penalty" or key == "metadata" or key == "frequency_penalty" or key == "tools" or key == "tool_choice" or key == "logprobs" or key == "top_logprobs" or key == "logit_bias" or key == "n" or key == "modalities" or key == "prediction" or key == "response_format" or key == "service_tier" or key == "seed" or key == "stop" or key == "stream_options" or key == "top_p" or key == "parallel_tool_calls" or key == "user" %} {% if not first %},{% endif %} "{{ key }}": {{ tojson(value) }} {% set first = false %} {% endif %} {% endfor %} })";
const std::string kOpenAITransformRespTemplate =
R"({ {%- set first = true -%} {%- for key, value in input_request -%} {%- if key == "id" or key == "choices" or key == "created" or key == "model" or key == "service_tier" or key == "system_fingerprint" or key == "object" or key == "usage" -%} {%- if not first -%},{%- endif -%} "{{ key }}": {{ tojson(value) }} {%- set first = false -%} {%- endif -%} {%- endfor -%} })";
const std::string kAnthropicTransformReqTemplate =
R"({
{% for key, value in input_request %}
{% if key == "messages" %}
{% if input_request.messages.0.role == "system" %}
"system": "{{ input_request.messages.0.content }}",
"messages": [
{% for message in input_request.messages %}
{% if not loop.is_first %}
{"role": "{{ message.role }}", "content": "{{ message.content }}" } {% if not loop.is_last %},{% endif %}
{% endif %}
{% endfor %}
]
{% else %}
"messages": [
{% for message in input_request.messages %}
{"role": " {{ message.role}}", "content": "{{ message.content }}" } {% if not loop.is_last %},{% endif %}
{% endfor %}
]
{% endif %}
{% else if key == "system" or key == "model" or key == "temperature" or key == "store" or key == "max_tokens" or key == "stream" or key == "presence_penalty" or key == "metadata" or key == "frequency_penalty" or key == "tools" or key == "tool_choice" or key == "logprobs" or key == "top_logprobs" or key == "logit_bias" or key == "n" or key == "modalities" or key == "prediction" or key == "response_format" or key == "service_tier" or key == "seed" or key == "stop" or key == "stream_options" or key == "top_p" or key == "parallel_tool_calls" or key == "user" %}
"{{ key }}": {{ tojson(value) }}
{% endif %}
{% if not loop.is_last %},{% endif %}
{% endfor %} })";
const std::string kAnthropicTransformRespTemplate = R"({
"id": "{{ input_request.id }}",
"created": null,
"object": "chat.completion",
"model": "{{ input_request.model }}",
"choices": [
{
"index": 0,
"message": {
"role": "{{ input_request.role }}",
"content": "{% if input_request.content and input_request.content.0.type == "text" %} {{input_request.content.0.text}} {% endif %}",
"refusal": null
},
"logprobs": null,
"finish_reason": "{{ input_request.stop_reason }}"
}
],
"usage": {
"prompt_tokens": {{ input_request.usage.input_tokens }},
"completion_tokens": {{ input_request.usage.output_tokens }},
"total_tokens": {{ input_request.usage.input_tokens + input_request.usage.output_tokens }},
"prompt_tokens_details": {
"cached_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 0,
"accepted_prediction_tokens": 0,
"rejected_prediction_tokens": 0
}
},
"system_fingerprint": "fp_6b68a8204b"
})";

} // namespace config
Loading

0 comments on commit 72aa7a7

Please sign in to comment.