#include "ANSLLM.h" #include #include #include #include #include #include static bool ansllmLicenceValid = false; static std::once_flag ansllmLicenseOnceFlag; namespace ANSCENTER { static void VerifyGlobalANSLMLicense(const std::string& licenseKey) { try { static const std::vector> licenseChecks = { {1000, "ANNHUB-LV"}, {1001, "DLHUB-LV"}, {1002, "ODHUB-LV"}, {1003, "ANSVIS"}, {1004, "ANSFR"}, {1005, "ANSOCR"}, {1006, "ANSALPR"}, {1007, "ANSCV"}, {1008, "ANSSRT"} }; ansllmLicenceValid = false; for (const auto& [productId, productName] : licenseChecks) { if (ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, productId, productName)) { ansllmLicenceValid = true; break; // Stop at the first valid license } } } catch (const std::exception& e) { ansllmLicenceValid = false; } } ANSLLM::ANSLLM() { _unlockCode = "ANSDRC.CB1122026_MEQCIFwO1IFQCG0BhZwsXFO68QUU6mDB5uge4duOsqOJanEyAiAB67ahqnXin4SRy0vIegISgbFlpldmbuS5gbU21GYVqA==";// "ANSDRC.CB1082025_Ax6P3M7F8B3d";// } ANSLLM::~ANSLLM() noexcept = default; void ANSLLM::CheckLicense() { std::lock_guard lock(_mutex); try { // Check once globally std::call_once(ansllmLicenseOnceFlag, [this]() { VerifyGlobalANSLMLicense(_licenseKey); }); // Update this instance's local license flag _isLicenseValid = ansllmLicenceValid; } catch (const std::exception& e) { this->_logger.LogFatal("ANSLLM::CheckLicense. Error:", e.what(), __FILE__, __LINE__); } } void ANSLLM::CheckUnlockCode() { std::lock_guard lock(_mutex); try { CkGlobal glob; _unlockCode = "ANSDRC.CB1122026_MEQCIFwO1IFQCG0BhZwsXFO68QUU6mDB5uge4duOsqOJanEyAiAB67ahqnXin4SRy0vIegISgbFlpldmbuS5gbU21GYVqA==";// "ANSDRC.CB1082025_Ax6P3M7F8B3d"; _isUnlockCodeValid = glob.UnlockBundle(_unlockCode.c_str()); if (!_isUnlockCodeValid) { _logger.LogFatal("ANSLLM::CheckUnlockCode", glob.lastErrorText(), __FILE__, __LINE__); return; } int status = glob.get_UnlockStatus(); if (status != 2) { _logger.LogDebug("ANSLLM::CheckUnlockCode", "Unlocked in trial mode.", __FILE__, __LINE__); } } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::CheckUnlockCode", e.what(), __FILE__, __LINE__); } } bool ANSLLM::Initialize(const std::string& licenseKey, bool localLLM) { std::lock_guard lock(_mutex); try { _licenseKey = licenseKey; _localLLM = localLLM; CheckLicense(); CheckUnlockCode(); if (_localLLM) { // Auto-configure for local Ollama: use custom provider with ChatCompletions API spec // Must use "custom" — setting "openai" resets BaseUrl to api.openai.com ai.put_Provider("custom"); ai.put_ApiSpec("ChatCompletions"); ai.put_BaseUrl(_ollamaBaseUrl.c_str()); ai.put_ApiKey("ollama"); // Ollama doesn't require a real API key _logger.LogDebug("ANSLLM::Initialize", "Configured for local Ollama at " + _ollamaBaseUrl, __FILE__, __LINE__); } return _isLicenseValid && _isUnlockCodeValid; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::Initialize", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetLLMProvider(const std::string& llmProvider) { if (llmProvider.empty()) return false; std::lock_guard lock(_mutex); try { ai.put_Provider(llmProvider.c_str()); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetLLMProvider", e.what(), __FILE__, __LINE__); return false; } } std::string ANSLLM::GetLLMProvider() { std::lock_guard lock(_mutex); try { CkString str; ai.get_Provider(str); const char* cstr = str.getString(); return (cstr != nullptr) ? std::string(cstr) : std::string(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetLLMProvider", e.what(), __FILE__, __LINE__); return ""; } } bool ANSLLM::SetApiKey(const std::string& apiKey) { if (apiKey.empty()) return false; std::lock_guard lock(_mutex); try { ai.put_ApiKey(apiKey.c_str()); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetApiKey", e.what(), __FILE__, __LINE__); return false; } } std::vector ANSLLM::GetModelList() { std::lock_guard lock(_mutex); std::vector modelList; try { CkStringTable st; if (!ai.GetModels(st)) { const char* errText = ai.lastErrorText(); const std::string errorMsg = (errText != nullptr) ? errText : "Unknown error"; _logger.LogError("ANSLLM::GetModelList", "Failed to get models: " + errorMsg, __FILE__, __LINE__); return modelList; } const int count = st.get_Count(); if (count <= 0) { return modelList; } modelList.reserve(static_cast(count)); for (int i = 0; i < count; ++i) { const char* modelName = st.stringAt(i); if (modelName != nullptr && modelName[0] != '\0') { modelList.emplace_back(modelName); } } return modelList; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetModelList", std::string("Exception: ") + e.what(), __FILE__, __LINE__); return modelList; } catch (...) { _logger.LogFatal("ANSLLM::GetModelList", "Unknown exception occurred", __FILE__, __LINE__); return modelList; } } bool ANSLLM::SetModel(const std::string& modelName) { if (modelName.empty()) return false; std::lock_guard lock(_mutex); try { ai.put_Model(modelName.c_str()); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetModel", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetTranscriptMode(bool transcriptMode) { std::lock_guard lock(_mutex); try { ai.put_FullTranscript(transcriptMode); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetTranscriptMode", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::InputAddText(const std::string& inputText) { if (inputText.empty()) return false; std::lock_guard lock(_mutex); try { ai.InputAddText(inputText.c_str()); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::InputAddText", e.what(), __FILE__, __LINE__); return false; } } std::string ANSLLM::Ask(const std::string& prompt) { if (prompt.empty()) return ""; std::lock_guard lock(_mutex); try { // Ask the AI for text output. bool success = ai.Ask(prompt.c_str()); if (success == false) { const char* errText = ai.lastErrorText(); return (errText != nullptr) ? std::string(errText) : std::string("Unknown error"); } // Get the text response. CkStringBuilder sbResponse; ai.GetOutputTextSb(sbResponse); const char* cstr = sbResponse.getAsString(); return (cstr != nullptr) ? std::string(cstr) : std::string(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::Ask", e.what(), __FILE__, __LINE__); return ""; } } bool ANSLLM::CreateConversation(const std::string& systemMessage, const std::string& developerMessage, const std::string& conversationName) { if (systemMessage.empty() || developerMessage.empty() || conversationName.empty()) { return false; } std::lock_guard lock(_mutex); try { return ai.NewConvo(conversationName.c_str(), systemMessage.c_str(), developerMessage.c_str()); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::CreateConversation", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetConversation(const std::string& conversationName) { if (conversationName.empty()) return false; std::lock_guard lock(_mutex); try { ai.put_SelectedConvo(conversationName.c_str()); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetConversation", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::InputAddImageUrl(const std::string& imageURL, const std::string& summary) { if (imageURL.empty()) return false; std::lock_guard lock(_mutex); try { return ai.InputAddImageUrl(imageURL.c_str(), summary.c_str()); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::InputAddImageUrl", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::InputAddImageFromPath(const std::string& filePath, const char* summary) { if (filePath.empty()) return false; std::lock_guard lock(_mutex); try { CkBinData bd; bool success = bd.LoadFile(filePath.c_str()); if (!success) { const char* errText = bd.lastErrorText(); _logger.LogError("ANSLLM::InputAddImageFromPath", (errText != nullptr) ? errText : "Failed to load file", __FILE__, __LINE__); return false; } return ai.InputAddImageData(bd, summary); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::InputAddImageFromPath", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::InputAddImageFromBase64(const std::string& jpegBase64String, const char* summary) { if (jpegBase64String.empty()) return false; std::lock_guard lock(_mutex); try { CkBinData bd; // Load base64 encoded JPEG data into CkBinData bool success = bd.AppendEncoded(jpegBase64String.c_str(), "base64"); if (!success) { _logger.LogError("ANSLLM::InputAddImage", bd.lastErrorText(), __FILE__, __LINE__); return false; } return ai.InputAddImageData(bd, summary); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::InputAddImage", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::InputAddFileData(const std::string& filePath, const char* summary) { if (filePath.empty()) return false; std::lock_guard lock(_mutex); try { CkBinData bd; bool success = bd.LoadFile(filePath.c_str()); if (!success) { const char* errText = bd.lastErrorText(); _logger.LogError("ANSLLM::InputAddFileData", (errText != nullptr) ? errText : "Failed to load file", __FILE__, __LINE__); return false; } return ai.InputAddImageData(bd, summary); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::InputAddFileData", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::InputAddFileURL(const std::string& fileURL, const char* summary) { if (fileURL.empty()) return false; std::lock_guard lock(_mutex); try { return ai.InputAddFileUrl(fileURL.c_str(), summary); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::InputAddFileURL", e.what(), __FILE__, __LINE__); return false; } } // Extra methods bool ANSLLM::ClearInputs() { std::lock_guard lock(_mutex); try { ai.InputClear(); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::ClearInputs", e.what(), __FILE__, __LINE__); return false; } } std::vector ANSLLM::GetConversationList() { std::lock_guard lock(_mutex); std::vector convList; try { CkStringTable st; if (!ai.ListConvos(st)) { const char* errText = ai.lastErrorText(); const std::string errorMsg = (errText != nullptr) ? errText : "Unknown error"; _logger.LogError("ANSLLM::GetConversationList", "Failed to get conversations: " + errorMsg, __FILE__, __LINE__); return convList; } const int count = st.get_Count(); if (count <= 0) { return convList; } convList.reserve(static_cast(count)); for (int i = 0; i < count; ++i) { const char* convName = st.stringAt(i); if (convName != nullptr && convName[0] != '\0') { convList.emplace_back(convName); } } return convList; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetConversationList", e.what(), __FILE__, __LINE__); return {}; } } bool ANSLLM::DeleteConversation(const std::string& conversationName) { if (conversationName.empty()) return false; std::lock_guard lock(_mutex); try { return ai.DeleteConvo(conversationName.c_str()); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::DeleteConversation", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetUTF8(bool b) { std::lock_guard lock(_mutex); try { ai.put_Utf8(b); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetUTF8", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::GetUTF8() { std::lock_guard lock(_mutex); try { return ai.get_Utf8(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetUTF8", e.what(), __FILE__, __LINE__); return false; } } int ANSLLM::PollAi(bool abort) { std::lock_guard lock(_mutex); try { return ai.PollAi(abort); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::PollAi", e.what(), __FILE__, __LINE__); return -1; } } bool ANSLLM::SetLocalLLM(bool localLLM) { std::lock_guard lock(_mutex); try { _localLLM = localLLM; if (_localLLM) { ai.put_Provider("custom"); ai.put_ApiSpec("ChatCompletions"); ai.put_BaseUrl(_ollamaBaseUrl.c_str()); ai.put_ApiKey("ollama"); _logger.LogDebug("ANSLLM::SetLocalLLM", "Configured for local Ollama at " + _ollamaBaseUrl, __FILE__, __LINE__); } return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetLocalLLM", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetOllamaBaseUrl(const std::string& baseUrl) { if (baseUrl.empty()) return false; std::lock_guard lock(_mutex); try { _ollamaBaseUrl = baseUrl; if (_localLLM) { ai.put_BaseUrl(_ollamaBaseUrl.c_str()); } return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetOllamaBaseUrl", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetBaseURL(const std::string& baseURL) { std::lock_guard lock(_mutex); try { ai.put_BaseUrl(baseURL.c_str()); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetBaseURL", e.what(), __FILE__, __LINE__); return false; } } int ANSLLM::GetHeartbeatMs() { std::lock_guard lock(_mutex); try { return ai.get_HeartbeatMs(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetHeartbeatMs", e.what(), __FILE__, __LINE__); return -1; } } bool ANSLLM::SetHeartbeatMs(int heartbeatMs) { std::lock_guard lock(_mutex); try { ai.put_HeartbeatMs(heartbeatMs); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetHeartbeatMs", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::GetHostedConversation() { std::lock_guard lock(_mutex); try { return ai.get_HostedConvo(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetHostedConversation", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetHostedConversation(bool hostedConversation) { std::lock_guard lock(_mutex); try { ai.put_HostedConvo(hostedConversation); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetHostedConversation", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::GetStreamingMode() { std::lock_guard lock(_mutex); try { return ai.get_Streaming(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetStreamingMode", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetStreamingMode(bool streamingMode) { std::lock_guard lock(_mutex); try { ai.put_Streaming(streamingMode); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetStreamingMode", e.what(), __FILE__, __LINE__); return false; } } int ANSLLM::GetIdleTimeoutMs() { std::lock_guard lock(_mutex); try { return ai.get_IdleTimeoutMs(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetIdleTimeoutMs", e.what(), __FILE__, __LINE__); return -1; } } bool ANSLLM::SetIdleTimeoutMs(int idleTimeoutMs) { std::lock_guard lock(_mutex); try { ai.put_IdleTimeoutMs(idleTimeoutMs); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetIdleTimeoutMs", e.what(), __FILE__, __LINE__); return false; } } std::string ANSLLM::GetLastErrorMessage() { std::lock_guard lock(_mutex); try { const char* errorText = ai.lastErrorText(); return (errorText != nullptr) ? std::string(errorText) : std::string(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetLastErrorMessage", e.what(), __FILE__, __LINE__); return e.what(); } } std::string ANSLLM::GetOutputText() { std::lock_guard lock(_mutex); try { CkString str; ai.GetOutputText(str); const char* cstr = str.getString(); return (cstr != nullptr) ? std::string(cstr) : std::string(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetOutputText", e.what(), __FILE__, __LINE__); return ""; } } std::string ANSLLM::GetOutputTextSb() { std::lock_guard lock(_mutex); try { CkStringBuilder sb; ai.GetOutputTextSb(sb); const char* cstr = sb.getAsString(); return (cstr != nullptr) ? std::string(cstr) : std::string(); } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::GetOutputTextSb", e.what(), __FILE__, __LINE__); return ""; } } bool ANSLLM::SetSleepMs(int sleepMs) { std::lock_guard lock(_mutex); try { ai.SleepMs(sleepMs); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetSleepMs", e.what(), __FILE__, __LINE__); return false; } } bool ANSLLM::SetAskParams(double temperature) { std::lock_guard lock(_mutex); try { CkJsonObject obj; std::string strTemp = std::to_string(temperature); obj.UpdateString("temperature", strTemp.c_str()); ai.SetAskParams(obj); return true; } catch (const std::exception& e) { _logger.LogFatal("ANSLLM::SetAskParams", e.what(), __FILE__, __LINE__); return false; } } }