From 1f3b7df61c8709189fde9d540bbc6e496b694e7b Mon Sep 17 00:00:00 2001 From: lucoiso Date: Sun, 20 Aug 2023 19:08:40 +0100 Subject: [PATCH 1/3] Hotfix: Move include to header to fix UE5.0 package --- .../HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.cpp | 1 - .../HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.cpp b/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.cpp index 28f7584..dc1c092 100644 --- a/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.cpp +++ b/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.cpp @@ -3,7 +3,6 @@ // Repo: https://github.com/lucoiso/UEHttpGPT #include "HttpGPTMessagingHandler.h" -#include #include #include diff --git a/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.h b/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.h index 7d87131..d4bab7a 100644 --- a/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.h +++ b/Source/HttpGPTEditorModule/Private/Chat/HttpGPTMessagingHandler.h @@ -6,6 +6,7 @@ #include #include +#include #include "HttpGPTMessagingHandler.generated.h" DECLARE_DELEGATE_OneParam(FMessageContentUpdated, FString); From d59a1cb32eddea044abf9aa66ab5ecc9910db852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Vilas-B=C3=B4as?= Date: Mon, 28 Aug 2023 21:38:27 +0100 Subject: [PATCH 2/3] First steps w/ function calling + Custom Endpoint + Fix editor chat first initialization --- .../Private/Tasks/HttpGPTChatRequest.cpp | 66 ++++++++++++++--- .../Public/Tasks/HttpGPTChatRequest.h | 17 ++--- .../Private/Management/HttpGPTSettings.cpp | 3 + .../Private/Structures/HttpGPTChatTypes.cpp | 59 ++++++++++++++-- .../Private/Structures/HttpGPTCommonTypes.cpp | 3 + .../Private/Tasks/HttpGPTBaseTask.cpp | 4 ++ .../Private/Utils/HttpGPTHelper.cpp | 70 +++++++++++++++++-- .../Public/Structures/HttpGPTChatTypes.h | 68 +++++++++++++++++- .../Public/Structures/HttpGPTCommonTypes.h | 9 +++ .../Public/Utils/HttpGPTHelper.h | 8 ++- .../Private/Chat/SHttpGPTChatShell.cpp | 5 ++ .../Private/Tasks/HttpGPTImageRequest.cpp | 9 ++- 12 files changed, 288 insertions(+), 33 deletions(-) diff --git a/Source/HttpGPTChatModule/Private/Tasks/HttpGPTChatRequest.cpp b/Source/HttpGPTChatModule/Private/Tasks/HttpGPTChatRequest.cpp index 49513f2..79b6eb1 100644 --- a/Source/HttpGPTChatModule/Private/Tasks/HttpGPTChatRequest.cpp +++ b/Source/HttpGPTChatModule/Private/Tasks/HttpGPTChatRequest.cpp @@ -29,34 +29,35 @@ #if WITH_EDITOR UHttpGPTChatRequest* UHttpGPTChatRequest::EditorTask(const TArray& Messages, const FHttpGPTChatOptions Options) { - UHttpGPTChatRequest* const NewAsyncTask = SendMessages_CustomOptions(GEditor->GetEditorWorldContext().World(), Messages, FHttpGPTCommonOptions(), Options); + UHttpGPTChatRequest* const NewAsyncTask = SendMessages_CustomOptions(GEditor->GetEditorWorldContext().World(), Messages, TArray(), FHttpGPTCommonOptions(), Options); NewAsyncTask->bIsEditorTask = true; return NewAsyncTask; } #endif -UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessage_DefaultOptions(UObject* const WorldContextObject, const FString& Message) +UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessage_DefaultOptions(UObject* const WorldContextObject, const FString& Message, const TArray& Functions) { - return SendMessage_CustomOptions(WorldContextObject, Message, FHttpGPTCommonOptions(), FHttpGPTChatOptions()); + return SendMessage_CustomOptions(WorldContextObject, Message, Functions, FHttpGPTCommonOptions(), FHttpGPTChatOptions()); } -UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessages_DefaultOptions(UObject* const WorldContextObject, const TArray& Messages) +UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessages_DefaultOptions(UObject* const WorldContextObject, const TArray& Messages, const TArray& Functions) { - return SendMessages_CustomOptions(WorldContextObject, Messages, FHttpGPTCommonOptions(), FHttpGPTChatOptions()); + return SendMessages_CustomOptions(WorldContextObject, Messages, Functions, FHttpGPTCommonOptions(), FHttpGPTChatOptions()); } -UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessage_CustomOptions(UObject* const WorldContextObject, const FString& Message, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions) +UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessage_CustomOptions(UObject* const WorldContextObject, const FString& Message, const TArray& Functions, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions) { - return SendMessages_CustomOptions(WorldContextObject, { FHttpGPTChatMessage(EHttpGPTChatRole::User, Message) }, CommonOptions, ChatOptions); + return SendMessages_CustomOptions(WorldContextObject, { FHttpGPTChatMessage(EHttpGPTChatRole::User, Message) }, Functions, CommonOptions, ChatOptions); } -UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessages_CustomOptions(UObject* const WorldContextObject, const TArray& Messages, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions) +UHttpGPTChatRequest* UHttpGPTChatRequest::SendMessages_CustomOptions(UObject* const WorldContextObject, const TArray& Messages, const TArray& Functions, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions) { UHttpGPTChatRequest* const NewAsyncTask = NewObject(); NewAsyncTask->Messages = Messages; NewAsyncTask->CommonOptions = CommonOptions; NewAsyncTask->ChatOptions = ChatOptions; + NewAsyncTask->Functions = Functions; NewAsyncTask->RegisterWithGameInstance(WorldContextObject); @@ -86,7 +87,7 @@ bool UHttpGPTChatRequest::CanBindProgress() const FString UHttpGPTChatRequest::GetEndpointURL() const { - return FString::Format(TEXT("https://api.openai.com/{0}"), { UHttpGPTHelper::GetEndpointForModel(GetChatOptions().Model).ToString() }); + return FString::Format(TEXT("{0}/{1}"), { GetCommonOptions().Endpoint, UHttpGPTHelper::GetEndpointForModel(GetChatOptions().Model, GetCommonOptions().bIsAzureOpenAI, GetCommonOptions().AzureOpenAIAPIVersion) }); } const FHttpGPTChatOptions UHttpGPTChatRequest::GetChatOptions() const @@ -153,6 +154,17 @@ FString UHttpGPTChatRequest::SetRequestContent() } JsonRequest->SetArrayField("messages", MessagesJson); + + if (!Functions.IsEmpty()) + { + TArray> FunctionsJson; + for (const FHttpGPTFunction& Iterator : Functions) + { + FunctionsJson.Add(Iterator.GetFunction()); + } + + JsonRequest->SetArrayField("functions", FunctionsJson); + } } else { @@ -352,18 +364,50 @@ void UHttpGPTChatRequest::DeserializeSingleResponse(const FString& Content) if (const TSharedPtr* MessageObj; ChoiceObj->TryGetObjectField("message", MessageObj)) { - Choice->Message = FHttpGPTChatMessage(*(*MessageObj)->GetStringField("role"), *(*MessageObj)->GetStringField("content")); + if (FString RoleStr; (*MessageObj)->TryGetStringField("role", RoleStr)) + { + Choice->Message.Role = RoleStr == "user" ? EHttpGPTChatRole::User : EHttpGPTChatRole::Assistant; + } + + if (FString ContentStr; (*MessageObj)->TryGetStringField("content", ContentStr)) + { + Choice->Message.Content = ContentStr; + } + + if (const TSharedPtr* FunctionObj; (*MessageObj)->TryGetObjectField("function_call", FunctionObj)) + { + if (FString FunctionNameStr; (*FunctionObj)->TryGetStringField("name", FunctionNameStr)) + { + Choice->Message.FunctionCall.Name = *FunctionNameStr; + } + if (FString FunctionArgumentsStr; (*FunctionObj)->TryGetStringField("arguments", FunctionArgumentsStr)) + { + Choice->Message.FunctionCall.Arguments = FunctionArgumentsStr; + } + } } else if (const TSharedPtr* DeltaObj; ChoiceObj->TryGetObjectField("delta", DeltaObj)) { if (FString RoleStr; (*DeltaObj)->TryGetStringField("role", RoleStr)) { - Choice->Message.Role = RoleStr == "user" ? EHttpGPTChatRole::User : EHttpGPTChatRole::Assistant; + Choice->Message.Role = UHttpGPTHelper::NameToRole(*RoleStr); } else if (FString ContentStr; (*DeltaObj)->TryGetStringField("content", ContentStr)) { Choice->Message.Content += ContentStr; } + + if (const TSharedPtr* FunctionObj; (*DeltaObj)->TryGetObjectField("function_call", FunctionObj)) + { + if (FString FunctionNameStr; (*FunctionObj)->TryGetStringField("name", FunctionNameStr)) + { + Choice->Message.FunctionCall.Name = *FunctionNameStr; + } + if (FString FunctionArgumentsStr; (*FunctionObj)->TryGetStringField("arguments", FunctionArgumentsStr)) + { + Choice->Message.FunctionCall.Arguments += FunctionArgumentsStr; + } + } } else if (FString MessageText; ChoiceObj->TryGetStringField("text", MessageText)) { diff --git a/Source/HttpGPTChatModule/Public/Tasks/HttpGPTChatRequest.h b/Source/HttpGPTChatModule/Public/Tasks/HttpGPTChatRequest.h index 745b5b8..9a19147 100644 --- a/Source/HttpGPTChatModule/Public/Tasks/HttpGPTChatRequest.h +++ b/Source/HttpGPTChatModule/Public/Tasks/HttpGPTChatRequest.h @@ -38,23 +38,24 @@ class HTTPGPTCHATMODULE_API UHttpGPTChatRequest : public UHttpGPTBaseTask static UHttpGPTChatRequest* EditorTask(const TArray& Messages, const FHttpGPTChatOptions Options); #endif - UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Default", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Message with Default Options")) - static UHttpGPTChatRequest* SendMessage_DefaultOptions(UObject* const WorldContextObject, const FString& Message); + UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Default", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Message with Default Options", AutoCreateRefTerm = "Functions")) + static UHttpGPTChatRequest* SendMessage_DefaultOptions(UObject* const WorldContextObject, const FString& Message, const TArray& Functions); - UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Default", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Messages with Default Options")) - static UHttpGPTChatRequest* SendMessages_DefaultOptions(UObject* const WorldContextObject, const TArray& Messages); + UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Default", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Messages with Default Options", AutoCreateRefTerm = "Functions")) + static UHttpGPTChatRequest* SendMessages_DefaultOptions(UObject* const WorldContextObject, const TArray& Messages, const TArray& Functions); - UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Custom", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Message with Custom Options")) - static UHttpGPTChatRequest* SendMessage_CustomOptions(UObject* const WorldContextObject, const FString& Message, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions); + UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Custom", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Message with Custom Options", AutoCreateRefTerm = "Functions")) + static UHttpGPTChatRequest* SendMessage_CustomOptions(UObject* const WorldContextObject, const FString& Message, const TArray& Functions, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions); - UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Custom", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Messages with Custom Options")) - static UHttpGPTChatRequest* SendMessages_CustomOptions(UObject* const WorldContextObject, const TArray& Messages, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions); + UFUNCTION(BlueprintCallable, Category = "HttpGPT | Chat | Custom", meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject", DisplayName = "Send Messages with Custom Options", AutoCreateRefTerm = "Functions")) + static UHttpGPTChatRequest* SendMessages_CustomOptions(UObject* const WorldContextObject, const TArray& Messages, const TArray& Functions, const FHttpGPTCommonOptions CommonOptions, const FHttpGPTChatOptions ChatOptions); UFUNCTION(BlueprintPure, Category = "HttpGPT | Chat") const FHttpGPTChatOptions GetChatOptions() const; protected: TArray Messages; + TArray Functions; FHttpGPTChatOptions ChatOptions; virtual bool CanActivateTask() const override; diff --git a/Source/HttpGPTCommonModule/Private/Management/HttpGPTSettings.cpp b/Source/HttpGPTCommonModule/Private/Management/HttpGPTSettings.cpp index 0369457..b2006be 100644 --- a/Source/HttpGPTCommonModule/Private/Management/HttpGPTSettings.cpp +++ b/Source/HttpGPTCommonModule/Private/Management/HttpGPTSettings.cpp @@ -84,6 +84,9 @@ void UHttpGPTSettings::SetToDefaults() { CommonOptions.APIKey = NAME_None; CommonOptions.User = NAME_None; + CommonOptions.bIsAzureOpenAI = false; + CommonOptions.Endpoint = TEXT("https://api.openai.com/"); + CommonOptions.AzureOpenAIAPIVersion = TEXT("2023-05-15"); ChatOptions.Model = EHttpGPTChatModel::gpt35turbo; ChatOptions.MaxTokens = 2048; diff --git a/Source/HttpGPTCommonModule/Private/Structures/HttpGPTChatTypes.cpp b/Source/HttpGPTCommonModule/Private/Structures/HttpGPTChatTypes.cpp index 8a41628..4b37439 100644 --- a/Source/HttpGPTCommonModule/Private/Structures/HttpGPTChatTypes.cpp +++ b/Source/HttpGPTCommonModule/Private/Structures/HttpGPTChatTypes.cpp @@ -11,17 +11,66 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(HttpGPTChatTypes) #endif -FHttpGPTChatMessage::FHttpGPTChatMessage(const FName& Role, const FString& Content) +TSharedPtr FHttpGPTFunction::GetFunction() const { - this->Role = UHttpGPTHelper::NameToRole(Role); - this->Content = Content; + TSharedPtr JsonObject = MakeShared(); + JsonObject->SetStringField("name", Name.ToString()); + JsonObject->SetStringField("description", Description); + + TSharedPtr ParametersObject = MakeShared(); + ParametersObject->SetStringField("type", "object"); + + TSharedPtr PropertiesObject = MakeShared(); + for (const FHttpGPTFunctionProperty& PropIt : Properties) + { + TSharedPtr PropertyObject = MakeShared(); + PropertyObject->SetStringField("type", UHttpGPTHelper::PropertyTypeToName(PropIt.Type).ToString().ToLower()); + PropertyObject->SetStringField("description", PropIt.Description); + + TArray> EnumArr; + for (const FName& EnumIt : PropIt.Enum) + { + EnumArr.Emplace(MakeShared(EnumIt.ToString())); + } + PropertyObject->SetArrayField("enum", EnumArr); + + PropertiesObject->SetObjectField(PropIt.Name.ToString(), PropertyObject); + } + + ParametersObject->SetObjectField("properties", PropertiesObject); + + TArray> RequiredParams; + for (const FName& ReqIt : RequiredProperties) + { + RequiredParams.Emplace(MakeShared(ReqIt.ToString())); + } + + ParametersObject->SetArrayField("required", RequiredParams); + JsonObject->SetObjectField("parameters", ParametersObject); + + return MakeShared(JsonObject); +} + +FHttpGPTChatMessage::FHttpGPTChatMessage(const FName& InRole, const FString& InContent) +{ + Role = UHttpGPTHelper::NameToRole(InRole); + Content = InContent; } TSharedPtr FHttpGPTChatMessage::GetMessage() const { TSharedPtr JsonObject = MakeShared(); JsonObject->SetStringField("role", UHttpGPTHelper::RoleToName(Role).ToString().ToLower()); - JsonObject->SetStringField("content", Content); + + if (Role == EHttpGPTChatRole::Function) + { + JsonObject->SetStringField("name", FunctionCall.Name.ToString()); + JsonObject->SetStringField("content", FunctionCall.Arguments); + } + else + { + JsonObject->SetStringField("content", Content); + } return MakeShared(JsonObject); } @@ -46,4 +95,4 @@ void FHttpGPTChatOptions::SetDefaults() FrequencyPenalty = Settings->ChatOptions.FrequencyPenalty; LogitBias = Settings->ChatOptions.LogitBias; } -} \ No newline at end of file +} diff --git a/Source/HttpGPTCommonModule/Private/Structures/HttpGPTCommonTypes.cpp b/Source/HttpGPTCommonModule/Private/Structures/HttpGPTCommonTypes.cpp index ffcdb5a..ad8e59a 100644 --- a/Source/HttpGPTCommonModule/Private/Structures/HttpGPTCommonTypes.cpp +++ b/Source/HttpGPTCommonModule/Private/Structures/HttpGPTCommonTypes.cpp @@ -20,5 +20,8 @@ void FHttpGPTCommonOptions::SetDefaults() { APIKey = Settings->CommonOptions.APIKey; User = Settings->CommonOptions.User; + bIsAzureOpenAI = Settings->CommonOptions.bIsAzureOpenAI; + Endpoint = Settings->CommonOptions.Endpoint; + AzureOpenAIAPIVersion = Settings->CommonOptions.AzureOpenAIAPIVersion; } } \ No newline at end of file diff --git a/Source/HttpGPTCommonModule/Private/Tasks/HttpGPTBaseTask.cpp b/Source/HttpGPTCommonModule/Private/Tasks/HttpGPTBaseTask.cpp index 9e56ea0..b863331 100644 --- a/Source/HttpGPTCommonModule/Private/Tasks/HttpGPTBaseTask.cpp +++ b/Source/HttpGPTCommonModule/Private/Tasks/HttpGPTBaseTask.cpp @@ -32,6 +32,10 @@ void UHttpGPTBaseTask::Activate() UE_LOG(LogHttpGPT, Display, TEXT("%s (%d): Activating task"), *FString(__func__), GetUniqueID()); bIsTaskActive = true; + if (!CommonOptions.Endpoint.EndsWith(TEXT("/"))) + { + CommonOptions.Endpoint += TEXT("/"); + } if (!CanActivateTask()) { diff --git a/Source/HttpGPTCommonModule/Private/Utils/HttpGPTHelper.cpp b/Source/HttpGPTCommonModule/Private/Utils/HttpGPTHelper.cpp index 1acd253..10bb711 100644 --- a/Source/HttpGPTCommonModule/Private/Utils/HttpGPTHelper.cpp +++ b/Source/HttpGPTCommonModule/Private/Utils/HttpGPTHelper.cpp @@ -86,6 +86,12 @@ const FName UHttpGPTHelper::RoleToName(const EHttpGPTChatRole Role) case EHttpGPTChatRole::System: return "system"; + + case EHttpGPTChatRole::Function: + return "function"; + + default: + break; } return NAME_None; @@ -105,10 +111,52 @@ const EHttpGPTChatRole UHttpGPTHelper::NameToRole(const FName Role) { return EHttpGPTChatRole::System; } + else if (Role.IsEqual("function", ENameCase::IgnoreCase)) + { + return EHttpGPTChatRole::Function; + } return EHttpGPTChatRole::User; } +const FName UHttpGPTHelper::PropertyTypeToName(const EHttpGPTPropertyType Type) +{ + switch (Type) + { + case EHttpGPTPropertyType::Boolean: + return "bool"; + + case EHttpGPTPropertyType::Number: + return "number"; + + case EHttpGPTPropertyType::String: + return "string"; + + default: + break; + } + + return NAME_None; +} + +const EHttpGPTPropertyType UHttpGPTHelper::NameToPropertyType(const FName Type) +{ + if (Type.IsEqual("bool", ENameCase::IgnoreCase)) + { + return EHttpGPTPropertyType::Boolean; + } + else if (Type.IsEqual("number", ENameCase::IgnoreCase)) + { + return EHttpGPTPropertyType::Number; + } + else if (Type.IsEqual("string", ENameCase::IgnoreCase)) + { + return EHttpGPTPropertyType::String; + } + + return EHttpGPTPropertyType::Boolean; +} + const TArray UHttpGPTHelper::GetAvailableGPTModels() { TArray Output; @@ -124,7 +172,7 @@ const TArray UHttpGPTHelper::GetAvailableGPTModels() return Output; } -const FName UHttpGPTHelper::GetEndpointForModel(const EHttpGPTChatModel Model) +const FString UHttpGPTHelper::GetEndpointForModel(const EHttpGPTChatModel Model, const bool bIsAzureOpenAI, const FString& AzureOpenAIAPIVersion) { switch (Model) { @@ -132,17 +180,31 @@ const FName UHttpGPTHelper::GetEndpointForModel(const EHttpGPTChatModel Model) case EHttpGPTChatModel::gpt432k: case EHttpGPTChatModel::gpt35turbo: case EHttpGPTChatModel::gpt35turbo16k: - return "v1/chat/completions"; + if (bIsAzureOpenAI) + { + return FString::Format(TEXT("/openai/deployments/{0}/chat/completions?api-version={1}"), { ModelToName(Model).ToString(), AzureOpenAIAPIVersion }); + } + else + { + return "v1/chat/completions"; + } case EHttpGPTChatModel::textdavinci003: case EHttpGPTChatModel::textdavinci002: case EHttpGPTChatModel::codedavinci002: - return "v1/completions"; + if (bIsAzureOpenAI) + { + return FString::Format(TEXT("/openai/deployments/{0}/completions?api-version={1}"), { ModelToName(Model).ToString(), AzureOpenAIAPIVersion }); + } + else + { + return "v1/completions"; + } default: break; } - return NAME_None; + return FString(); } const bool UHttpGPTHelper::ModelSupportsChat(const EHttpGPTChatModel Model) diff --git a/Source/HttpGPTCommonModule/Public/Structures/HttpGPTChatTypes.h b/Source/HttpGPTCommonModule/Public/Structures/HttpGPTChatTypes.h index a2b30a1..1eb892e 100644 --- a/Source/HttpGPTCommonModule/Public/Structures/HttpGPTChatTypes.h +++ b/Source/HttpGPTCommonModule/Public/Structures/HttpGPTChatTypes.h @@ -11,12 +11,71 @@ #include "Structures/HttpGPTCommonTypes.h" #include "HttpGPTChatTypes.generated.h" +UENUM(BlueprintType, Category = "HttpGPT | Chat", Meta = (DisplayName = "HttpGPT Property Type")) +enum class EHttpGPTPropertyType : uint8 +{ + Number, + Boolean, + String +}; + +USTRUCT(BlueprintType, Category = "HttpGPT | Chat", Meta = (DisplayName = "HttpGPT Function Parameter")) +struct HTTPGPTCOMMONMODULE_API FHttpGPTFunctionProperty +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Name")) + FName Name; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Type")) + EHttpGPTPropertyType Type; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Description")) + FString Description; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Enum")) + TArray Enum; +}; + +USTRUCT(BlueprintType, Category = "HttpGPT | Chat", Meta = (DisplayName = "HttpGPT Function")) +struct HTTPGPTCOMMONMODULE_API FHttpGPTFunction +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Name")) + FName Name; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Description")) + FString Description; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Properties")) + TArray Properties; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Required Properties")) + TArray RequiredProperties; + + TSharedPtr GetFunction() const; +}; + +USTRUCT(BlueprintType, Category = "HttpGPT | Chat", Meta = (DisplayName = "HttpGPT Function Call")) +struct HTTPGPTCOMMONMODULE_API FHttpGPTFunctionCall +{ + GENERATED_BODY() + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Name")) + FName Name; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (DisplayName = "Arguments")) + FString Arguments; +}; + UENUM(BlueprintType, Category = "HttpGPT | Chat", Meta = (DisplayName = "HttpGPT Chat Role")) enum class EHttpGPTChatRole : uint8 { User, Assistant, - System + System, + Function }; USTRUCT(BlueprintType, Category = "HttpGPT | Chat", Meta = (DisplayName = "HttpGPT Chat Message")) @@ -25,8 +84,8 @@ struct HTTPGPTCOMMONMODULE_API FHttpGPTChatMessage GENERATED_BODY() FHttpGPTChatMessage() = default; - FHttpGPTChatMessage(const EHttpGPTChatRole& Role, const FString& Content) : Role(Role), Content(Content) {} - FHttpGPTChatMessage(const FName& Role, const FString& Content); + FHttpGPTChatMessage(const EHttpGPTChatRole& InRole, const FString& InContent) : Role(InRole), Content(InContent) {} + FHttpGPTChatMessage(const FName& InRole, const FString& InContent); UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat") EHttpGPTChatRole Role = EHttpGPTChatRole::User; @@ -34,6 +93,9 @@ struct HTTPGPTCOMMONMODULE_API FHttpGPTChatMessage UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat") FString Content; + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Chat", Meta = (EditCondition = "Role == EHttpGPTChatRole::Function")) + FHttpGPTFunctionCall FunctionCall; + TSharedPtr GetMessage() const; }; diff --git a/Source/HttpGPTCommonModule/Public/Structures/HttpGPTCommonTypes.h b/Source/HttpGPTCommonModule/Public/Structures/HttpGPTCommonTypes.h index 851492f..128148d 100644 --- a/Source/HttpGPTCommonModule/Public/Structures/HttpGPTCommonTypes.h +++ b/Source/HttpGPTCommonModule/Public/Structures/HttpGPTCommonTypes.h @@ -37,6 +37,15 @@ struct HTTPGPTCOMMONMODULE_API FHttpGPTCommonOptions UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Common", Meta = (DisplayName = "User")) FName User; + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Common", Meta = (DisplayName = "Is Azure OpenAI")) + bool bIsAzureOpenAI; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Common", Meta = (DisplayName = "Endpoint", EditCondition = "bIsAzureOpenAI")) + FString Endpoint; + + UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "HttpGPT | Common", Meta = (DisplayName = "Azure OpenAI API Version", EditCondition = "bIsAzureOpenAI")) + FString AzureOpenAIAPIVersion; + private: void SetDefaults(); }; \ No newline at end of file diff --git a/Source/HttpGPTCommonModule/Public/Utils/HttpGPTHelper.h b/Source/HttpGPTCommonModule/Public/Utils/HttpGPTHelper.h index dbcf4cc..0c0fc88 100644 --- a/Source/HttpGPTCommonModule/Public/Utils/HttpGPTHelper.h +++ b/Source/HttpGPTCommonModule/Public/Utils/HttpGPTHelper.h @@ -31,11 +31,17 @@ class HTTPGPTCOMMONMODULE_API UHttpGPTHelper final : public UBlueprintFunctionLi UFUNCTION(BlueprintPure, Category = "HttpGPT | Chat", meta = (DisplayName = "Convert Name to HttpGPT Role")) static const EHttpGPTChatRole NameToRole(const FName Role); + UFUNCTION(BlueprintPure, Category = "HttpGPT | Chat", meta = (DisplayName = "Convert HttpGPT Param Type to Name")) + static const FName PropertyTypeToName(const EHttpGPTPropertyType Type); + + UFUNCTION(BlueprintPure, Category = "HttpGPT | Chat", meta = (DisplayName = "Convert Name to HttpGPT Param Type")) + static const EHttpGPTPropertyType NameToPropertyType(const FName Type); + UFUNCTION(BlueprintPure, Category = "HttpGPT | Chat", meta = (DisplayName = "Get Available GPT Models")) static const TArray GetAvailableGPTModels(); UFUNCTION(BlueprintPure, Category = "HttpGPT | Chat", meta = (DisplayName = "Get Endpoint for Model")) - static const FName GetEndpointForModel(const EHttpGPTChatModel Model); + static const FString GetEndpointForModel(const EHttpGPTChatModel Model, const bool bIsAzureOpenAI = false, const FString& AzureOpenAIAPIVersion = TEXT("None")); UFUNCTION(BlueprintPure, Category = "HttpGPT | Chat", meta = (DisplayName = "Model Supports Chat")) static const bool ModelSupportsChat(const EHttpGPTChatModel Model); diff --git a/Source/HttpGPTEditorModule/Private/Chat/SHttpGPTChatShell.cpp b/Source/HttpGPTEditorModule/Private/Chat/SHttpGPTChatShell.cpp index 249bc86..bc23841 100644 --- a/Source/HttpGPTEditorModule/Private/Chat/SHttpGPTChatShell.cpp +++ b/Source/HttpGPTEditorModule/Private/Chat/SHttpGPTChatShell.cpp @@ -145,6 +145,11 @@ void SHttpGPTChatShell::InitializeChatSessionOptions() InitializeChatSession(ChatSessions[0]); } + else if (IFileManager::Get().MakeDirectory(*SessionsPath, true)) + { + InitializeChatSessionOptions(); + return; + } if (ChatSessionListView.IsValid()) { diff --git a/Source/HttpGPTImageModule/Private/Tasks/HttpGPTImageRequest.cpp b/Source/HttpGPTImageModule/Private/Tasks/HttpGPTImageRequest.cpp index 56db9d1..4be8351 100644 --- a/Source/HttpGPTImageModule/Private/Tasks/HttpGPTImageRequest.cpp +++ b/Source/HttpGPTImageModule/Private/Tasks/HttpGPTImageRequest.cpp @@ -89,7 +89,14 @@ bool UHttpGPTImageRequest::CanBindProgress() const FString UHttpGPTImageRequest::GetEndpointURL() const { - return "https://api.openai.com/v1/images/generations"; + if (CommonOptions.bIsAzureOpenAI) + { + return FString::Format(TEXT("{0}/openai/images/generations:submit?api-version={1}"), { GetCommonOptions().Endpoint, GetCommonOptions().AzureOpenAIAPIVersion }); + } + else + { + return FString::Format(TEXT("{0}/v1/images/generations"), { GetCommonOptions().Endpoint }); + } } FString UHttpGPTImageRequest::SetRequestContent() From e27fd531b174677db88e63b3c8627f2805ff8e1c Mon Sep 17 00:00:00 2001 From: lucoiso Date: Mon, 28 Aug 2023 21:39:10 +0100 Subject: [PATCH 3/3] Update version --- HttpGPT.uplugin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HttpGPT.uplugin b/HttpGPT.uplugin index 238926d..c3e0ffb 100644 --- a/HttpGPT.uplugin +++ b/HttpGPT.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, - "Version": 19, - "VersionName": "1.5.6", + "Version": 20, + "VersionName": "1.5.7", "FriendlyName": "HttpGPT - GPT Integration", "Description": "HttpGPT is an Unreal Engine plugin that facilitates integration with OpenAI's GPT based services (ChatGPT and DALL-E) through asynchronous REST requests, making it easy for developers to communicate with these services. HttpGPT also includes new Editor Tools to integrate Chat GPT and DALL-E image generation directly in the Engine.", "Category": "Game Features",