|
| 1 | +#include "native_ai_bridge.h" |
| 2 | +#include <httplib.h> |
| 3 | +#include <iostream> |
| 4 | +#include <nlohmann/json.hpp> |
| 5 | + |
| 6 | +using json = nlohmann::json; |
| 7 | + |
| 8 | +struct NativeAIBridge::Impl { |
| 9 | + std::string base_url; |
| 10 | + std::string api_key; |
| 11 | + std::string model; |
| 12 | + std::unique_ptr<httplib::Client> client; |
| 13 | + |
| 14 | + Impl(const std::string &url, const std::string &key, const std::string &mdl) |
| 15 | + : base_url(url), api_key(key), model(mdl) { |
| 16 | + // Parse host and port from URL roughly or let httplib handle it |
| 17 | + // httplib::Client expects "http://host:port" |
| 18 | + client = std::make_unique<httplib::Client>(base_url.c_str()); |
| 19 | + client->set_connection_timeout(5, 0); // 5s connection timeout |
| 20 | + client->set_read_timeout(10, |
| 21 | + 0); // 10s read timeout (fast inference required) |
| 22 | + } |
| 23 | +}; |
| 24 | + |
| 25 | +NativeAIBridge::NativeAIBridge(const std::string &endpoint, |
| 26 | + const std::string &api_key, |
| 27 | + const std::string &model) |
| 28 | + : impl_(std::make_shared<Impl>(endpoint, api_key, model)) {} |
| 29 | + |
| 30 | +NativeAIBridge::~NativeAIBridge() {} |
| 31 | + |
| 32 | +std::string NativeAIBridge::query(const std::string &prompt) { |
| 33 | + json payload = { |
| 34 | + {"model", impl_->model}, |
| 35 | + {"messages", {{{"role", "user"}, {"content", prompt}}}}, |
| 36 | + {"max_tokens", 100}, // Limit response size for speed |
| 37 | + {"temperature", 0.0} // Deterministic |
| 38 | + }; |
| 39 | + |
| 40 | + httplib::Headers headers = {{"Content-Type", "application/json"}, |
| 41 | + {"Authorization", "Bearer " + impl_->api_key}}; |
| 42 | + |
| 43 | + auto res = impl_->client->Post("/v1/chat/completions", headers, |
| 44 | + payload.dump(), "application/json"); |
| 45 | + |
| 46 | + if (res && res->status == 200) { |
| 47 | + try { |
| 48 | + auto response_json = json::parse(res->body); |
| 49 | + if (response_json.contains("choices") && |
| 50 | + !response_json["choices"].empty()) { |
| 51 | + return response_json["choices"][0]["message"]["content"] |
| 52 | + .get<std::string>(); |
| 53 | + } |
| 54 | + } catch (const std::exception &e) { |
| 55 | + std::cerr << "[AIBridge] JSON Parse Error: " << e.what() << std::endl; |
| 56 | + return "Error: Parse Failure"; |
| 57 | + } |
| 58 | + } else { |
| 59 | + if (res) { |
| 60 | + std::cerr << "[AIBridge] HTTP Error: " << res->status |
| 61 | + << " Body: " << res->body << std::endl; |
| 62 | + return "Error: HTTP " + std::to_string(res->status); |
| 63 | + } else { |
| 64 | + std::cerr << "[AIBridge] Connection Failed: " << to_string(res.error()) |
| 65 | + << std::endl; |
| 66 | + return "Error: Connection Failed"; |
| 67 | + } |
| 68 | + } |
| 69 | + return "Error: Unknown"; |
| 70 | +} |
| 71 | + |
| 72 | +std::future<std::string> |
| 73 | +NativeAIBridge::query_async(const std::string &prompt) { |
| 74 | + // Simple std::async wrapper for now. |
| 75 | + // In production, this should use a thread pool or httplib's async features if |
| 76 | + // available (httplib is blocking sync usually). |
| 77 | + return std::async(std::launch::async, |
| 78 | + [this, prompt]() { return this->query(prompt); }); |
| 79 | +} |
| 80 | + |
| 81 | +bool NativeAIBridge::is_connected() const { |
| 82 | + // Simple health check |
| 83 | + auto res = impl_->client->Get("/v1/models"); |
| 84 | + return (res && res->status == 200); |
| 85 | +} |
0 commit comments