|
|
@@ -0,0 +1,30 @@
|
|
|
+#include "embeddings.hpp"
|
|
|
+#include "errors.hpp"
|
|
|
+#include <httplib.h>
|
|
|
+namespace svapi {
|
|
|
+std::vector<float> parseEmbeddingResponse(const nlohmann::json& body) {
|
|
|
+ if (!body.contains("data") || !body["data"].is_array() || body["data"].empty())
|
|
|
+ throw ApiError(ErrCode::Unprocessable, "embedding_failed", "embedding response missing data[]");
|
|
|
+ const auto& emb = body["data"][0].value("embedding", nlohmann::json());
|
|
|
+ if (!emb.is_array() || emb.empty())
|
|
|
+ throw ApiError(ErrCode::Unprocessable, "embedding_failed", "embedding response missing embedding[]");
|
|
|
+ std::vector<float> out; out.reserve(emb.size());
|
|
|
+ for (const auto& v : emb) out.push_back(v.get<float>());
|
|
|
+ return out;
|
|
|
+}
|
|
|
+EmbeddingClient::EmbeddingClient(std::string apiBase, std::string apiKey)
|
|
|
+ : apiBase_(std::move(apiBase)), apiKey_(std::move(apiKey)) {}
|
|
|
+std::vector<float> EmbeddingClient::embed(const std::string& model, const std::string& text) {
|
|
|
+ httplib::Client cli(apiBase_);
|
|
|
+ cli.set_connection_timeout(10); cli.set_read_timeout(30);
|
|
|
+ cli.enable_server_certificate_verification(true);
|
|
|
+ if (!apiKey_.empty()) cli.set_bearer_token_auth(apiKey_);
|
|
|
+ nlohmann::json req{{"model", model}, {"input", text}};
|
|
|
+ auto res = cli.Post("/v1/embeddings", req.dump(), "application/json");
|
|
|
+ if (!res) throw ApiError(ErrCode::Unavailable, "embedding_unreachable", "could not reach embedding endpoint");
|
|
|
+ if (res->status != 200)
|
|
|
+ throw ApiError(ErrCode::Unprocessable, "embedding_failed",
|
|
|
+ "embedding endpoint returned HTTP " + std::to_string(res->status));
|
|
|
+ return parseEmbeddingResponse(nlohmann::json::parse(res->body));
|
|
|
+}
|
|
|
+}
|