From ebefd3d10af8d79e765030c263aa560cbb6420d2 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Sat, 25 Oct 2025 12:24:22 +0200 Subject: ai invoice importing with batch queries --- src/ai_providers/openAI.cpp | 78 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) (limited to 'src/ai_providers/openAI.cpp') diff --git a/src/ai_providers/openAI.cpp b/src/ai_providers/openAI.cpp index fa2cc05..64e7a6a 100644 --- a/src/ai_providers/openAI.cpp +++ b/src/ai_providers/openAI.cpp @@ -14,6 +14,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #define CPPHTTPLIB_OPENSSL_SUPPORT #include "httplib.h" @@ -22,9 +24,77 @@ #include "logger.hpp" #include "importer.hpp" +static bool _openAI_batch_query_with_file(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]; + + 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(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(char* query, size_t query_length, char* file_id, char** response) { - #if 1 const char *api_key = administration::get_ai_service().api_key_public; httplib::SSLClient cli("api.openai.com", 443); @@ -58,11 +128,6 @@ static bool _openAI_query_with_file(char* query, size_t query_length, char* file strops::get_json_value(*response, "text", *response, 100000); *response = strops::unprep_str_from_json(*response); - #else - *response = (char*)memops::alloc(100000); - memops::zero(*response, 100000); - strops::copy(*response, " urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 492043632 2024-09-01 2024-09-01 380 USD Final invoice do:team:67840ecb-44e2-472e-bc45-801bd4e1f1fe DigitalOcean LLC 101 Avenue of the Americas 2nd Floor New York 10013 NY US EU528002224 VAT DigitalOcean LLC My Team Keerderstraat 81 Maastricht 6226 XW LI NL VAT aldrikboy@gmail.com 492043632 3.49 15.60 3.28 VAT 1.00 0.21 VAT 16.60 16.60 20.09 20.09 1 16.60 false Discount Product Usage Charges Internal Tax Rate ID VAT ", 100000); - #endif return 1; } @@ -205,5 +270,6 @@ importer::ai_provider_impl _chatgpt_api_provider = { "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 -- cgit v1.2.3-70-g09d2