|
@@ -12,15 +12,26 @@ std::vector<float> parseEmbeddingResponse(const nlohmann::json& body) {
|
|
|
for (const auto& v : emb) out.push_back(v.get<float>());
|
|
for (const auto& v : emb) out.push_back(v.get<float>());
|
|
|
return out;
|
|
return out;
|
|
|
}
|
|
}
|
|
|
|
|
+EmbeddingEndpoint splitEmbeddingBase(const std::string& apiBase) {
|
|
|
|
|
+ std::string base = apiBase;
|
|
|
|
|
+ while (!base.empty() && base.back() == '/') base.pop_back(); // strip trailing slashes
|
|
|
|
|
+ auto schemeEnd = base.find("://");
|
|
|
|
|
+ std::size_t from = (schemeEnd == std::string::npos) ? 0 : schemeEnd + 3;
|
|
|
|
|
+ auto slash = base.find('/', from);
|
|
|
|
|
+ if (slash == std::string::npos) return {base, ""};
|
|
|
|
|
+ return {base.substr(0, slash), base.substr(slash)}; // path keeps its leading '/', no trailing '/'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
EmbeddingClient::EmbeddingClient(std::string apiBase, std::string apiKey)
|
|
EmbeddingClient::EmbeddingClient(std::string apiBase, std::string apiKey)
|
|
|
: apiBase_(std::move(apiBase)), apiKey_(std::move(apiKey)) {}
|
|
: apiBase_(std::move(apiBase)), apiKey_(std::move(apiKey)) {}
|
|
|
std::vector<float> EmbeddingClient::embed(const std::string& model, const std::string& text) {
|
|
std::vector<float> EmbeddingClient::embed(const std::string& model, const std::string& text) {
|
|
|
- httplib::Client cli(apiBase_);
|
|
|
|
|
|
|
+ EmbeddingEndpoint ep = splitEmbeddingBase(apiBase_);
|
|
|
|
|
+ httplib::Client cli(ep.origin);
|
|
|
cli.set_connection_timeout(10); cli.set_read_timeout(30);
|
|
cli.set_connection_timeout(10); cli.set_read_timeout(30);
|
|
|
cli.enable_server_certificate_verification(true);
|
|
cli.enable_server_certificate_verification(true);
|
|
|
if (!apiKey_.empty()) cli.set_bearer_token_auth(apiKey_);
|
|
if (!apiKey_.empty()) cli.set_bearer_token_auth(apiKey_);
|
|
|
nlohmann::json req{{"model", model}, {"input", text}};
|
|
nlohmann::json req{{"model", model}, {"input", text}};
|
|
|
- auto res = cli.Post("/v1/embeddings", req.dump(), "application/json");
|
|
|
|
|
|
|
+ auto res = cli.Post(ep.path + "/v1/embeddings", req.dump(), "application/json");
|
|
|
if (!res) throw ApiError(ErrCode::Unavailable, "embedding_unreachable", "could not reach embedding endpoint");
|
|
if (!res) throw ApiError(ErrCode::Unavailable, "embedding_unreachable", "could not reach embedding endpoint");
|
|
|
if (res->status != 200)
|
|
if (res->status != 200)
|
|
|
throw ApiError(ErrCode::Unprocessable, "embedding_failed",
|
|
throw ApiError(ErrCode::Unprocessable, "embedding_failed",
|