commit ab742e04f7f8c94b1c6144debaf24ffa59afc4cb Author: DESKTOP-PPVPOUR\CADNetwork Date: Thu Feb 15 19:07:22 2024 +0100 First commit. Most things still very temporary diff --git a/OpenAIManager/OpenAIManager.uplugin b/OpenAIManager/OpenAIManager.uplugin new file mode 100644 index 0000000..b2f9da5 --- /dev/null +++ b/OpenAIManager/OpenAIManager.uplugin @@ -0,0 +1,51 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "OpenAIManager", + "Description": "TBD", + "Category": "Other", + "CreatedBy": "Konstantin Meixner", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "CanContainContent": true, + "IsBetaVersion": false, + "IsExperimentalVersion": false, + "Installed": false, + "Modules": [ + { + "Name": "OpenAIManager", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ], + "Plugins": [ + { + "Name": "LowEntryHttpRequest", + "Enabled": true, + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/29d22bc9b02148d6bf6f57e1a0f660cc" + }, + { + "Name": "LowEntryJson", + "Enabled": true, + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/c108b5a8917c4c86873edf835237beab" + }, + { + "Name": "LowEntryFileManager", + "Enabled": true, + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/58edabbac7514311a4670c5d47a6fae6" + }, + { + "Name": "LowEntryExtStdLib", + "Enabled": true, + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/846c2ad08f164f45b0335ecebf85361e" + }, + { + "Name": "LowEntryEncryption", + "Enabled": true, + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/93647fb26bd14898b7ea63d4eefbf33a" + } + ] +} \ No newline at end of file diff --git a/OpenAIManager/Resources/Icon128.png b/OpenAIManager/Resources/Icon128.png new file mode 100644 index 0000000..1231d4a Binary files /dev/null and b/OpenAIManager/Resources/Icon128.png differ diff --git a/OpenAIManager/Source/OpenAIManager/OpenAIManager.Build.cs b/OpenAIManager/Source/OpenAIManager/OpenAIManager.Build.cs new file mode 100644 index 0000000..3f78d77 --- /dev/null +++ b/OpenAIManager/Source/OpenAIManager/OpenAIManager.Build.cs @@ -0,0 +1,57 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class OpenAIManager : ModuleRules +{ + public OpenAIManager(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + "LowEntryHttpRequest", + "LowEntryJson", + "LowEntryFileManager", + "LowEntryExtendedStandardLibrary" + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/OpenAIManager/Source/OpenAIManager/Private/OpenAIAPI.cpp b/OpenAIManager/Source/OpenAIManager/Private/OpenAIAPI.cpp new file mode 100644 index 0000000..6be601f --- /dev/null +++ b/OpenAIManager/Source/OpenAIManager/Private/OpenAIAPI.cpp @@ -0,0 +1,324 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "OpenAIAPI.h" + + +void UOpenAIAPI::SetAPIKey(FString Key) +{ + APIKey = Key; +} + +bool UOpenAIAPI::IsAPIKeySet() +{ + return !APIKey.IsEmpty(); +} +void UOpenAIAPI::CreateNewThread(FDelegateULowEntryHttpRequestOnComplete OnComplete) +{ + ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); + + // URL + Request->SetUrl(ELowEntryHttpRequestType::POST, "https://api.openai.com/v1/threads"); + + // Headers + Request->SetHeader("Authorization", "Bearer " + APIKey); + Request->SetHeader("Content-Type", "application/json"); + Request->SetHeader("OpenAI-Beta", "assistants=v1"); + + // Body + + // Execute + Request->ExecuteRequestEvent(OnComplete); +} + +void UOpenAIAPI::DeleteThread(FString ThreadId, FDelegateULowEntryHttpRequestOnComplete OnComplete) +{ + ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); + + // URL + Request->SetUrl(ELowEntryHttpRequestType::_DELETE, "https://api.openai.com/v1/threads/" + ThreadId); + + // Headers + Request->SetHeader("Authorization", "Bearer " + APIKey); + Request->SetHeader("Content-Type", "application/json"); + Request->SetHeader("OpenAI-Beta", "assistants=v1"); + + // Body + + // Execute + Request->ExecuteRequestEvent(OnComplete); +} + +void UOpenAIAPI::CreateMessage(FString Message, FString ThreadId, FDelegateULowEntryHttpRequestOnComplete OnComplete) +{ + ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); + + // URL + Request->SetUrl(ELowEntryHttpRequestType::POST, "https://api.openai.com/v1/threads/" + ThreadId + "/messages"); + + // Headers + Request->SetHeader("Authorization", "Bearer " + APIKey); + Request->SetHeader("Content-Type", "application/json"); + Request->SetHeader("OpenAI-Beta", "assistants=v1"); + + // Body + ULowEntryJsonObjectEntry *RoleEntry = ULowEntryJsonObjectEntry::CreateFromString("role", "user"); + ULowEntryJsonObjectEntry *ContentEntry = ULowEntryJsonObjectEntry::CreateFromString("content", Message); + ULowEntryJsonObject* ContentJsonObject = ULowEntryJsonObject::Create( { RoleEntry, ContentEntry } ); + FString ContentJsonString = ULowEntryJsonObject::ToJsonString(ContentJsonObject); + Request->SetContentAsJsonString(ContentJsonString); + + // Execute + Request->ExecuteRequestEvent(OnComplete); +} + +void UOpenAIAPI::CreateRun(FString ThreadId, FString AssistantId, FString ModelId, FDelegateULowEntryHttpRequestOnComplete OnComplete) +{ + ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); + + // URL + Request->SetUrl(ELowEntryHttpRequestType::POST, "https://api.openai.com/v1/threads/" + ThreadId + "/runs"); + + // Headers + Request->SetHeader("Authorization", "Bearer " + APIKey); + Request->SetHeader("Content-Type", "application/json"); + Request->SetHeader("OpenAI-Beta", "assistants=v1"); + + // Body + ULowEntryJsonObjectEntry *AssistantIdEntry = ULowEntryJsonObjectEntry::CreateFromString("assistant_id", AssistantId); + //ULowEntryJsonObjectEntry *ModelEntry = ULowEntryJsonObjectEntry::CreateFromString("model", ModelId); + ULowEntryJsonObject* ContentJsonObject = ULowEntryJsonObject::Create( { AssistantIdEntry } ); + FString ContentJsonString = ULowEntryJsonObject::ToJsonString(ContentJsonObject); + Request->SetContentAsJsonString(ContentJsonString); + + // Execute + Request->ExecuteRequestEvent(OnComplete); +} + +void UOpenAIAPI::GetRun(FString ThreadId, FString RunId, FDelegateULowEntryHttpRequestOnComplete OnComplete) +{ + ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); + + // URL + Request->SetUrl(ELowEntryHttpRequestType::GET, "https://api.openai.com/v1/threads/" + ThreadId + "/runs/" + RunId); + + // Headers + Request->SetHeader("Authorization", "Bearer " + APIKey); + Request->SetHeader("Content-Type", "application/json"); + Request->SetHeader("OpenAI-Beta", "assistants=v1"); + + // Body + + // Execute + Request->ExecuteRequestEvent(OnComplete); +} + +void UOpenAIAPI::GetAllMessages(FString ThreadId, FDelegateULowEntryHttpRequestOnComplete OnComplete) +{ + ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); + + // URL + Request->SetUrl(ELowEntryHttpRequestType::GET, "https://api.openai.com/v1/threads/" + ThreadId + "/messages"); + + // Headers + Request->SetHeader("Authorization", "Bearer " + APIKey); + Request->SetHeader("Content-Type", "application/json"); + Request->SetHeader("OpenAI-Beta", "assistants=v1"); + + // Body + + // Execute + Request->ExecuteRequestEvent(OnComplete); +} + + +//void UOpenAIAPI::ListAllDocuments() +//{ +// ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); +// +// // URL +// Request->SetUrl(ELowEntryHttpRequestType::GET, "https://api.openai.com/v1/files"); +// +// // Headers +// Request->SetHeader("Authorization", "Bearer " + APIKey); +// +// // Body +// +// // Execute +// FDelegateULowEntryHttpRequestOnComplete OnComplete; +// OnComplete.BindUFunction(this, "OnListAllDocumentsComplete"); +// Request->ExecuteRequestEvent(OnComplete); +//} +// +//void UOpenAIAPI::OnListAllDocumentsComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnListAllDocumentsCompleteDelegate.Broadcast(Response); +//} +// +//void UOpenAIAPI::ShowFile(FString DefaultFile) +//{ +// ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); +// +// // URL +// Request->SetUrl(ELowEntryHttpRequestType::GET, "https://api.openai.com/v1/files/" + DefaultFile); +// +// // Headers +// Request->SetHeader("Authorization", "Bearer " + APIKey); +// +// // Body +// +// // Execute +// FDelegateULowEntryHttpRequestOnComplete OnComplete; +// OnComplete.BindUFunction(this, "OnShowFileComplete"); +// Request->ExecuteRequestEvent(OnComplete); +//} +// +//void UOpenAIAPI::OnShowFileComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnShowFileCompleteDelegate.Broadcast(Response); +//} +// +//void UOpenAIAPI::DeleteFile(FString Id) +//{ +// ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); +// +// // URL +// Request->SetUrl(ELowEntryHttpRequestType::_DELETE, "https://api.openai.com/v1/files/" + Id); +// +// // Headers +// Request->SetHeader("Authorization", "Bearer " + APIKey); +// +// // Body +// +// // Execute +// FDelegateULowEntryHttpRequestOnComplete OnComplete; +// OnComplete.BindUFunction(this, "OnDeleteFileComplete"); +// Request->ExecuteRequestEvent(OnComplete); +//} +// +//void UOpenAIAPI::OnDeleteFileComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnDeleteFileCompleteDelegate.Broadcast(Response); +//} +// +//void UOpenAIAPI::UploadFile(TArray Content) +//{ +// ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); +// +// // URL +// Request->SetUrl(ELowEntryHttpRequestType::POST, "https://api.openai.com/v1/files"); +// +// // Headers +// Request->SetHeader("Authorization", "Bearer " + APIKey); +// +// // Body +// Request->SetContentAsMultipartParameters("purpose", "answers", "", ""); +// Request->SetContentAsMultipartParametersBytes("file", Content, "", "dynamicUpload.json"); +// +// // Execute +// FDelegateULowEntryHttpRequestOnComplete OnComplete; +// OnComplete.BindUFunction(this, "OnUploadFileComplete"); +// Request->ExecuteRequestEvent(OnComplete); +//} +// +//void UOpenAIAPI::OnUploadFileComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnUploadFileCompleteDelegate.Broadcast(Response); +//} +// +// +//// This should call deletefile in a loop after +//void UOpenAIAPI::RemoveAllDocuments() +//{ +// ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); +// +// // URL +// Request->SetUrl(ELowEntryHttpRequestType::GET, "https://api.openai.com/v1/files"); +// +// // Headers +// Request->SetHeader("Authorization", "Bearer " + APIKey); +// +// // Body +// +// // Execute +// FDelegateULowEntryHttpRequestOnComplete OnComplete; +// OnComplete.BindUFunction(this, "OnRemoveAllDocumentsComplete"); +// Request->ExecuteRequestEvent(OnComplete); +//} +// +//void UOpenAIAPI::OnRemoveAllDocumentsComplete(ULowEntryHttpRequestResponse* Response) +//{ +// // Parse the response and call deletefile for each file +//} +// + +// +//void UOpenAIAPI::OnCreateNewThreadComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnCreateNewThreadCompleteDelegate.Broadcast(Response); +//} +// + +// +//void UOpenAIAPI::OnDeleteThreadComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnDeleteThreadCompleteDelegate.Broadcast(Response); +//} +// +// +// +//void UOpenAIAPI::OnCreateMessageComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnCreateMessageCompleteDelegate.Broadcast(Response); +//} +// +// +// +//void UOpenAIAPI::OnCreateRunComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnCreateRunCompleteDelegate.Broadcast(Response); +//} +// + +// +//void UOpenAIAPI::OnGetRunComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnGetRunCompleteDelegate.Broadcast(Response); +//} +// + +// +//void UOpenAIAPI::OnGetAllMessagesComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnGetAllMessagesCompleteDelegate.Broadcast(Response); +//} +// +//void UOpenAIAPI::ListAssistants() +//{ +// FColor BaseColor; +// FColor HighlightColor; +// int GraphHeight = 0; +// int i = 0; +// ULowEntryHttpRequest* Request = ULowEntryHttpRequest::Create(); +// +// // URL +// Request->SetUrl(ELowEntryHttpRequestType::GET, "https://api.openai.com/v1/assistants"); +// +// // Headers +// Request->SetHeader("Authorization", "Bearer " + APIKey); +// Request->SetHeader("Content-Type", "application/json"); +// Request->SetHeader("OpenAI-Beta", "assistants=v1"); +// +// // Body +// +// // Execute +// FDelegateULowEntryHttpRequestOnComplete OnComplete; +// OnComplete.BindUFunction(this, "OnListAssistantsComplete"); +// +// Request->ExecuteRequestEvent(OnComplete); +//} +// +//void UOpenAIAPI::OnListAssistantsComplete(ULowEntryHttpRequestResponse* Response) +//{ +// OnListAssistantsCompleteDelegate.Broadcast(Response); +//} diff --git a/OpenAIManager/Source/OpenAIManager/Private/OpenAIManager.cpp b/OpenAIManager/Source/OpenAIManager/Private/OpenAIManager.cpp new file mode 100644 index 0000000..87191f9 --- /dev/null +++ b/OpenAIManager/Source/OpenAIManager/Private/OpenAIManager.cpp @@ -0,0 +1,20 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "OpenAIManager.h" + +#define LOCTEXT_NAMESPACE "FOpenAIManagerModule" + +void FOpenAIManagerModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module +} + +void FOpenAIManagerModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FOpenAIManagerModule, OpenAIManager) \ No newline at end of file diff --git a/OpenAIManager/Source/OpenAIManager/Private/OpenAIManagerSystem.cpp b/OpenAIManager/Source/OpenAIManager/Private/OpenAIManagerSystem.cpp new file mode 100644 index 0000000..3b80d6f --- /dev/null +++ b/OpenAIManager/Source/OpenAIManager/Private/OpenAIManagerSystem.cpp @@ -0,0 +1,347 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "OpenAIManagerSystem.h" + +UOpenAIAPI* UOpenAIManagerSystem::OpenAI; +bool UOpenAIManagerSystem::IsBusy = false; +FString UOpenAIManagerSystem::ActiveThread = ""; +UOpenAIManagerSystem* UOpenAIManagerSystem::Self; +FString UOpenAIManagerSystem::CurrentAssistant = ""; +FString UOpenAIManagerSystem::CurrentRun = ""; + + +FOnOpenAIErrorMulticastDelegate UOpenAIManagerSystem::OnError; +FOpenAIDelegate UOpenAIManagerSystem::OnAIReadyDelegate; +FOpenAIDelegate UOpenAIManagerSystem::OnThreadDeletedDelegate; +FOnOpenAIResponseReceivedDelegate UOpenAIManagerSystem::OnResponseReceived; + + +void UOpenAIManagerSystem::Initialize(FSubsystemCollectionBase& Collection) +{ + OpenAI = NewObject(); + OpenAI->AddToRoot(); + Self = this; +} + +void UOpenAIManagerSystem::Deinitialize() +{ + OpenAI->RemoveFromRoot(); + OpenAI = nullptr; +} + +void UOpenAIManagerSystem::SetAPIKey(FString Key) +{ + OpenAI->SetAPIKey(Key); +} + + +void UOpenAIManagerSystem::SetAssistant(FString Assistant) +{ + CurrentAssistant = Assistant; + +} + +void UOpenAIManagerSystem::BindOnError(FOnOpenAIErrorDelegate Delegate) +{ + OnError.Add(Delegate); +} + + +void UOpenAIManagerSystem::RemoveAllFromOnError() +{ + OnError.Clear(); +} + +void UOpenAIManagerSystem::ListAssistants(FOnOpenAIErrorDelegate test) +{ + if (!OpenAI->IsAPIKeySet()) + { + OnError.Broadcast("API Key is not set"); + return; + } + //OpenAI->OnListAssistantsCompleteDelegate.Add(test); + //OpenAI->ListAssistants(); + //OpenAI->OnListAssistantsCompleteDelegate.Remove(test); +} + + +void UOpenAIManagerSystem::RemoveFromOnError(FOnOpenAIErrorDelegate Delegate) +{ + OnError.Remove(Delegate); +} + +UOpenAIAPI* UOpenAIManagerSystem::GetOpenAI_API() +{ + return OpenAI; +} + + +void UOpenAIManagerSystem::InitializeThread(FOpenAIDelegate Delegate) +{ + if (IsBusy) + { + OnError.Broadcast("Unable to initialize thread: System is busy"); + return; + } + if (!OpenAI->IsAPIKeySet()) + { + OnError.Broadcast("Unable to initialize thread: API Key is not set"); + return; + } + if (CurrentAssistant.IsEmpty()) + { + OnError.Broadcast("Unable to initialize thread: Assistant is not set"); + return; + } + OnAIReadyDelegate = Delegate; + IsBusy = true; + FDelegateULowEntryHttpRequestOnComplete OnComplete; + OnComplete.BindUFunction(Self, "OnThreadCreated"); + OpenAI->CreateNewThread(OnComplete); +} + +void UOpenAIManagerSystem::OnThreadCreated(ULowEntryHttpRequestResponse* Response) +{ + if (!(Response->GetResponseCode() == 200)) + { + OnError.Broadcast("Unable to create thread: " + Response->GetContentAsString()); + return; + } + + FString JsonString = Response->GetContentAsString(); + ULowEntryJsonObject* JsonObject = ULowEntryJsonObject::Create(); + ULowEntryJsonArray* JsonArray = ULowEntryJsonArray::Create(); + ELowEntryJsonParseResult ParseStatus; + + // get the response as json object + ULowEntryJsonLibrary::Json_ParseJsonString(JsonString, JsonObject, JsonArray, ParseStatus); + + if (ParseStatus == ELowEntryJsonParseResult::StringIsEmpty) + { + OnError.Broadcast("Unable to create thread: Response string is empty"); + return; + } + + if (ParseStatus == ELowEntryJsonParseResult::UnableToParse) + { + OnError.Broadcast("Unable to create thread: Unable to parse"); + return; + } + ELowEntryJsonValueAndTypeFound SearchStatus; + ActiveThread = ULowEntryJsonObject::GetString(JsonObject, "id", SearchStatus); + if (SearchStatus != ELowEntryJsonValueAndTypeFound::Success) + { + OnError.Broadcast("Unable to create thread: Unable to find id"); + return; + } + IsBusy = false; + OnAIReadyDelegate.ExecuteIfBound(); + OnAIReadyDelegate.Clear(); +} + +void UOpenAIManagerSystem::DeleteActiveThread(FOpenAIDelegate Delegate) +{ + if (IsBusy) + { + OnError.Broadcast("Unable to delete thread: System is busy"); + return; + } + if (!OpenAI->IsAPIKeySet()) + { + OnError.Broadcast("Unable to delete thread: API Key is not set"); + return; + } + if (ActiveThread.IsEmpty()) + { + OnError.Broadcast("Unable to delete thread: No active Thread"); + return; + } + OnThreadDeletedDelegate = Delegate; + IsBusy = true; + FDelegateULowEntryHttpRequestOnComplete OnComplete; + OnComplete.BindUFunction(Self, "OnThreadDeleted"); + OpenAI->DeleteThread(ActiveThread, OnComplete); +} + +void UOpenAIManagerSystem::OnThreadDeleted(ULowEntryHttpRequestResponse* Response) +{ + if (!(Response->GetResponseCode() == 200)) + { + OnError.Broadcast("Unable to delete thread: " + Response->GetContentAsString()); + return; + } + ActiveThread = ""; + IsBusy = false; + OnThreadDeletedDelegate.ExecuteIfBound(); + OnThreadDeletedDelegate.Clear(); +} + + +void UOpenAIManagerSystem::AskQuestion(FString Message, FOnOpenAIResponseReceivedDelegate Delegate) +{ + if (IsBusy) + { + OnError.Broadcast("Unable to create message: System is busy"); + return; + } + if (!OpenAI->IsAPIKeySet()) + { + OnError.Broadcast("Unable to create message: API Key is not set!"); + return; + } + if (CurrentAssistant.IsEmpty()) + { + OnError.Broadcast("Unable to create message: Assistant is not set!"); + return; + } + if (ActiveThread.IsEmpty()) + { + OnError.Broadcast("Unable to create message: Thread is not set!"); + return; + } + + OnResponseReceived = Delegate; + IsBusy = true; + FDelegateULowEntryHttpRequestOnComplete OnComplete; + OnComplete.BindUFunction(Self, "OnMessageCreated"); + OpenAI->CreateMessage(Message, ActiveThread, OnComplete); + +} + +void UOpenAIManagerSystem::OnMessageCreated(ULowEntryHttpRequestResponse* Response) +{ + if (!(Response->GetResponseCode() == 200)) + { + OnError.Broadcast("Creating message failed: " + Response->GetContentAsString()); + return; + } + FDelegateULowEntryHttpRequestOnComplete OnComplete; + OnComplete.BindUFunction(Self, "OnRunCreated"); + OpenAI->CreateRun(ActiveThread, CurrentAssistant, "davinci", OnComplete); +} + +void UOpenAIManagerSystem::OnRunCreated(ULowEntryHttpRequestResponse* Response) +{ + if (!(Response->GetResponseCode() == 200)) + { + OnError.Broadcast("Creating run failed: " + Response->GetContentAsString()); + return; + } + FString JsonString = Response->GetContentAsString(); + ULowEntryJsonObject* JsonObject = ULowEntryJsonObject::Create(); + ULowEntryJsonArray* JsonArray = ULowEntryJsonArray::Create(); + ELowEntryJsonParseResult ParseStatus; + + ULowEntryJsonLibrary::Json_ParseJsonString(JsonString, JsonObject, JsonArray, ParseStatus); + + if (ParseStatus == ELowEntryJsonParseResult::StringIsEmpty) + { + OnError.Broadcast("Checking run failed: Response string is empty"); + return; + } + + if (ParseStatus == ELowEntryJsonParseResult::UnableToParse) + { + OnError.Broadcast("Checking run failed: Unable to parse"); + return; + } + ELowEntryJsonValueAndTypeFound SearchStatus; + CurrentRun = ULowEntryJsonObject::GetString(JsonObject, "id", SearchStatus); + if (SearchStatus != ELowEntryJsonValueAndTypeFound::Success) + { + OnError.Broadcast("Checking run failed: Unable to find id"); + return; + } + FDelegateULowEntryHttpRequestOnComplete OnComplete; + OnComplete.BindUFunction(Self, "OnRunChecked"); + OpenAI->GetRun(ActiveThread, CurrentRun, OnComplete); +} + +void UOpenAIManagerSystem::OnRunChecked(ULowEntryHttpRequestResponse* Response) +{ + if (!(Response->GetResponseCode() == 200)) + { + OnError.Broadcast("Checking run failed: " + Response->GetContentAsString()); + return; + } + FString JsonString = Response->GetContentAsString(); + ULowEntryJsonObject* JsonObject = ULowEntryJsonObject::Create(); + ULowEntryJsonArray* JsonArray = ULowEntryJsonArray::Create(); + ELowEntryJsonParseResult ParseStatus; + + // get the response as json object + ULowEntryJsonLibrary::Json_ParseJsonString(JsonString, JsonObject, JsonArray, ParseStatus); + + if (ParseStatus == ELowEntryJsonParseResult::StringIsEmpty) + { + OnError.Broadcast("Checking run failed: Response string is empty"); + return; + } + + if (ParseStatus == ELowEntryJsonParseResult::UnableToParse) + { + OnError.Broadcast("Checking run failed: Unable to parse"); + return; + } + ELowEntryJsonValueAndTypeFound SearchStatus; + FString Status = ULowEntryJsonObject::GetString(JsonObject, "status", SearchStatus); + if (SearchStatus != ELowEntryJsonValueAndTypeFound::Success) + { + OnError.Broadcast("Checking run failed: Unable to find status"); + return; + } + if (Status == "completed") + { + //OnError.Broadcast("Run completed!"); + FDelegateULowEntryHttpRequestOnComplete OnComplete; + OnComplete.BindUFunction(Self, "OnAllMessagesReceived"); + OpenAI->GetAllMessages(ActiveThread, OnComplete); + } + else + { + OnError.Broadcast("Run not yet completed, checking again.."); + FPlatformProcess::Sleep(1); + FDelegateULowEntryHttpRequestOnComplete OnComplete; + OnComplete.BindUFunction(Self, "OnRunChecked"); + OpenAI->GetRun(ActiveThread, CurrentRun, OnComplete); + } +} + +void UOpenAIManagerSystem::OnAllMessagesReceived(ULowEntryHttpRequestResponse* Response) +{ + if (!(Response->GetResponseCode() == 200)) + { + OnError.Broadcast("Getting all messages failed: " + Response->GetContentAsString()); + return; + } + FString JsonString = Response->GetContentAsString(); + ULowEntryJsonObject* JsonObject = ULowEntryJsonObject::Create(); + ULowEntryJsonArray* JsonArray = ULowEntryJsonArray::Create(); + ELowEntryJsonParseResult ParseStatus; + + // get the response as json object + ULowEntryJsonLibrary::Json_ParseJsonString(JsonString, JsonObject, JsonArray, ParseStatus); + + if (ParseStatus == ELowEntryJsonParseResult::StringIsEmpty) + { + OnError.Broadcast("Getting all messages failed: Response string is empty"); + return; + } + + if (ParseStatus == ELowEntryJsonParseResult::UnableToParse) + { + OnError.Broadcast("Getting all messages failed: Unable to parse"); + return; + } + ELowEntryJsonValueAndTypeFound SearchStatus; + ULowEntryJsonArray* DataArray = ULowEntryJsonObject::GetJsonArray(JsonObject, "data", SearchStatus); + ULowEntryJsonObject* FirstElement = ULowEntryJsonArray::GetJsonObject(DataArray, 0, SearchStatus); + ULowEntryJsonArray* ContentArray = ULowEntryJsonObject::GetJsonArray(FirstElement, "content", SearchStatus); + ULowEntryJsonObject* FirstElementAgain = ULowEntryJsonArray::GetJsonObject(ContentArray, 0, SearchStatus); + ULowEntryJsonObject* ResponseJsonText = ULowEntryJsonObject::GetJsonObject(FirstElementAgain, "text", SearchStatus); + FString ResponseString = ULowEntryJsonObject::GetString(ResponseJsonText, "value", SearchStatus); + IsBusy = false; + OnResponseReceived.ExecuteIfBound(ResponseString); + OnResponseReceived.Clear(); +} \ No newline at end of file diff --git a/OpenAIManager/Source/OpenAIManager/Public/OpenAIAPI.h b/OpenAIManager/Source/OpenAIManager/Public/OpenAIAPI.h new file mode 100644 index 0000000..7e95f17 --- /dev/null +++ b/OpenAIManager/Source/OpenAIManager/Public/OpenAIAPI.h @@ -0,0 +1,111 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" + +#include "LowEntryHttpRequest.h" +#include "LowEntryHttpRequestLibrary.h" +#include "LowEntryHttpRequestResponse.h" +#include "LowEntryJsonLibrary.h" +#include "LowEntryJsonObject.h" +#include "LowEntryJsonObjectEntry.h" +#include "LowEntryFileManagerLibrary.h" +#include "LowEntryExtendedStandardLibrary.h" + +#include "OpenAIAPI.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnRequestCompleteMulticastDelegate, ULowEntryHttpRequestResponse*, Response); + +//DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnListAssistantsComplete); + +/** + * + */ +UCLASS() +class OPENAIMANAGER_API UOpenAIAPI : public UObject +{ + GENERATED_BODY() + +protected: + FString APIKey; + +public: + + void SetAPIKey(FString Key); + bool IsAPIKeySet(); + + void CreateNewThread(FDelegateULowEntryHttpRequestOnComplete OnComplete); + void DeleteThread(FString ThreadId, FDelegateULowEntryHttpRequestOnComplete OnComplete); + void CreateMessage(FString Message, FString ThreadId, FDelegateULowEntryHttpRequestOnComplete OnComplete); + void CreateRun(FString ThreadId, FString AssistantId, FString ModelId, FDelegateULowEntryHttpRequestOnComplete OnComplete); + void GetRun(FString ThreadId, FString RunId, FDelegateULowEntryHttpRequestOnComplete OnComplete); + void GetAllMessages(FString ThreadId, FDelegateULowEntryHttpRequestOnComplete OnComplete); + + /*UFUNCTION() + void OnCreateNewThreadComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnCreateNewThreadCompleteDelegate;*/ + /*void ListAllDocuments(); + UFUNCTION() + void OnListAllDocumentsComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnListAllDocumentsCompleteDelegate; + + void ShowFile(FString DefaultFile); + UFUNCTION() + void OnShowFileComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnShowFileCompleteDelegate; + + void DeleteFile(FString Id); + UFUNCTION() + void OnDeleteFileComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnDeleteFileCompleteDelegate; + + void UploadFile(TArray Content); + UFUNCTION() + void OnUploadFileComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnUploadFileCompleteDelegate; + + void RemoveAllDocuments(); + UFUNCTION() + void OnRemoveAllDocumentsComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnRemoveAllDocumentsCompleteDelegate; + + UFUNCTION() + void OnDeleteThreadComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnDeleteThreadCompleteDelegate; + + void CreateMessage(FString Message, FString ThreadId); + UFUNCTION() + void OnCreateMessageComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnCreateMessageCompleteDelegate; + + UFUNCTION() + void OnCreateRunComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnCreateRunCompleteDelegate; + + UFUNCTION() + void OnGetRunComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnGetRunCompleteDelegate; + + UFUNCTION() + void OnGetAllMessagesComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnGetAllMessagesCompleteDelegate; + + void ListAssistants(); + UFUNCTION() + void OnListAssistantsComplete(ULowEntryHttpRequestResponse* Response); + UPROPERTY(BlueprintAssignable, Category = "OpenAIAPI") + FOnRequestCompleteMulticastDelegate OnListAssistantsCompleteDelegate;*/ +}; diff --git a/OpenAIManager/Source/OpenAIManager/Public/OpenAIManager.h b/OpenAIManager/Source/OpenAIManager/Public/OpenAIManager.h new file mode 100644 index 0000000..a87a941 --- /dev/null +++ b/OpenAIManager/Source/OpenAIManager/Public/OpenAIManager.h @@ -0,0 +1,15 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +class FOpenAIManagerModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; diff --git a/OpenAIManager/Source/OpenAIManager/Public/OpenAIManagerSystem.h b/OpenAIManager/Source/OpenAIManager/Public/OpenAIManagerSystem.h new file mode 100644 index 0000000..0430d37 --- /dev/null +++ b/OpenAIManager/Source/OpenAIManager/Public/OpenAIManagerSystem.h @@ -0,0 +1,97 @@ +// Fill out your copyright notice in the Description page of Project Settings. + +#pragma once + +#include "CoreMinimal.h" +#include "Subsystems/GameInstanceSubsystem.h" +#include "OpenAIAPI.h" + +#include "LowEntryHttpRequest.h" +#include "LowEntryHttpRequestLibrary.h" +#include "LowEntryHttpRequestResponse.h" +#include "LowEntryJsonLibrary.h" +#include "LowEntryJsonObject.h" +#include "LowEntryJsonObjectEntry.h" +#include "LowEntryFileManagerLibrary.h" +#include "LowEntryExtendedStandardLibrary.h" +#include "LowEntryJsonArray.h" + +#include "OpenAIManagerSystem.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnOpenAIErrorMulticastDelegate, FString, ErrorMessage); +DECLARE_DYNAMIC_DELEGATE_OneParam(FOnOpenAIErrorDelegate, FString, ErrorMessage); +DECLARE_DYNAMIC_DELEGATE_OneParam(FOnOpenAIResponseReceivedDelegate, FString, Response); +DECLARE_DYNAMIC_DELEGATE(FOpenAIDelegate); +/** + * + */ +UCLASS() +class OPENAIMANAGER_API UOpenAIManagerSystem : public UGameInstanceSubsystem +{ + GENERATED_BODY() + + static UOpenAIManagerSystem* Self; + static FOnOpenAIErrorMulticastDelegate OnError; + static UOpenAIAPI* OpenAI; + static FString CurrentAssistant; + static FString ActiveThread; + static FString CurrentRun; + +public: + static bool IsBusy; + virtual void Initialize(FSubsystemCollectionBase& Collection) override; + virtual void Deinitialize() override; + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void SetAPIKey(FString Key); + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void SetAssistant(FString Assistant); + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void BindOnError(FOnOpenAIErrorDelegate Delegate); + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void RemoveFromOnError(FOnOpenAIErrorDelegate Delegate); + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void RemoveAllFromOnError(); + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void ListAssistants(FOnOpenAIErrorDelegate test); + + + + + UFUNCTION(BlueprintPure, Category = "OpenAI") + static UOpenAIAPI *GetOpenAI_API(); + + UFUNCTION(BlueprintPure, Category = "OpenAI") + static FString getActiveThread() { return ActiveThread; } + + + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void InitializeThread(FOpenAIDelegate Delegate); + UFUNCTION() + void OnThreadCreated(ULowEntryHttpRequestResponse *Response); + static FOpenAIDelegate OnAIReadyDelegate; + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void DeleteActiveThread(FOpenAIDelegate Delegate); + UFUNCTION() + void OnThreadDeleted(ULowEntryHttpRequestResponse* Response); + static FOpenAIDelegate OnThreadDeletedDelegate; + + UFUNCTION(BlueprintCallable, Category = "OpenAI") + static void AskQuestion(FString Message, FOnOpenAIResponseReceivedDelegate OnResponse); + UFUNCTION() + void OnMessageCreated(ULowEntryHttpRequestResponse* Response); + UFUNCTION() + void OnRunCreated(ULowEntryHttpRequestResponse* Response); + UFUNCTION() + void OnRunChecked(ULowEntryHttpRequestResponse* Response); + UFUNCTION() + void OnAllMessagesReceived(ULowEntryHttpRequestResponse* Response); + static FOnOpenAIResponseReceivedDelegate OnResponseReceived; +}; \ No newline at end of file