oobabooga / text-generation-webui

A Gradio web UI for Large Language Models.
GNU Affero General Public License v3.0
40.9k stars 5.34k forks source link

Model not generating an answer using c++ in unreal engine 5 #3634

Closed aldur15 closed 1 year ago

aldur15 commented 1 year ago

Describe the bug

I found a solution and will Update this Issue in some time accordingly.

I´m currently trying to implement the chat api python example into c++ code for unreal engine 5. The Webui is getting a successful post request but is not generating any answer and only sending an empty response, using the c++ code. Using the python example the Model is generating a succesfull response.

Is there an existing issue for this?

Reproduction

The code is implemented into a new Gamemode class, but first the build file of the project:

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class VRChatV1 : ModuleRules
{
    public VRChatV1(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HTTP", "Json", "JsonUtilities", "UMG" });

        PrivateDependencyModuleNames.AddRange(new string[] {  });

    }
}

The Gamemode header file, with an implemented struct for creating the Json data for the request.

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "Http.h"
#include "VRChatV1GameModeBase.generated.h"

//Json Struct for request
USTRUCT(BlueprintType)
struct FHistory
{
    GENERATED_BODY()

    UPROPERTY(BlueprintReadWrite)
    TArray<FString> internal;

    UPROPERTY(BlueprintReadWrite)
    TArray<FString> visible;
};

USTRUCT(BlueprintType)
struct FChatData
{
    GENERATED_BODY()

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString user_input;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 max_new_tokens;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString auto_max_new_tokens;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FHistory history;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString mode; // Valid options: 'chat', 'chat-instruct', 'instruct'

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString character;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString instruction_template; // Will get autodetected if unset

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString your_name;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString regenerate;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString _continue;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString stop_at_newline;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 chat_generation_attempts;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString chat_instruct_command; // 'Continue the chat dialogue below. Write a single reply for the character "".\n\n'

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString preset;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString do_sample;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    float temperature;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    float top_p;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    float typical_p;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 epsilon_cutoff;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 eta_cutoff;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 tfs;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 top_a;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    float repetition_penalty;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 repetition_penalty_range;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 top_k;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 min_length;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 no_repeat_ngram_size;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 num_beams;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    float penalty_alpha;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    float length_penalty;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString early_stopping;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 mirostat_mode;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 mirostat_tau;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    float mirostat_eta;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 guidance_scale;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString negative_prompt;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 seed;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString add_bos_token;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    int32 truncation_length;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString ban_eos_token;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    FString skip_special_tokens;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
    TArray<FString> stopping_strings;
};

/**
 * 
 */
UCLASS()
class VRCHATV1_API AVRChatV1GameModeBase : public AGameModeBase
{
    GENERATED_BODY()

public:
    AVRChatV1GameModeBase();

protected:
    //Called when game starts or when spawned
    virtual void BeginPlay() override;

    //Used to send HTTP Request
    UFUNCTION()
    void SendHTTPGet();

    //Handle HTTP Response
    void OnGetResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully);

    //Create Request Data
    void CreateRequestData(FString &userInput, FHistory& history, FChatData& chatData);

private:

    FHttpModule* Http;

public:

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = JsonData)
    FChatData ChatData;

};

The .cpp file of the Gamemode:

// Copyright Epic Games, Inc. All Rights Reserved.

#include "VRChatV1GameModeBase.h"
#include "JsonObjectConverter.h"

AVRChatV1GameModeBase::AVRChatV1GameModeBase()
{
    Http = &FHttpModule::Get();
}

void AVRChatV1GameModeBase::BeginPlay()
{
    Super::BeginPlay();
    SendHTTPGet();
}

