Skip to content

Commit

Permalink
feat: move virtual environment inside model
Browse files Browse the repository at this point in the history
  • Loading branch information
nguyenhoangthuan99 committed Dec 17, 2024
1 parent 3838a36 commit 34237d6
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 247 deletions.
35 changes: 26 additions & 9 deletions engine/config/model_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -547,17 +547,17 @@ struct PythonModelConfig {

// Model Load Parameters
std::string port;
std::string model_location;
std::string script;
std::string log_path;
std::string log_level;
std::string environment;
std::vector<std::string> command; // New command field
std::vector<std::string> files;
std::string engine;
Json::Value extra_params; // Accept dynamic extra parameters

// Method to convert C++ struct to YAML
void ToYaml(const std::string & filepath) const {
void ToYaml(const std::string& filepath) const {
YAML::Emitter out;
out << YAML::BeginMap;

Expand Down Expand Up @@ -597,7 +597,6 @@ struct PythonModelConfig {

// Model Load Parameters
out << YAML::Key << "port" << YAML::Value << port;
out << YAML::Key << "model_location" << YAML::Value << model_location;
out << YAML::Key << "script" << YAML::Value << script;
out << YAML::Key << "log_path" << YAML::Value << log_path;
out << YAML::Key << "log_level" << YAML::Value << log_level;
Expand All @@ -610,6 +609,13 @@ struct PythonModelConfig {
}
out << YAML::EndSeq;

// Serialize files as YAML list
out << YAML::Key << "files" << YAML::Value << YAML::BeginSeq;
for (const auto& file : files) {
out << file;
}
out << YAML::EndSeq;

out << YAML::Key << "engine" << YAML::Value << engine;

// Serialize extra_params as YAML
Expand Down Expand Up @@ -674,8 +680,6 @@ struct PythonModelConfig {
auto mlp = config;
if (mlp["port"])
port = mlp["port"].as<std::string>();
if (mlp["model_location"])
model_location = mlp["model_location"].as<std::string>();
if (mlp["script"])
script = mlp["script"].as<std::string>();
if (mlp["log_path"])
Expand All @@ -693,6 +697,12 @@ struct PythonModelConfig {
}
}

if (mlp["files"] && mlp["files"].IsSequence()) {
for (const auto& file : mlp["files"]) {
files.push_back(file.as<std::string>());
}
}

if (mlp["extra_params"]) {
for (YAML::const_iterator it = mlp["extra_params"].begin();
it != mlp["extra_params"].end(); ++it) {
Expand Down Expand Up @@ -735,14 +745,17 @@ struct PythonModelConfig {
root["log_path"] = log_path;
root["log_level"] = log_level;
root["environment"] = environment;
root["model_location"] = model_location;
root["script"] = script;

// Serialize command as JSON array
for (const auto& cmd : command) {
root["command"].append(cmd);
}

for (const auto& file : files) {
root["files"].append(file);
}

root["engine"] = engine;
root["extra_params"] = extra_params; // Serialize the JSON value directly

Expand All @@ -751,7 +764,7 @@ struct PythonModelConfig {

// Method to populate struct from JSON
void FromJson(const Json::Value& root) {

if (root.isMember("id"))
id = root["id"].asString();
if (root.isMember("model"))
Expand Down Expand Up @@ -802,8 +815,6 @@ struct PythonModelConfig {
environment = mlp["environment"].asString();
if (mlp.isMember("engine"))
engine = mlp["engine"].asString();
if (mlp.isMember("model_location"))
model_location = mlp["model_location"].asString();
if (mlp.isMember("script"))
script = mlp["script"].asString();

Expand All @@ -813,6 +824,12 @@ struct PythonModelConfig {
}
}

if (mlp.isMember("files")) {
for (const auto& file : mlp["files"]) {
files.push_back(file.asString());
}
}

if (mlp.isMember("extra_params")) {
extra_params = mlp["extra_params"]; // Directly assign the JSON value
}
Expand Down
21 changes: 7 additions & 14 deletions engine/extensions/python-engine/python_engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ pid_t PythonEngine::SpawnProcess(const std::string& model,

// Convert command vector to char*[]
std::vector<char*> argv = convertToArgv(command);
for (auto c : command) {
std::cout << c << " " << std::endl;
}
// for (auto c : command) {
// std::cout << c << " " << std::endl;
// }

// Use posix_spawn for cross-platform compatibility
int spawn_result = posix_spawn(&pid, // pid output
Expand Down Expand Up @@ -319,7 +319,7 @@ void PythonEngine::GetModels(
void PythonEngine::LoadModel(
std::shared_ptr<Json::Value> json_body,
std::function<void(Json::Value&&, Json::Value&&)>&& callback) {
// TODO: handle a case that can spawn process but the process spawn fail.
// TODO: handle a case that can spawn process but the process spawn fail.
pid_t pid;
if (!json_body->isMember("model") || !json_body->isMember("model_path")) {
Json::Value error;
Expand Down Expand Up @@ -359,26 +359,19 @@ void PythonEngine::LoadModel(
return;
}
auto model_config = models_[model];
auto model_folder_path = model_config.files[0];
auto data_folder_path = std::filesystem::path(model_folder_path) / std::filesystem::path("venv");
try {
std::string data_folder_path =
"/home/thuan/cortexcpp/environments/"; // To do: will be removed with cortex data path
std::string model_folder_path =
"/home/thuan/cortexcpp/models/cortex.so/whispervq/fp16/"; // To do: will be removed with cortex model path
#ifdef _WIN32
auto executable = std::filesystem::path(data_folder_path) /
std::filesystem::path(model_config.environment) /
std::filesystem::path("Scripts");
#else
auto executable = std::filesystem::path(data_folder_path) /
std::filesystem::path(model_config.environment) /
std::filesystem::path("bin");
#endif
std::cout << "executable string: " << executable.string()
<< data_folder_path << " " << model_config.environment
<< std::endl;

auto executable_str =
(executable / std::filesystem::path(model_config.command[0])).string();
std::cout << "executable string: " << executable_str << std::endl;
auto command = model_config.command;
command[0] = executable_str;
command.push_back((std::filesystem::path(model_folder_path) /
Expand Down
Empty file.
51 changes: 0 additions & 51 deletions engine/services/environment_service.h

This file was deleted.

61 changes: 59 additions & 2 deletions engine/services/model_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,23 @@
#include <curl/multi.h>
#include <drogon/HttpTypes.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <optional>
#include <ostream>
#include "config/gguf_parser.h"
#include "config/yaml_config.h"
#include "database/models.h"
#include "hardware_service.h"
#include "utils/archive_utils.h"
#include "utils/cli_selection_utils.h"
#include "utils/cortex_utils.h"
#include "utils/engine_constants.h"
#include "utils/file_manager_utils.h"
#include "utils/huggingface_utils.h"
#include "utils/logging_utils.h"
#include "utils/result.hpp"
#include "utils/set_permission_utils.h"
#include "utils/string_utils.h"
#include "utils/widechar_conv.h"

Expand Down Expand Up @@ -540,9 +543,63 @@ ModelService::DownloadModelFromCortexsoAsync(
if (mc.engine == kPythonEngine) { // process for Python engine
config::PythonModelConfig python_model_config;
python_model_config.ReadFromYaml(model_yml_item->localPath.string());
python_model_config.model_location =
model_yml_item->localPath.parent_path().string();
python_model_config.files.push_back(
model_yml_item->localPath.parent_path().string());
python_model_config.ToYaml(model_yml_item->localPath.string());
// unzip venv.zip
auto model_folder = model_yml_item->localPath.parent_path();
auto venv_path = model_folder / std::filesystem::path("venv");
if (!std::filesystem::exists(venv_path)) {
std::filesystem::create_directories(venv_path);
}
auto venv_zip = model_folder / std::filesystem::path("venv.zip");
if (std::filesystem::exists(venv_zip)) {
if (archive_utils::ExtractArchive(venv_zip.string(), venv_path)) {
std::filesystem::remove_all(venv_zip);
CTL_INF("Successfully extract venv.zip");
// If extract success create pyvenv.cfg
std::ofstream pyvenv_cfg(venv_path /
std::filesystem::path("pyvenv.cfg"));
#ifdef _WIN32
pyvenv_cfg << "home = "
<< (venv_path / std::filesystem::path("Scripts")).string()
<< std::endl;
pyvenv_cfg << "executable = "
<< (venv_path / std::filesystem::path("Scripts") /
std::filesystem::path("python.exe"))
.string()
<< std::endl;

#else
pyvenv_cfg << "home = "
<< (venv_path / std::filesystem::path("bin/")).string()
<< std::endl;
pyvenv_cfg
<< "executable = "
<< (venv_path / std::filesystem::path("bin/python")).string()
<< std::endl;
#endif

// Close the file
pyvenv_cfg.close();
// Add executable permission to python

#ifdef _WIN32
set_permission_utils::SetExecutePermissionsRecursive(
venv_path / std::filesystem::path("Scripts"));
#else
set_permission_utils::SetExecutePermissionsRecursive(
venv_path / std::filesystem::path("bin"));
#endif

} else {
CTL_ERR("Failed to extract venv.zip");
};

} else {
CTL_ERR(
"venv.zip not found in model folder: " << model_folder.string());
}

} else {
mc.model = unique_model_id;
Expand Down
3 changes: 0 additions & 3 deletions engine/utils/environment_constants.h

This file was deleted.

Loading

0 comments on commit 34237d6

Please sign in to comment.