6#include <nlohmann/json.hpp>
7#include <rclcpp/rclcpp.hpp>
51 virtual void initialize_rest_base(
const rclcpp::Node::SharedPtr& node, std::string plugin_name =
"RestBase",
52 std::string api_key_name =
"")
61 node_->declare_parameter(
plugin_name_ +
".rest.uri",
"http://localhost:8000/api/v1/perception");
78 RCLCPP_INFO(
node_->get_logger(),
"Assigned driver URI: %s",
uri_.c_str());
79 RCLCPP_INFO(
node_->get_logger(),
"Assigned driver Method: %s",
method_.c_str());
80 RCLCPP_INFO(
node_->get_logger(),
"Assigned driver SSL Verify: %s",
ssl_verify_ ?
"true" :
"false");
81 RCLCPP_INFO(
node_->get_logger(),
"Assigned driver Auth Type: %s",
auth_type_.c_str());
82 RCLCPP_INFO(
node_->get_logger(),
"Assigned driver Timeout: %ld sec",
timeout_sec_);
86 if (!api_key_name.empty())
88 const char* api_key_env = std::getenv(api_key_name.c_str());
92 RCLCPP_INFO(
node_->get_logger(),
"API key loaded from environment variables: %s", api_key_name.c_str());
96 RCLCPP_ERROR(
node_->get_logger(),
"missing env variable: %s", api_key_name.c_str());
103 RCLCPP_INFO(
node_->get_logger(),
"An API key is not used for this plugin, using empty string");
120 nlohmann::json body_json =
toJson(req);
122 std::string json_body = body_json.dump();
123 std::string response_data;
125 CURL* curl = curl_easy_init();
132 struct curl_slist* headers =
nullptr;
133 headers = curl_slist_append(headers,
"Content-Type: application/json");
137 std::string auth_header =
"Authorization: Bearer " +
api_key_;
138 headers = curl_slist_append(headers, auth_header.c_str());
142 curl_slist_free_all(headers);
143 curl_easy_cleanup(curl);
148 curl_easy_setopt(curl, CURLOPT_URL,
uri_.c_str());
149 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
150 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_body.c_str());
151 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json_body.size());
153 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
158 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
159 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
162 CURLcode res = curl_easy_perform(curl);
165 curl_slist_free_all(headers);
166 curl_easy_cleanup(curl);
172 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
174 curl_slist_free_all(headers);
175 curl_easy_cleanup(curl);
177 if (http_code != 200)
187 nlohmann::json response_json = nlohmann::json::parse(response_data);
188 auto response =
fromJson(response_json);
192 catch (
const std::exception& e)
210 CURL* curl = curl_easy_init();
217 curl_mime* mime = curl_mime_init(curl);
220 curl_easy_cleanup(curl);
226 for (
const auto& opt : req.
options)
228 curl_mimepart* option_part = curl_mime_addpart(mime);
229 if (!option_part || curl_mime_name(option_part, opt.key.c_str()) != CURLE_OK ||
230 curl_mime_data(option_part, opt.value.c_str(), CURL_ZERO_TERMINATED) != CURLE_OK)
232 curl_mime_free(mime);
233 curl_easy_cleanup(curl);
240 curl_mimepart* file_part = curl_mime_addpart(mime);
241 if (!file_part || curl_mime_name(file_part,
"file") != CURLE_OK ||
242 curl_mime_filename(file_part,
"audio.wav") != CURLE_OK ||
244 curl_mime_type(file_part, req.
file_type.c_str()) != CURLE_OK)
246 curl_mime_free(mime);
247 curl_easy_cleanup(curl);
252 std::string response_data;
255 curl_easy_setopt(curl, CURLOPT_URL,
uri_.c_str());
256 curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
258 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
264 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
265 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
269 struct curl_slist* headers =
nullptr;
272 std::string auth_header =
"Authorization: Bearer " +
api_key_;
273 headers = curl_slist_append(headers, auth_header.c_str());
274 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
278 curl_mime_free(mime);
279 curl_easy_cleanup(curl);
285 CURLcode res = curl_easy_perform(curl);
289 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
292 curl_slist_free_all(headers);
293 curl_mime_free(mime);
294 curl_easy_cleanup(curl);
299 record_rest_result(
false, http_code, std::string(
"cURL error: ") + curl_easy_strerror(res));
303 if (http_code != 200)
313 nlohmann::json json = nlohmann::json::parse(response_data);
318 catch (
const std::exception& e)
327 CURL* curl = curl_easy_init();
335 nlohmann::json json_body;
336 for (
const auto& opt : req.
options)
338 json_body[opt.key] = opt.value;
340 json_body[
"input"] = req.
prompt;
342 std::string body = json_body.dump();
343 std::vector<uint8_t> response_binary;
346 struct curl_slist* headers =
nullptr;
347 headers = curl_slist_append(headers,
"Content-Type: application/json");
350 std::string auth_header =
"Authorization: Bearer " +
api_key_;
351 headers = curl_slist_append(headers, auth_header.c_str());
355 curl_easy_cleanup(curl);
356 curl_slist_free_all(headers);
361 curl_easy_setopt(curl, CURLOPT_URL,
uri_.c_str());
362 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
363 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());
364 curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, body.size());
369 curl, CURLOPT_WRITEFUNCTION, +[](
void* ptr,
size_t size,
size_t nmemb,
void* userdata) ->
size_t {
370 auto* vec =
reinterpret_cast<std::vector<uint8_t>*
>(userdata);
371 size_t total_size = size * nmemb;
372 vec->insert(vec->end(), (uint8_t*)ptr, (uint8_t*)ptr + total_size);
375 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_binary);
379 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
380 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
384 CURLcode res = curl_easy_perform(curl);
386 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
388 curl_slist_free_all(headers);
389 curl_easy_cleanup(curl);
393 record_rest_result(
false, http_code, std::string(
"cURL error: ") + curl_easy_strerror(res));
397 if (http_code != 200)
399 const std::string response_text(response_binary.begin(), response_binary.end());
406 std::vector<int16_t> samples(response_binary.size() / 2);
407 std::memcpy(samples.data(), response_binary.data(), response_binary.size());
423 const auto err_json = nlohmann::json::parse(response_data);
424 if (err_json.contains(
"error"))
426 const auto& err = err_json[
"error"];
427 if (err.is_object() && err.contains(
"message"))
429 if (err[
"message"].is_string())
430 details = err[
"message"].get<std::string>();
432 details = err[
"message"].dump();
436 details = err.dump();
442 if (details.empty() && !response_data.empty())
444 constexpr size_t kMaxLen = 1024;
445 details = response_data.substr(0, std::min(kMaxLen, response_data.size()));
448 std::string msg =
"HTTP error: " + std::to_string(http_code);
449 if (!details.empty())
450 msg +=
" - " + details;
477 static size_t write_callback(
void* contents,
size_t size,
size_t nmemb, std::string* userp)
479 userp->append(
static_cast<char*
>(contents), size * nmemb);
Definition driver_base.hpp:19
rclcpp::Node::SharedPtr node_
ROS node for the driver.
Definition driver_base.hpp:138
void initialize_base(const rclcpp::Node::SharedPtr &node)
Initializer base driver in place of constructor due to plugin semantics.
Definition driver_base.hpp:95
RestBase.
Definition rest_base.hpp:23
long connect_timeout_sec_
Definition rest_base.hpp:512
std::string method_
Definition rest_base.hpp:507
void apply_timeouts(CURL *curl)
Definition rest_base.hpp:455
virtual fp_perception::RESTResponse call(const fp_perception::RESTRequest &req)
Request data from the REST API.
Definition rest_base.hpp:117
std::atomic< bool > last_rest_success_
Definition rest_base.hpp:515
std::string last_rest_error_
Definition rest_base.hpp:518
static std::string build_http_error_message(long http_code, const std::string &response_data)
Definition rest_base.hpp:417
std::mutex rest_status_mutex_
Definition rest_base.hpp:517
void record_rest_result(bool success, long http_code, const std::string &error)
Definition rest_base.hpp:464
std::string plugin_name_
Definition rest_base.hpp:505
std::atomic< uint64_t > rest_request_count_
Definition rest_base.hpp:513
virtual fp_perception::RESTResponse fromJson(const nlohmann::json &object)=0
Convert a JSON object to a fp_perception response.
std::atomic< long > last_rest_http_code_
Definition rest_base.hpp:516
std::string uri_
Definition rest_base.hpp:506
virtual nlohmann::json toJson(const fp_perception::RESTRequest &request)=0
Convert a prompt request to a JSON object.
virtual fp_perception::RESTResponse call_tts(const fp_perception::RESTRequest &req)
Definition rest_base.hpp:325
bool ssl_verify_
Definition rest_base.hpp:508
RestBase()
Constructor.
Definition rest_base.hpp:30
virtual fp_perception::RESTResponse call_audio(const fp_perception::RESTRequest &req)
Request audio data from the REST API.
Definition rest_base.hpp:208
std::atomic< uint64_t > rest_failure_count_
Definition rest_base.hpp:514
std::string api_key_
Definition rest_base.hpp:510
virtual void initialize_rest_base(const rclcpp::Node::SharedPtr &node, std::string plugin_name="RestBase", std::string api_key_name="")
Initialize the REST base class.
Definition rest_base.hpp:51
std::string auth_type_
Definition rest_base.hpp:509
static size_t write_callback(void *contents, size_t size, size_t nmemb, std::string *userp)
Definition rest_base.hpp:477
virtual ~RestBase()
Destructor.
Definition rest_base.hpp:39
long timeout_sec_
Definition rest_base.hpp:511
Definition audio_buffer.hpp:16
Definition structs.hpp:26
std::string prompt
Definition structs.hpp:27
std::string file_type
Definition structs.hpp:28
std::vector< RESTOption > options
Definition structs.hpp:30
std::vector< char > file_stream
Definition structs.hpp:29
Definition structs.hpp:35
std::vector< int16_t > audio_stream
Definition structs.hpp:38
Base class for driver exceptions.
Definition exceptions.hpp:14