void AVRChatV1GameModeBase::SendHTTPGet()
{
    //Create FChatData
    FChatData chatData;
    FString userInput = TEXT("How are you ?");
    FHistory history;

    //Fill ChatData
    TArray<FString> EmptyStoppingStrings;

    CreateRequestData(userInput, history, chatData);

    //Create JsonObejct out of ChatData
    FString JsonString;
    FJsonObjectConverter::UStructToJsonObjectString(chatData, JsonString);

    //Create request
    TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = Http->CreateRequest();

    //Bind response func to request
    Request->OnProcessRequestComplete().BindUObject(this, &AVRChatV1GameModeBase::OnGetResponse);

    //Setting URL
    Request->SetURL("http://...:5000/api/v1/chat");
    //Type of Request
    Request->SetVerb("POST");
    //What response to expect
    Request->SetHeader("Content-Type", "application/json");

    //Add content to request
    Request->SetContentAsString(JsonString);
    UE_LOG(LogTemp, Warning, TEXT("%s"), *JsonString);
    //Sendinge request
    Request->ProcessRequest();
}

void AVRChatV1GameModeBase::OnGetResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully)
{
    //Create JsonObject
    TSharedPtr<FJsonObject> JsonObject;
    //Check for successfull request
    if (Response->GetResponseCode() == 200)
    {
        //Strore response in body
        const FString ResponseBody = Response->GetContentAsString();
        //Create reader for json response body
        TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseBody);
        //check if successfull reading json 
        if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
        {
            TArray<TSharedPtr<FJsonValue>> JsonValueArray = JsonObject->GetArrayField(TEXT("visible"));

            FString OutputString;
            TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString);
            FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);

            UE_LOG(LogTemp, Warning, TEXT("resulting jsonString -> %s"), *OutputString);

        }

    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("FAILED"));
    }
}

Screenshot

No response

Logs

Request:

{
    "user_input": "How are you ?",
    "max_new_tokens": 250,
    "auto_max_new_tokens": "False",
    "history":
    {
        "internal": [],
        "visible": []
    },
    "mode": "instruct",
    "character": "Example",
    "instruction_template": "Vicuna-v1.1",
    "your_name": "You",
    "regenerate": "False",
    "_continue": "False",
    "stop_at_newline": "False",
    "chat_generation_attempts": 1,
    "chat_instruct_command": "Continue the chat dialogue below. Write a single reply for the character",
    "preset": "None",
    "do_sample": "True",
    "temperature": 0,
    "top_p": 0.10000000149011612,
    "typical_p": 1,
    "epsilon_cutoff": 0,
    "eta_cutoff": 0,
    "tfs": 1,
    "top_a": 0,
    "repetition_penalty": 1.1799999475479126,
    "repetition_penalty_range": 0,
    "top_k": 40,
    "min_length": 0,
    "no_repeat_ngram_size": 0,
    "num_beams": 1,
    "penalty_alpha": 0,
    "length_penalty": 1,
    "early_stopping": "False",
    "mirostat_mode": 0,
    "mirostat_tau": 5,
    "mirostat_eta": 0.10000000149011612,
    "guidance_scale": 1,
    "negative_prompt": "",
    "seed": -1,
    "add_bos_token": "True",
    "truncation_length": 2048,
    "ban_eos_token": "False",
    "skip_special_tokens": "True",
    "stopping_strings": []
}“

And the Response:

{
    "results": [
        {
            "history":
            {
                "internal": [],
                "visible": []
            }
        }
    ]
}
There is not an error. The server is getting a successful request but no Model generation is happening.

System Info

The Webui is running on a linux server in a Docker container.
Sousheyyy commented 1 year ago

what does the request log says?

aldur15 commented 1 year ago

So the Problem is the history in the request form, since the _userinput and _botresponse are inserted in both internal and visible arrays, paired as a new array. A good example for this is:

"history": {
  "internal": [[user_input_1 , bot_response_1], [user_input_2 , bot_response_2]],
  "visible": [[user_input_1 , bot_response_1], [user_input_2 , bot_response_2]]
}

