summaryrefslogtreecommitdiff
path: root/src/ai_providers/openAI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ai_providers/openAI.cpp')
-rw-r--r--src/ai_providers/openAI.cpp276
1 files changed, 0 insertions, 276 deletions
diff --git a/src/ai_providers/openAI.cpp b/src/ai_providers/openAI.cpp
deleted file mode 100644
index d1495dc..0000000
--- a/src/ai_providers/openAI.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
-* Copyright (c) 2025 Aldrik Ramaekers <aldrik.ramaekers@gmail.com>
-*
-* Permission to use, copy, modify, and/or distribute this software for any
-* purpose with or without fee is hereby granted, provided that the above
-* copyright notice and this permission notice appear in all copies.
-*
-* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#include <threads.h>
-
-#define CPPHTTPLIB_OPENSSL_SUPPORT
-#include "httplib.h"
-
-#include "memops.hpp"
-#include "strops.hpp"
-#include "logger.hpp"
-#include "importer.hpp"
-
-static bool _openAI_batch_query_with_file(const char** queries, size_t query_count, char* file_id, invoice* buffer, importer::batch_query_response_handler response_handler)
-{
- const char *api_key = administration::get_ai_service().api_key_public;
- httplib::SSLClient cli("api.openai.com", 443);
-
- thrd_t threads[20];
- assert(query_count <= 20);
-
- for (u32 i = 0; i < query_count; i++)
- {
- auto* func = new auto([&api_key, &cli, i, &file_id, &response_handler, &buffer, &queries]() {
- char* query_escaped = strops::prep_str_for_json(queries[i], 1000);
-
- size_t body_size = 1000; // Ballpark
- char* body = (char*)memops::alloc(body_size);
- strops::format(body, body_size,
- "{ \"model\":\"%s\", "
- " \"input\": [ "
- " { \"role\": \"user\", "
- " \"content\": [ "
- " { \"type\": \"input_file\", \"file_id\": \"%s\" }, "
- " { \"type\": \"input_text\", \"text\": \"%s\" } "
- " ] "
- " }"
- "], "
- " \"text\": { \"format\": { \"type\": \"json_object\" } } "
- "}", administration::get_ai_service().model_name, file_id, query_escaped);
-
- httplib::Headers headers;
- headers.insert(std::make_pair("Authorization", std::string("Bearer ") + api_key));
-
- httplib::Result res = cli.Post("/v1/responses", headers, body, "application/json");
- memops::unalloc(body);
-
- if (!res || res->status != 200) {
- logger::error("ERROR Failed to query API.");
- logger::error(res->body.c_str());
- return 0;
- }
-
- char* response_body = (char*)res->body.c_str();
- char* response = (char*)memops::alloc(5000);
- memops::zero(response, 5000);
- strops::copy(response, response_body, 5000);
-
- strops::get_json_value(response, "text", response, 5000);
- strops::unprep_str_from_json(response);
-
- response_handler(buffer, response);
-
- memops::unalloc(response);
- memops::unalloc(query_escaped);
- return 1;
- });
-
- auto trampoline = [](void* arg) -> int {
- auto* f = static_cast<decltype(func)>(arg);
- (*f)();
- delete f;
- return 0;
- };
-
- thrd_create(&threads[i], trampoline, func);
- }
-
- for (u32 i = 0; i < query_count; i++) thrd_join(threads[i], nullptr);
-
- return 1;
-}
-
-static bool _openAI_query_with_file(const char* query, size_t query_length, char* file_id, char** response)
-{
- const char *api_key = administration::get_ai_service().api_key_public;
-
- httplib::SSLClient cli("api.openai.com", 443);
- //cli.enable_server_certificate_verification(false);
-
- char* query_escaped = strops::prep_str_for_json(query, query_length);
- //memops::unalloc(query);
-
- size_t body_size = query_length + 200;
- char* body = (char*)memops::alloc(body_size);
- strops::format(body, body_size,
- "{\"model\":\"%s\", \"input\": [ { \"role\": \"user\", \"content\": [ { \"type\": \"input_file\", \"file_id\": \"%s\" }, "
- "{ \"type\": \"input_text\", \"text\": \"%s\" } ] } ] }", administration::get_ai_service().model_name, file_id, query_escaped);
-
- httplib::Headers headers;
- headers.insert(std::make_pair("Authorization", std::string("Bearer ") + api_key));
-
- httplib::Result res = cli.Post("/v1/responses", headers, body, "application/json");
- memops::unalloc(body);
-
- if (!res || res->status != 200) {
- logger::error("ERROR Failed to query API.");
- logger::error(res->body.c_str());
- return 0;
- }
-
- char* response_body = (char*)res->body.c_str();
- *response = (char*)memops::alloc(100000);
- memops::zero(*response, 100000);
- strops::copy(*response, response_body, 100000);
-
- strops::get_json_value(*response, "text", *response, 100000);
- *response = strops::unprep_str_from_json(*response);
-
- return 1;
-}
-
-static bool _openAI_upload_file(char* file_path, char* file_id, size_t file_id_len)
-{
- const char *api_key = administration::get_ai_service().api_key_public;
- const char *filename = strops::get_filename(file_path);
-
- FILE* orig_file = fopen(file_path, "rb");
- if (orig_file == NULL) {
- logger::error("ERROR: file to upload could not be opened.");
- return 0;
- }
-
- fseek(orig_file, 0L, SEEK_END);
- long sz = ftell(orig_file);
- fseek(orig_file, 0, SEEK_SET);
-
- httplib::SSLClient cli("api.openai.com", 443);
- //cli.enable_server_certificate_verification(false);
-
- char body[512];
- strops::format(body, sizeof(body), "{\"filename\":\"%s\",\"purpose\":\"user_data\", \"bytes\": %d, \"mime_type\": \"application/pdf\", \"expires_after\": { \"anchor\": \"created_at\", \"seconds\": 3600 } }", filename, sz);
-
- httplib::Headers headers;
- headers.insert(std::make_pair("Authorization", std::string("Bearer ") + api_key));
-
- httplib::Result res = cli.Post("/v1/uploads", headers, body, "application/json");
- if (!res || res->status != 200) {
- logger::error("ERROR Failed to create upload.");
- logger::error(res->body.c_str());
- fclose(orig_file);
- return 0;
- }
-
- char upload_id[128];
- strops::get_json_value(res->body.c_str(), "id", upload_id, sizeof(upload_id));
- size_t part_size = 64000000; // 64mb
- logger::info("Created upload %s with part size %zu.", upload_id, part_size);
-
- char *buffer = (char*)memops::alloc(part_size);
-
- char completion_body[1048];
- strops::format(completion_body, sizeof(completion_body), "{\"part_ids\": [");
-
- int part_number = 0;
- while (1) {
- size_t read_bytes = fread(buffer, 1, part_size, orig_file);
- if (read_bytes == 0) break;
-
- httplib::Headers part_headers;
- part_headers.insert(std::make_pair("Authorization", std::string("Bearer ") + api_key));
-
- std::string chunk(buffer, read_bytes);
-
- httplib::UploadFormDataItems items = {
- {"data", chunk, filename, "application/octet-stream"}
- };
-
- char path[256];
- strops::format(path, sizeof(path), "/v1/uploads/%s/parts?part_number=%d", upload_id, part_number);
-
- httplib::Result part_res = cli.Post(path, part_headers, items);
-
- if (!part_res || part_res->status != 200) {
- logger::error("Failed to upload part %d.", part_number);
- logger::error(part_res->body.c_str());
- memops::unalloc(buffer);
- fclose(orig_file);
- return 0;
- }
- else {
- char part_id[128];
- strops::get_json_value(part_res->body.c_str(), "id", part_id, sizeof(part_id));
- if (part_number == 0) strops::format(completion_body+strops::length(completion_body), sizeof(completion_body)-strops::length(completion_body), "\"%s\"", part_id);
- if (part_number != 0) strops::format(completion_body+strops::length(completion_body), sizeof(completion_body)-strops::length(completion_body), ", \"%s\"", part_id);
- }
-
- logger::info("Uploaded part %d\n", part_number);
- part_number++;
- }
-
- strops::format(completion_body+strops::length(completion_body), sizeof(completion_body)-strops::length(completion_body), "]}");
-
- memops::unalloc(buffer);
- fclose(orig_file);
-
- // ---------- Step 3: Complete upload ----------
-
- httplib::Result complete_res = cli.Post((std::string("/v1/uploads/") + upload_id + "/complete").c_str(),
- headers, completion_body, "application/json");
-
-
- if (!complete_res || complete_res->status != 200) {
- logger::error("ERROR Failed to complete upload.");
- logger::error(complete_res->body.c_str());
- return 0;
- }
-
- char* completion_body_response = (char*)complete_res->body.c_str();
- strops::get_json_value(completion_body_response, "id", file_id, file_id_len, 1);
-
- return 1;
-}
-
-static bool _openAI_get_available_models(importer::model_list_request* buffer)
-{
- const char *api_key = administration::get_ai_service().api_key_public;
-
- httplib::SSLClient cli("api.openai.com", 443);
-
- httplib::Headers headers;
- headers.insert(std::make_pair("Authorization", std::string("Bearer ") + api_key));
-
- httplib::Result res = cli.Get("/v1/models", headers);
- if (!res || res->status != 200) {
- logger::error("ERROR Failed to get models list.");
- logger::error(res->body.c_str());
- return 0;
- }
-
- char* completion_body_response = (char*)res->body.c_str();
-
- u32 count = 0;
- char model_name[MAX_LEN_SHORT_DESC];
-
- while(1) {
- if (!strops::get_json_value(completion_body_response, "id", model_name, MAX_LEN_SHORT_DESC, count++)) break;
- if (count == MAX_MODEL_LIST_RESULT_COUNT) break;
-
- strops::copy(buffer->result[buffer->result_count++], model_name, MAX_LEN_SHORT_DESC);
- }
-
- return 1;
-}
-
-importer::ai_provider_impl _chatgpt_api_provider = {
- "OpenAI",
- "gpt-5-nano",
- _openAI_upload_file,
- _openAI_query_with_file,
- _openAI_batch_query_with_file,
- _openAI_get_available_models,
-}; \ No newline at end of file