diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/administration.cpp | 1 | ||||
| -rw-r--r-- | src/administration_reader.cpp | 1 | ||||
| -rw-r--r-- | src/administration_writer.cpp | 1 | ||||
| -rw-r--r-- | src/ai_providers/DeepSeek.cpp | 118 | ||||
| -rw-r--r-- | src/ai_providers/openAI.cpp | 1 | ||||
| -rw-r--r-- | src/import_service.cpp | 1 | ||||
| -rw-r--r-- | src/ui/ui_settings.cpp | 11 |
7 files changed, 126 insertions, 8 deletions
diff --git a/src/administration.cpp b/src/administration.cpp index 3be34da..a07e79a 100644 --- a/src/administration.cpp +++ b/src/administration.cpp @@ -528,6 +528,7 @@ void administration_create_income_statement(income_statement* statement) quarter.uncategorized_taxes = 0.0f; quarter.report_count = 0; quarter.is_empty = 1; + quarter.profit = 0.0f; snprintf(quarter.quarter_str, MAX_LEN_SHORT_DESC, "%dQ%d", quarter.quarter+1, quarter.year); project_count = administration_project_count(); diff --git a/src/administration_reader.cpp b/src/administration_reader.cpp index a72ba8a..e845e7c 100644 --- a/src/administration_reader.cpp +++ b/src/administration_reader.cpp @@ -410,7 +410,6 @@ bool administration_reader_import_administration_info(char* buffer, size_t buffe ai_service ai_service; ai_service.provider = (ai_provider)xml_get_s32_x(root, "AIService", "Provider", 0); xml_get_str_x(root, ai_service.api_key_public, MAX_LEN_API_KEY, "AIService", "PublicKey", 0); - xml_get_str_x(root, ai_service.api_key_private, MAX_LEN_API_KEY, "AIService", "PrivateKey", 0); administration_set_ai_service(ai_service); log_info("Loaded administration info in %.3fms. next_id=%d next_sequence_number=%d", diff --git a/src/administration_writer.cpp b/src/administration_writer.cpp index 8bcf741..0ac0b40 100644 --- a/src/administration_writer.cpp +++ b/src/administration_writer.cpp @@ -788,7 +788,6 @@ bool administration_writer_save_all_administration_info_blocking() ai_service ai_service = administration_get_ai_service(); strops_replace_int32(file_content, buf_length, "{{AI_SERVICE_PROVIDER}}", (s32)ai_service.provider); strops_replace(file_content, buf_length, "{{AI_SERVICE_PUBLIC_KEY}}", ai_service.api_key_public); - strops_replace(file_content, buf_length, "{{AI_SERVICE_PRIVATE_KEY}}", ai_service.api_key_private); //// Write to Disk. int final_length = (int)strlen(file_content); diff --git a/src/ai_providers/DeepSeek.cpp b/src/ai_providers/DeepSeek.cpp new file mode 100644 index 0000000..67d17c2 --- /dev/null +++ b/src/ai_providers/DeepSeek.cpp @@ -0,0 +1,118 @@ +/* +* 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. +*/ + +#define _CRT_SECURE_NO_WARNINGS + +#include <fstream> +#include <iostream> +#include <string> + +#define CPPHTTPLIB_OPENSSL_SUPPORT +#include "httplib.h" +#include "strops.hpp" +#include "log.hpp" +#include "import_service.hpp" + +#define QUERY_BUFFER_SIZE 1000000 + +char* query_buffer = 0; +static bool _DeepSeek_query_with_file(char* query, size_t query_length, char* file_id, char** response) +{ + 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); + //free(query); // TODO why?? + + size_t file_size = strlen(query_buffer); + sprintf(query_buffer + file_size, "%s", query); + + char* query_escaped = strops_prep_str_for_json(query_buffer, strlen(query_buffer)); + + size_t body_size = file_size + QUERY_BUFFER_SIZE; + char* body = (char*)malloc(body_size); + snprintf(body, body_size, + "{\"model\":\"deepseek-reasoner\", \"messages\": [ { \"role\": \"user\", \"content\": \"%s\" } ] }", 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"); + free(body); + + if (!res || res->status != 200) { + log_error("ERROR Failed to query API."); + log_error(res->body.c_str()); + return 0; + } + + char* response_body = (char*)res->body.c_str(); + *response = (char*)malloc(100000); + memset(*response, 0, 100000); + strncpy(*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) +{ + const char *filename = strops_get_filename(file_path); + + FILE* orig_file = fopen(file_path, "r"); + if (orig_file == NULL) { + log_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*)malloc(buffer_size); + memset(file_content_buffer, 0, 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; +} + +ai_provider_impl _deepseek_api_provider = { + _DeepSeek_upload_file, + _DeepSeek_query_with_file, +};
\ No newline at end of file diff --git a/src/ai_providers/openAI.cpp b/src/ai_providers/openAI.cpp index 7ebd680..20c1fa4 100644 --- a/src/ai_providers/openAI.cpp +++ b/src/ai_providers/openAI.cpp @@ -51,6 +51,7 @@ static bool _openAI_query_with_file(char* query, size_t query_length, char* file if (!res || res->status != 200) { log_error("ERROR Failed to query API."); + log_error(res->body.c_str()); return 0; } diff --git a/src/import_service.cpp b/src/import_service.cpp index 0aaa839..cff7fdb 100644 --- a/src/import_service.cpp +++ b/src/import_service.cpp @@ -36,6 +36,7 @@ ai_provider_impl _ai_get_impl() switch(provider) { case AI_PROVIDER_OPENAI: return _chatgpt_api_provider; + case AI_PROVIDER_DEEPSEEK: return _deepseek_api_provider; default: assert(0); break; } diff --git a/src/ui/ui_settings.cpp b/src/ui/ui_settings.cpp index 1f9fe5a..d7dfd4d 100644 --- a/src/ui/ui_settings.cpp +++ b/src/ui/ui_settings.cpp @@ -338,13 +338,15 @@ static void ui_draw_services() // AI service if (ImGui::CollapsingHeader(localize("settings.services.ai_service"))) { - char* services[1] = { - "OpenAI" + // TODO: get this from iterator over ai_get_impl + char* services[2] = { + "OpenAI", + "DeepSeek", }; if (ImGui::BeginCombo(localize("settings.services.ai_service.provider"), services[new_service.provider])) { - for (u32 n = 0; n < 1; n++) + for (u32 n = 0; n < 2; n++) { bool is_selected = n == (uint32_t)new_service.provider; if (ImGui::Selectable(services[n], is_selected)) { @@ -357,9 +359,6 @@ static void ui_draw_services() ImGui::InputTextWithHint(localize("settings.services.ai_service.pubkey"), localize("settings.services.ai_service.pubkey"), new_service.api_key_public, sizeof(new_service.api_key_public)); - ImGui::InputTextWithHint(localize("settings.services.ai_service.privkey"), localize("settings.services.ai_service.privkey"), - new_service.api_key_private, sizeof(new_service.api_key_private)); - if (ImGui::Button(localize("form.save"))) { administration_set_ai_service(new_service); } |