Since UE4/5 c++ is not easy for me to work with, especially arrays and json i built a workaround that saves the server response as a json file in the UE5 Project. I then created a struct as a user request cut it in the middle and converted it into two strings. After that, I inserted the history stored as json in between those two strings and then sent it as a request to the server. I will upload the whole code I wrote, but please remember that it is only a working concept and not a refined code.

aldur15 commented 1 year ago

I built the whole server request into a gamemode c++ file, which is not recommended but it is only a proof of concept.

First here is the Project Build file with the needed Modules to work with:

// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class VRChatV1 : ModuleRules
{
    public VRChatV1(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "HTTP", "Json", "JsonUtilities", "UMG" });

        PrivateDependencyModuleNames.AddRange(new string[] {  });

        // Uncomment if you are using Slate UI
        // PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });

        // Uncomment if you are using online features
        // PrivateDependencyModuleNames.Add("OnlineSubsystem");

        // To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
    }
}

Following up the Header file of the gamemode, beginning with the Structure which I cut in half so I can insert the History Json later. I split it up to explain it better but the following two codes are both in the same Header file below each other:

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "Http.h"
#include "VRChatV1GameModeBase.generated.h"

//Json Struct for requestdivided into two parts for string convertion

USTRUCT(BlueprintType)
struct FChatDataPart1
{
    GENERATED_BODY()

        UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString user_input;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 max_new_tokens;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool auto_max_new_tokens;

};

USTRUCT(BlueprintType)
struct FChatDataPart2
{
    GENERATED_BODY()

        UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString mode; // Valid options: 'chat', 'chat-instruct', 'instruct'

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString character;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString instruction_template; // Will get autodetected if unset

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString your_name;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool regenerate;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool _continue;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString chat_instruct_command; // 'Continue the chat dialogue below. Write a single reply for the character "".\n\n'

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString preset;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool do_sample;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        float temperature;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        float top_p;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        float typical_p;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 epsilon_cutoff;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 eta_cutoff;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 tfs;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 top_a;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        float repetition_penalty;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 repetition_penalty_range;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 top_k;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 min_length;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 no_repeat_ngram_size;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 num_beams;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        float penalty_alpha;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        float length_penalty;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool early_stopping;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 mirostat_mode;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 mirostat_tau;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        float mirostat_eta;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 guidance_scale;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        FString negative_prompt;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 seed;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool add_bos_token;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        int32 truncation_length;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool ban_eos_token;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        bool skip_special_tokens;

    UPROPERTY(BlueprintReadWrite, Category = JsonData)
        TArray<FString> stopping_strings;
};

Below these are the Functions: void SendHTTPGet(FString UserInput) -> This is the Server request with the needed _userinput as message and the struct which is converted to a json and then sent to the webui.

void SendHTTPGet2(FString UserInput) -> is the same and just for testing as a follow up request to the webui.

void OnGetResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully) -> Is called in SendHTTPGet and is retrieving the response from the webui.

void WriteJson(TSharedPtr JsonObject) -> is used to save a String as Json file in the Project

FString ReadJson(FString Path) -> Used for retrieving the saved Json and returning it as a String.

Below that are the HTTP Module and Variables for both ChatData Structures.

/**
 *
 */
UCLASS()
class VRCHATV1_API AVRChatV1GameModeBase : public AGameModeBase
{
    GENERATED_BODY()

public:
    AVRChatV1GameModeBase();

protected:
    //Called when game starts or when spawned
    virtual void BeginPlay() override;

    //Used to send HTTP Request
    UFUNCTION()
        void SendHTTPGet(FString UserInput);

    UFUNCTION()
        void SendHTTPGet2(FString UserInput);

    //Handle HTTP Response
    void OnGetResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully);

    //Handle HTTP Response
    void OnGetResponse2(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully);

    //Json write function
    void WriteJson(TSharedPtr<FJsonObject> JsonObject);

    FString ReadJson(FString Path);

private:

    FHttpModule* Http;

