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

Commit 0ae2c27

Browse files
authored
fix: change to abs path for engine loading (#560)
1 parent 9e95b45 commit 0ae2c27

File tree

4 files changed

+114
-62
lines changed

4 files changed

+114
-62
lines changed

cortex-cpp/controllers/server.cc

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
#include <iostream>
66

77
#include "trantor/utils/Logger.h"
8-
#include "utils/logging_utils.h"
98
#include "utils/cortex_utils.h"
9+
#include "utils/logging_utils.h"
1010

1111
using namespace inferences;
1212
using json = nlohmann::json;
1313
namespace inferences {
1414
namespace {
1515
constexpr static auto kLlamaEngine = "cortex.llamacpp";
16-
constexpr static auto kLlamaLibPath = "./engines/cortex.llamacpp";
16+
constexpr static auto kLlamaLibPath = "/engines/cortex.llamacpp";
1717
} // namespace
1818

1919
server::server()
@@ -57,9 +57,8 @@ void server::ChatCompletion(
5757
LOG_TRACE << "Done chat completion";
5858
}
5959

60-
void server::Embedding(
61-
const HttpRequestPtr& req,
62-
std::function<void(const HttpResponsePtr&)>&& callback) {
60+
void server::Embedding(const HttpRequestPtr& req,
61+
std::function<void(const HttpResponsePtr&)>&& callback) {
6362
if (!IsEngineLoaded()) {
6463
Json::Value res;
6564
res["message"] = "Engine is not loaded yet";
@@ -130,9 +129,8 @@ void server::ModelStatus(
130129
LOG_TRACE << "Done get model status";
131130
}
132131

133-
void server::LoadModel(
134-
const HttpRequestPtr& req,
135-
std::function<void(const HttpResponsePtr&)>&& callback) {
132+
void server::LoadModel(const HttpRequestPtr& req,
133+
std::function<void(const HttpResponsePtr&)>&& callback) {
136134
auto engine_type =
137135
(*(req->getJsonObject())).get("engine", kLlamaEngine).asString();
138136
if (!dylib_ || engine_type != cur_engine_name_) {
@@ -146,9 +144,11 @@ void server::LoadModel(
146144
};
147145

148146
try {
147+
std::string abs_path = cortex_utils::GetCurrentPath() +
148+
get_engine_path(cur_engine_name_);
149149
dylib_ =
150-
std::make_unique<dylib>(get_engine_path(cur_engine_name_), "engine");
151-
} catch (const dylib::load_error& e) {
150+
std::make_unique<cortex_cpp::dylib>(abs_path, "engine");
151+
} catch (const cortex_cpp::dylib::load_error& e) {
152152
LOG_ERROR << "Could not load engine: " << e.what();
153153
dylib_.reset();
154154
engine_ = nullptr;
@@ -180,7 +180,7 @@ void server::LoadModel(
180180
}
181181

182182
void server::ProcessStreamRes(std::function<void(const HttpResponsePtr&)> cb,
183-
std::shared_ptr<SyncQueue> q) {
183+
std::shared_ptr<SyncQueue> q) {
184184
auto err_or_done = std::make_shared<std::atomic_bool>(false);
185185
auto chunked_content_provider =
186186
[q, err_or_done](char* buf, std::size_t buf_size) -> std::size_t {
@@ -209,12 +209,12 @@ void server::ProcessStreamRes(std::function<void(const HttpResponsePtr&)> cb,
209209
};
210210

211211
auto resp = cortex_utils::nitroStreamResponse(chunked_content_provider,
212-
"chat_completions.txt");
212+
"chat_completions.txt");
213213
cb(resp);
214214
}
215215

216-
void server::ProcessNonStreamRes(
217-
std::function<void(const HttpResponsePtr&)> cb, SyncQueue& q) {
216+
void server::ProcessNonStreamRes(std::function<void(const HttpResponsePtr&)> cb,
217+
SyncQueue& q) {
218218
auto [status, res] = q.wait_and_pop();
219219
auto resp = cortex_utils::nitroHttpJsonResponse(res);
220220
resp->setStatusCode(

cortex-cpp/controllers/server.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ class server : public drogon::HttpController<server>,
120120
};
121121

122122
private:
123-
std::unique_ptr<dylib> dylib_;
123+
std::unique_ptr<cortex_cpp::dylib> dylib_;
124124
EngineI* engine_;
125125
std::string cur_engine_name_;
126126
};

cortex-cpp/utils/cortex_utils.h

Lines changed: 97 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,34 @@
11
#pragma once
2-
#include "cstdio"
3-
#include "random"
4-
#include "string"
5-
#include <algorithm>
62
#include <drogon/HttpClient.h>
73
#include <drogon/HttpResponse.h>
4+
#include <algorithm>
85
#include <fstream>
96
#include <iostream>
107
#include <ostream>
118
#include <regex>
129
#include <vector>
10+
#include "cstdio"
11+
#include "random"
12+
#include "string"
1313
// Include platform-specific headers
1414
#ifdef _WIN32
15-
#include <winsock2.h>
1615
#include <windows.h>
16+
#include <winsock2.h>
1717
#else
1818
#include <dirent.h>
19+
#include <unistd.h>
20+
#endif
21+
22+
#if __APPLE__
23+
#include <limits.h>
24+
#include <mach-o/dyld.h>
1925
#endif
2026

2127
namespace cortex_utils {
2228

2329
inline std::string models_folder = "./models";
2430

25-
inline std::string extractBase64(const std::string &input) {
31+
inline std::string extractBase64(const std::string& input) {
2632
std::regex pattern("base64,(.*)");
2733
std::smatch match;
2834

@@ -36,7 +42,7 @@ inline std::string extractBase64(const std::string &input) {
3642
}
3743

3844
// Helper function to encode data to Base64
39-
inline std::string base64Encode(const std::vector<unsigned char> &data) {
45+
inline std::string base64Encode(const std::vector<unsigned char>& data) {
4046
static const char encodingTable[] =
4147
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4248
std::string encodedData;
@@ -78,7 +84,7 @@ inline std::string base64Encode(const std::vector<unsigned char> &data) {
7884
}
7985

8086
// Function to load an image and convert it to Base64
81-
inline std::string imageToBase64(const std::string &imagePath) {
87+
inline std::string imageToBase64(const std::string& imagePath) {
8288
std::ifstream imageFile(imagePath, std::ios::binary);
8389
if (!imageFile.is_open()) {
8490
throw std::runtime_error("Could not open the image file.");
@@ -90,8 +96,8 @@ inline std::string imageToBase64(const std::string &imagePath) {
9096
}
9197

9298
// Helper function to generate a unique filename
93-
inline std::string generateUniqueFilename(const std::string &prefix,
94-
const std::string &extension) {
99+
inline std::string generateUniqueFilename(const std::string& prefix,
100+
const std::string& extension) {
95101
// Get current time as a timestamp
96102
auto now = std::chrono::system_clock::now();
97103
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
@@ -108,18 +114,18 @@ inline std::string generateUniqueFilename(const std::string &prefix,
108114
return ss.str();
109115
}
110116

111-
inline void
112-
processLocalImage(const std::string &localPath,
113-
std::function<void(const std::string &)> callback) {
117+
inline void processLocalImage(
118+
const std::string& localPath,
119+
std::function<void(const std::string&)> callback) {
114120
try {
115121
std::string base64Image = imageToBase64(localPath);
116-
callback(base64Image); // Invoke the callback with the Base64 string
117-
} catch (const std::exception &e) {
122+
callback(base64Image); // Invoke the callback with the Base64 string
123+
} catch (const std::exception& e) {
118124
std::cerr << "Error during processing: " << e.what() << std::endl;
119125
}
120126
}
121127

122-
inline std::vector<std::string> listFilesInDir(const std::string &path) {
128+
inline std::vector<std::string> listFilesInDir(const std::string& path) {
123129
std::vector<std::string> files;
124130

125131
#ifdef _WIN32
@@ -137,12 +143,12 @@ inline std::vector<std::string> listFilesInDir(const std::string &path) {
137143
}
138144
#else
139145
// POSIX-specific code (Linux, Unix, MacOS)
140-
DIR *dir;
141-
struct dirent *ent;
146+
DIR* dir;
147+
struct dirent* ent;
142148

143149
if ((dir = opendir(path.c_str())) != NULL) {
144150
while ((ent = readdir(dir)) != NULL) {
145-
if (ent->d_type == DT_REG) { // Check if it's a regular file
151+
if (ent->d_type == DT_REG) { // Check if it's a regular file
146152
files.push_back(ent->d_name);
147153
}
148154
}
@@ -153,7 +159,7 @@ inline std::vector<std::string> listFilesInDir(const std::string &path) {
153159
return files;
154160
}
155161

156-
inline std::string rtrim(const std::string &str) {
162+
inline std::string rtrim(const std::string& str) {
157163
size_t end = str.find_last_not_of("\n\t ");
158164
return (end == std::string::npos) ? "" : str.substr(0, end + 1);
159165
}
@@ -165,7 +171,8 @@ inline std::string generate_random_string(std::size_t length) {
165171
std::random_device rd;
166172
std::mt19937 generator(rd());
167173

168-
std::uniform_int_distribution<> distribution(0, static_cast<int>(characters.size()) - 1);
174+
std::uniform_int_distribution<> distribution(
175+
0, static_cast<int>(characters.size()) - 1);
169176

170177
std::string random_string(length, '\0');
171178
std::generate_n(random_string.begin(), length,
@@ -174,37 +181,39 @@ inline std::string generate_random_string(std::size_t length) {
174181
return random_string;
175182
}
176183

177-
#if (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(__i386__))
184+
#if (defined(__GNUC__) || defined(__clang__)) && \
185+
(defined(__x86_64__) || defined(__i386__))
178186
#include <cpuid.h>
179-
inline bool isAVX2Supported() {
180-
unsigned eax, ebx, ecx, edx;
181-
if (__get_cpuid_max(0, nullptr) < 7) return false;
187+
inline bool isAVX2Supported() {
188+
unsigned eax, ebx, ecx, edx;
189+
if (__get_cpuid_max(0, nullptr) < 7)
190+
return false;
182191

183-
__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx);
184-
return (ebx & (1 << 5)) != 0;
185-
}
192+
__get_cpuid_count(7, 0, &eax, &ebx, &ecx, &edx);
193+
return (ebx & (1 << 5)) != 0;
194+
}
186195
#elif defined(_MSC_VER) && defined(_M_X64) || defined(_M_IX86)
187196
#include <intrin.h>
188-
inline bool isAVX2Supported() {
189-
int cpuInfo[4];
190-
__cpuid(cpuInfo, 0);
191-
int nIds = cpuInfo[0];
192-
if (nIds >= 7) {
193-
__cpuidex(cpuInfo, 7, 0);
194-
return (cpuInfo[1] & (1 << 5)) != 0;
195-
}
196-
return false;
197+
inline bool isAVX2Supported() {
198+
int cpuInfo[4];
199+
__cpuid(cpuInfo, 0);
200+
int nIds = cpuInfo[0];
201+
if (nIds >= 7) {
202+
__cpuidex(cpuInfo, 7, 0);
203+
return (cpuInfo[1] & (1 << 5)) != 0;
197204
}
205+
return false;
206+
}
198207
#else
199-
inline bool isAVX2Supported() {
200-
return false;
201-
}
208+
inline bool isAVX2Supported() {
209+
return false;
210+
}
202211
#endif
203212

204213
inline void nitro_logo() {
205214
std::string rainbowColors[] = {
206-
"\033[93m", // Yellow
207-
"\033[94m", // Blue
215+
"\033[93m", // Yellow
216+
"\033[94m", // Blue
208217
};
209218

210219
std::string resetColor = "\033[0m";
@@ -242,7 +251,7 @@ inline void nitro_logo() {
242251
}
243252
}
244253

245-
std::cout << resetColor; // Reset color at the endreturn;
254+
std::cout << resetColor; // Reset color at the endreturn;
246255
}
247256

248257
inline drogon::HttpResponsePtr nitroHttpResponse() {
@@ -254,7 +263,7 @@ inline drogon::HttpResponsePtr nitroHttpResponse() {
254263
return resp;
255264
}
256265

257-
inline drogon::HttpResponsePtr nitroHttpJsonResponse(const Json::Value &data) {
266+
inline drogon::HttpResponsePtr nitroHttpJsonResponse(const Json::Value& data) {
258267
auto resp = drogon::HttpResponse::newHttpJsonResponse(data);
259268
#ifdef ALLOW_ALL_CORS
260269
LOG_INFO << "Respond for all cors!";
@@ -265,8 +274,8 @@ inline drogon::HttpResponsePtr nitroHttpJsonResponse(const Json::Value &data) {
265274
};
266275

267276
inline drogon::HttpResponsePtr nitroStreamResponse(
268-
const std::function<std::size_t(char *, std::size_t)> &callback,
269-
const std::string &attachmentFileName = "") {
277+
const std::function<std::size_t(char*, std::size_t)>& callback,
278+
const std::string& attachmentFileName = "") {
270279
auto resp = drogon::HttpResponse::newStreamResponse(
271280
callback, attachmentFileName, drogon::CT_NONE, "text/event-stream");
272281
#ifdef ALLOW_ALL_CORS
@@ -282,4 +291,45 @@ inline void ltrim(std::string& s) {
282291
}));
283292
};
284293

285-
} // namespace cortex_utils
294+
#if defined(_WIN32)
295+
inline std::string GetCurrentPath() {
296+
wchar_t path[MAX_PATH];
297+
DWORD result = GetModuleFileNameW(NULL, path, MAX_PATH);
298+
if (result == 0) {
299+
std::wcerr << L"Error getting module file name." << std::endl;
300+
return "";
301+
}
302+
std::wstring::size_type pos = std::wstring(path).find_last_of(L"\\/");
303+
auto ws = std::wstring(path).substr(0, pos);
304+
std::string res;
305+
std::transform(ws.begin(), ws.end(), std::back_inserter(res),
306+
[](wchar_t c) { return (char)c; });
307+
return res;
308+
}
309+
#else
310+
inline std::string GetCurrentPath() {
311+
#ifdef __APPLE__
312+
char buf[PATH_MAX];
313+
uint32_t bufsize = PATH_MAX;
314+
315+
if (_NSGetExecutablePath(buf, &bufsize) == 0) {
316+
auto s = std::string(buf);
317+
auto const pos = s.find_last_of('/');
318+
return s.substr(0, pos);
319+
}
320+
return "";
321+
#else
322+
std::vector<char> buf(PATH_MAX);
323+
ssize_t len = readlink("/proc/self/exe", &buf[0], buf.size());
324+
if (len == -1 || len == buf.size()) {
325+
std::cerr << "Error reading symlink /proc/self/exe." << std::endl;
326+
return "";
327+
}
328+
auto s = std::string(&buf[0], len);
329+
auto const pos = s.find_last_of('/');
330+
return s.substr(0, pos);
331+
#endif
332+
}
333+
#endif
334+
335+
} // namespace cortex_utils

cortex-cpp/utils/dylib.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
* The `dylib` class represents a single dynamic library instance,
5959
* allowing the access of symbols like functions or global variables
6060
*/
61+
namespace cortex_cpp {
6162
class dylib {
6263
public:
6364
struct filename_components {
@@ -311,6 +312,7 @@ class dylib {
311312
}
312313
};
313314

315+
}
314316
#undef DYLIB_WIN_MAC_OTHER
315317
#undef DYLIB_WIN_OTHER
316318
#undef DYLIB_CPP17

0 commit comments

Comments
 (0)