From 7c3a271feea4b3693bf93a47924f7c682585e179 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Sat, 27 Dec 2025 17:25:41 +0100 Subject: mail provider settings ui --- src/ai_providers/DeepSeek.cpp | 120 ------------------ src/ai_providers/openAI.cpp | 276 ------------------------------------------ 2 files changed, 396 deletions(-) delete mode 100644 src/ai_providers/DeepSeek.cpp delete mode 100644 src/ai_providers/openAI.cpp (limited to 'src/ai_providers') diff --git a/src/ai_providers/DeepSeek.cpp b/src/ai_providers/DeepSeek.cpp deleted file mode 100644 index c34e299..0000000 --- a/src/ai_providers/DeepSeek.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* -* Copyright (c) 2025 Aldrik Ramaekers -* -* 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. -*/ - -#define CPPHTTPLIB_OPENSSL_SUPPORT -#include "httplib.h" -#include "strops.hpp" -#include "memops.hpp" -#include "logger.hpp" -#include "importer.hpp" - -#define QUERY_BUFFER_SIZE 1000000 - -char* query_buffer = 0; -static bool _DeepSeek_query_with_file(const char* query, size_t query_length, char* file_id, char** response) -{ - (void)file_id; - (void)query_length; - assert(query_buffer); - - const char *api_key = administration::get_ai_service().api_key_public; - - httplib::SSLClient cli("api.deepseek.com"); - //cli.enable_server_certificate_verification(false); - - //char* query_escaped = strops::prep_str_for_json(query, query_length); - //memops::unalloc(query); // TODO why?? - - size_t file_size = strops::length(query_buffer); - sprintf(query_buffer + file_size, "%s", query); - - char* query_escaped = strops::prep_str_for_json(query_buffer, strops::length(query_buffer)); - - size_t body_size = file_size + QUERY_BUFFER_SIZE; - char* body = (char*)memops::alloc(body_size); - strops::format(body, body_size, - "{\"model\":\"%s\", \"messages\": [ { \"role\": \"user\", \"content\": \"%s\" } ] }", administration::get_ai_service().model_name, query_escaped); - - httplib::Headers headers; - headers.insert(std::make_pair("Authorization", std::string("Bearer ") + api_key)); - headers.insert(std::make_pair("Content-Type", "application/json")); - headers.insert(std::make_pair("Accept", "application/json")); - - httplib::Result res = cli.Post("/chat/completions", 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, "content", *response, 100000); - *response = strops::unprep_str_from_json(*response); - - return 1; -} - -static bool _DeepSeek_upload_file(char* file_path, char* file_id, size_t file_id_len) -{ - (void)file_id; - (void)file_id_len; - const char *filename = strops::get_filename(file_path); - - FILE* orig_file = fopen(file_path, "r"); - 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); - - size_t buffer_size = sz + QUERY_BUFFER_SIZE; - char* file_content_buffer = (char*)memops::alloc(buffer_size); - memops::zero(file_content_buffer, buffer_size); - - query_buffer = file_content_buffer; - - file_content_buffer += sprintf(file_content_buffer, "[file name]: %s\n", filename); - file_content_buffer += sprintf(file_content_buffer, "[file content begin]\n"); - - fread(file_content_buffer, sz, 1, orig_file); - file_content_buffer += sz; - - for (int i = 0; i < file_content_buffer-query_buffer; i++) if (query_buffer[i] <= 0x1f) query_buffer[i] = ' '; - - file_content_buffer += sprintf(file_content_buffer, "\n[file content end]\n"); - file_content_buffer[0] = 0; - - fclose(orig_file); - - return 1; -} - -importer::ai_provider_impl _deepseek_api_provider = { - "DeekSeek", - "deepseek-reasoner", - _DeepSeek_upload_file, - _DeepSeek_query_with_file, - 0, -}; \ No newline at end of file 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 -* -* 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 - -#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(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 -- cgit v1.2.3-70-g09d2