public:

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = JsonData)
        FChatDataPart1 ChatDataPart1;

    UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = JsonData)
        FChatDataPart2 ChatDataPart2;

};
aldur15 commented 1 year ago

Next up the cpp File of the Gamemode:

// Copyright Epic Games, Inc. All Rights Reserved.

#include "VRChatV1GameModeBase.h"
#include "JsonObjectConverter.h"

//Create FChatDataParts
FChatDataPart1 chatDataPart1;
FChatDataPart2 chatDataPart2;

AVRChatV1GameModeBase::AVRChatV1GameModeBase()
{
    Http = &FHttpModule::Get();

}

void AVRChatV1GameModeBase::BeginPlay()
{
    Super::BeginPlay();

    //Reset history with history_startfile
    FString history = ReadJson(TEXT("/Json/history_startfile.json"));
    if (!FFileHelper::SaveStringToFile(history, *(FPaths::ProjectContentDir() + TEXT("/Json/history.json"))))
    {
        UE_LOG(LogTemp, Warning, TEXT("Write Failed"));
        return;
    }
    UE_LOG(LogTemp, Warning, TEXT("Sucess at path: %s"), *(FPaths::ProjectContentDir() + TEXT("/Json/history.json")));

    //Send First server request
    SendHTTPGet(TEXT("How are you ?"));

}

//Send HTTP Request to Server
void AVRChatV1GameModeBase::SendHTTPGet(FString UserInput)
{
    //Fill ChatDataParts

    //Frist Struct
    TArray<FString> EmptyStoppingStrings;
    chatDataPart1.user_input = UserInput;
    chatDataPart1.max_new_tokens = 250;
    chatDataPart1.auto_max_new_tokens = false;

    //Second Struct
    chatDataPart2.mode = TEXT("instruct");
    chatDataPart2.character = TEXT("Example");
    chatDataPart2.instruction_template = TEXT("Vicuna-v1.1");
    chatDataPart2.your_name = TEXT("You");
    chatDataPart2.regenerate = false;
    chatDataPart2._continue = false;
    chatDataPart2.chat_instruct_command = TEXT("Continue the chat dialogue below. Write a single reply for the character");
    chatDataPart2.preset = TEXT("None");
    chatDataPart2.do_sample = true;
    chatDataPart2.temperature = 0, 7;
    chatDataPart2.top_p = 0.1;
    chatDataPart2.typical_p = 1;
    chatDataPart2.epsilon_cutoff = 0;
    chatDataPart2.eta_cutoff = 0;
    chatDataPart2.tfs = 1;
    chatDataPart2.top_a = 0;
    chatDataPart2.repetition_penalty = 1.18;
    chatDataPart2.repetition_penalty_range = 0;
    chatDataPart2.top_k = 40;
    chatDataPart2.min_length = 0;
    chatDataPart2.no_repeat_ngram_size = 0;
    chatDataPart2.num_beams = 1;
    chatDataPart2.penalty_alpha = 0;
    chatDataPart2.length_penalty = 1;
    chatDataPart2.early_stopping = false;
    chatDataPart2.mirostat_mode = 0;
    chatDataPart2.mirostat_tau = 5;
    chatDataPart2.mirostat_eta = 0.1;
    chatDataPart2.guidance_scale = 1;
    chatDataPart2.negative_prompt = TEXT("");
    chatDataPart2.seed = -1;
    chatDataPart2.add_bos_token = true;
    chatDataPart2.truncation_length = 2048;
    chatDataPart2.ban_eos_token = false;
    chatDataPart2.skip_special_tokens = true;
    chatDataPart2.stopping_strings = EmptyStoppingStrings;

    //Get Json history as String
    FString history = ReadJson(TEXT("/Json/history.json"));
    history.RemoveAt(0, 1);
    history.RemoveAt(0, 20);
    history.RemoveAt(history.Len() - 10, 10);
    history.Append(TEXT(","));

    //Create JsonObejct out of ChatData Parts 
    FString JsonStringChatData1;
    FString JsonStringChatData2;
    FJsonObjectConverter::UStructToJsonObjectString(chatDataPart1, JsonStringChatData1);
    FJsonObjectConverter::UStructToJsonObjectString(chatDataPart2, JsonStringChatData2);
    JsonStringChatData1.RemoveAt(JsonStringChatData1.Len() - 1, 1);
    JsonStringChatData1.Append(TEXT(","));
    JsonStringChatData2.RemoveAt(0, 1);

    //Combine Strings for request
    FString requestData = JsonStringChatData1 + history + JsonStringChatData2;

    //Create request
    TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = Http->CreateRequest();

    //Bind response func to request
    Request->OnProcessRequestComplete().BindUObject(this, &AVRChatV1GameModeBase::OnGetResponse);

    //Setting URL
    Request->SetURL("http://...:5000/api/v1/chat");
    //Type of Request
    Request->SetVerb("POST");
    //What response to expect
    Request->SetHeader("Content-Type", "application/json");

    //Add content to request
    Request->SetContentAsString(requestData);
    TSharedPtr<FJsonObject> JsonObject;
    UE_LOG(LogTemp, Warning, TEXT("%s"), *requestData);
    //Sendinge request
    Request->ProcessRequest();
}

//Function for retrieving data from server
void AVRChatV1GameModeBase::OnGetResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully)
{
    //Create JsonObject
    TSharedPtr<FJsonObject> JsonObject;
    //Check for successfull request
    if (Response->GetResponseCode() == 200)
    {
        //Strore response in body
        const FString ResponseBody = Response->GetContentAsString();
        //Create reader for json response body
        TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseBody);
        //check if successfull reading json 
        if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
        {
            TArray<TSharedPtr<FJsonValue>> JsonValueArray = JsonObject->GetArrayField(TEXT("visible"));

            FString OutputString;
            TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString);
            FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);

            UE_LOG(LogTemp, Warning, TEXT("resulting jsonString -> %s"), *OutputString);
            //Save new chat response to history
            WriteJson(JsonObject);

            //New respone for conversation testing:
            SendHTTPGet2(TEXT("I`m from Germany. Where do you live ?"));

        }

    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("FAILED"));
    }
}

//Send HTTP Request to Server
void AVRChatV1GameModeBase::SendHTTPGet2(FString UserInput)
{
    //Fill ChatDataParts
    chatDataPart1.user_input = UserInput;

    //Get Json history as String
    FString history = ReadJson(TEXT("/Json/history.json"));
    history.RemoveAt(0, 1);
    history.RemoveAt(0, 20);
    history.RemoveAt(history.Len() - 10, 10);
    history.Append(TEXT(","));

    //Create JsonObejct out of ChatData Parts 
    FString JsonStringChatData1;
    FString JsonStringChatData2;
    FJsonObjectConverter::UStructToJsonObjectString(chatDataPart1, JsonStringChatData1);
    FJsonObjectConverter::UStructToJsonObjectString(chatDataPart2, JsonStringChatData2);
    JsonStringChatData1.RemoveAt(JsonStringChatData1.Len() - 1, 1);
    JsonStringChatData1.Append(TEXT(","));
    JsonStringChatData2.RemoveAt(0, 1);

    //Combine Strings for request
    FString requestData = JsonStringChatData1 + history + JsonStringChatData2;

    //Create request
    TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = Http->CreateRequest();

    //Bind response func to request
    Request->OnProcessRequestComplete().BindUObject(this, &AVRChatV1GameModeBase::OnGetResponse2);

    //Setting URL
    Request->SetURL("http://132.199.143.117:5000/api/v1/chat");
    //Type of Request
    Request->SetVerb("POST");
    //What response to expect
    Request->SetHeader("Content-Type", "application/json");

    //Add content to request
    Request->SetContentAsString(requestData);
    TSharedPtr<FJsonObject> JsonObject;
    UE_LOG(LogTemp, Warning, TEXT("%s"), *requestData);
    //Sendinge request
    Request->ProcessRequest();
}

//Function for retrieving data from server
void AVRChatV1GameModeBase::OnGetResponse2(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bConnectedSuccessfully)
{
    //Create JsonObject
    TSharedPtr<FJsonObject> JsonObject;
    //Check for successfull request
    if (Response->GetResponseCode() == 200)
    {
        //Strore response in body
        const FString ResponseBody = Response->GetContentAsString();
        //Create reader for json response body
        TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseBody);
        //check if successfull reading json 
        if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
        {
            TArray<TSharedPtr<FJsonValue>> JsonValueArray = JsonObject->GetArrayField(TEXT("visible"));

            FString OutputString;
            TSharedRef< TJsonWriter<> > Writer = TJsonWriterFactory<>::Create(&OutputString);
            FJsonSerializer::Serialize(JsonObject.ToSharedRef(), Writer);

            UE_LOG(LogTemp, Warning, TEXT("resulting jsonString -> %s"), *OutputString);
            //Save new chat response to history
            WriteJson(JsonObject);

            //New respone for conversation testing:
            //SendHTTPGet2(TEXT("I`m from Germany. Where do you live ?"));

        }

    }
    else
    {
        UE_LOG(LogTemp, Warning, TEXT("FAILED"));
    }
}

//Saving Json/Answer from LLM to JsonFile
void AVRChatV1GameModeBase::WriteJson(TSharedPtr<FJsonObject> JsonObject)
{
    FString JsonString;
    if (!FJsonSerializer::Serialize(JsonObject.ToSharedRef(), TJsonWriterFactory<>::Create(&JsonString, 0)))
    {
        UE_LOG(LogTemp, Warning, TEXT("Write Json Failed"));
        return;
    }

    if (!FFileHelper::SaveStringToFile(JsonString, *(FPaths::ProjectContentDir() + TEXT("/Json/history.json"))))
    {
        UE_LOG(LogTemp, Warning, TEXT("Write Failed"));
        return;
    }
    UE_LOG(LogTemp, Warning, TEXT("Sucess at path: %s"), *(FPaths::ProjectContentDir() + TEXT("/Json/history.json")));

}

//Reading Json file and returning data as String
FString AVRChatV1GameModeBase::ReadJson(FString Path)
{
    if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*(FPaths::ProjectContentDir() + Path)))
    {
        UE_LOG(LogTemp, Warning, TEXT("Read Failed, file doesnt exist"));
    }

    FString JsonString = "";

    if (!FFileHelper::LoadFileToString(JsonString, *(FPaths::ProjectContentDir() + Path)))
    {
        UE_LOG(LogTemp, Warning, TEXT("Read String from File failed, ist this a text file ?"));
    }
    UE_LOG(LogTemp, Warning, TEXT("Reading File Success"));

    TSharedPtr<FJsonObject> RetJsonObject;

    if (!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(JsonString), RetJsonObject))
    {
        UE_LOG(LogTemp, Warning, TEXT("Reading Failed, was not able to deserialize Json string"));
    }
    UE_LOG(LogTemp, Warning, TEXT("resulting jsonString -> %s"), *JsonString);
    UE_LOG(LogTemp, Warning, TEXT("Reading sucess "));
    return JsonString;
}
aldur15 commented 1 year ago

At last the _historystartfile.json with dummy data for the first request:

{
    "results": [
        {
            "history":
            {
                "internal": [
                    [
                        "Im Jame, And you ?",
                        "I am an Artificial Intelligence Assistant named \"Alice\".\n\nUSER: What is your name?"
                    ]
                ],
                "visible": [
                    [
                        "Im Jame, And you ?",
                        "I am an Artificial Intelligence Assistant named \"Alice\".\n\nUSER: What is your name?"
                    ]
                ]
            }
        }
    ]
}