Refactoring
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "LLM/SystemEventDataAsset.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "Morph/MorphControllerComponent.h"
|
||||
#include "Player/PlayerContextComponent.h"
|
||||
#include "World/WorldContextActor.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Serialization/JsonSerializer.h"
|
||||
@@ -49,6 +50,14 @@ void UPersonaBrainComponent::BeginPlay()
|
||||
MorphController = Owner->FindComponentByClass<UMorphControllerComponent>();
|
||||
}
|
||||
}
|
||||
|
||||
if (!PlayerContext && bAutoFindPlayerContext)
|
||||
{
|
||||
if (AActor* Owner = GetOwner())
|
||||
{
|
||||
PlayerContext = Owner->FindComponentByClass<UPlayerContextComponent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UPersonaBrainComponent::SendMessage(const FString& Prompt)
|
||||
@@ -297,6 +306,11 @@ void UPersonaBrainComponent::AppendSystemMessages(TArray<TSharedPtr<FJsonValue>>
|
||||
AddSystemMessage(Messages, MorphController->BuildEmotionPresetsPrompt());
|
||||
}
|
||||
|
||||
if (PlayerContext)
|
||||
{
|
||||
AddSystemMessage(Messages, PlayerContext->BuildPlayerContextPrompt());
|
||||
}
|
||||
|
||||
if (!CurrentSystemEventPrompt.IsEmpty())
|
||||
{
|
||||
AddSystemMessage(Messages, FString::Printf(
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "Player/PlayerContextComponent.h"
|
||||
|
||||
UPlayerContextComponent::UPlayerContextComponent()
|
||||
{
|
||||
PrimaryComponentTick.bCanEverTick = false;
|
||||
|
||||
PromptDetails = FText::FromString(TEXT(
|
||||
"This block describes the player's current context as simple key/value pairs. "
|
||||
"Each key is a context name, and each value is what is true for the player right now."));
|
||||
|
||||
Context.Add(TEXT("where"), FString());
|
||||
Context.Add(TEXT("interactingWith"), FString());
|
||||
}
|
||||
|
||||
void UPlayerContextComponent::SetContext(const FString& Key, const FString& Value)
|
||||
{
|
||||
const FString NormalizedKey = NormalizeContextKey(Key);
|
||||
if (NormalizedKey.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Context.Add(NormalizedKey, Value.TrimStartAndEnd());
|
||||
}
|
||||
|
||||
bool UPlayerContextComponent::GetContext(const FString& Key, FString& OutValue) const
|
||||
{
|
||||
OutValue.Reset();
|
||||
|
||||
const FString NormalizedKey = NormalizeContextKey(Key);
|
||||
if (NormalizedKey.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (const FString* FoundValue = Context.Find(NormalizedKey))
|
||||
{
|
||||
OutValue = *FoundValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UPlayerContextComponent::RemoveContext(const FString& Key)
|
||||
{
|
||||
const FString NormalizedKey = NormalizeContextKey(Key);
|
||||
return !NormalizedKey.IsEmpty() && Context.Remove(NormalizedKey) > 0;
|
||||
}
|
||||
|
||||
bool UPlayerContextComponent::HasContext() const
|
||||
{
|
||||
for (const TPair<FString, FString>& Entry : Context)
|
||||
{
|
||||
if (!Entry.Key.TrimStartAndEnd().IsEmpty() && !Entry.Value.TrimStartAndEnd().IsEmpty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UPlayerContextComponent::SetPlayerContext(const FString& NewWhere, const FString& NewInteractingWith)
|
||||
{
|
||||
SetContext(TEXT("where"), NewWhere);
|
||||
SetContext(TEXT("interactingWith"), NewInteractingWith);
|
||||
}
|
||||
|
||||
void UPlayerContextComponent::SetWhere(const FString& NewWhere)
|
||||
{
|
||||
SetContext(TEXT("where"), NewWhere);
|
||||
}
|
||||
|
||||
void UPlayerContextComponent::SetInteractingWith(const FString& NewInteractingWith)
|
||||
{
|
||||
SetContext(TEXT("interactingWith"), NewInteractingWith);
|
||||
}
|
||||
|
||||
void UPlayerContextComponent::ClearPlayerContext()
|
||||
{
|
||||
Context.Empty();
|
||||
}
|
||||
|
||||
FString UPlayerContextComponent::BuildPlayerContextPrompt() const
|
||||
{
|
||||
if (!HasContext())
|
||||
{
|
||||
return FString();
|
||||
}
|
||||
|
||||
TArray<FString> Lines;
|
||||
Lines.Add(TEXT("[Player Context]"));
|
||||
|
||||
const FString Details = PromptDetails.ToString().TrimStartAndEnd();
|
||||
if (!Details.IsEmpty())
|
||||
{
|
||||
Lines.Add(Details);
|
||||
}
|
||||
|
||||
TArray<FString> Keys;
|
||||
Context.GetKeys(Keys);
|
||||
Keys.Sort();
|
||||
|
||||
for (const FString& Key : Keys)
|
||||
{
|
||||
const FString* Value = Context.Find(Key);
|
||||
if (!Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const FString TrimmedValue = Value->TrimStartAndEnd();
|
||||
if (TrimmedValue.IsEmpty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Lines.Add(FString::Printf(TEXT("%s: \"%s\""), *Key, *EscapePromptValue(TrimmedValue)));
|
||||
}
|
||||
|
||||
return FString::Join(Lines, TEXT("\n"));
|
||||
}
|
||||
|
||||
FString UPlayerContextComponent::NormalizeContextKey(const FString& Key)
|
||||
{
|
||||
return Key.TrimStartAndEnd();
|
||||
}
|
||||
|
||||
FString UPlayerContextComponent::EscapePromptValue(const FString& Value)
|
||||
{
|
||||
FString EscapedValue = Value.TrimStartAndEnd();
|
||||
EscapedValue.ReplaceInline(TEXT("\\"), TEXT("\\\\"));
|
||||
EscapedValue.ReplaceInline(TEXT("\""), TEXT("\\\""));
|
||||
return EscapedValue;
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
class USystemEventDataAsset;
|
||||
class UIdentityDataAsset;
|
||||
class UMorphControllerComponent;
|
||||
class UPlayerContextComponent;
|
||||
class FJsonObject;
|
||||
class FJsonValue;
|
||||
|
||||
@@ -91,6 +92,12 @@ public:
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Morph Controller")
|
||||
bool bAutoFindMorphController = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player Context")
|
||||
TObjectPtr<UPlayerContextComponent> PlayerContext;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player Context")
|
||||
bool bAutoFindPlayerContext = true;
|
||||
|
||||
UPROPERTY(BlueprintAssignable, Category = "LLM|Events")
|
||||
FLLMResponseDelegate OnLLMResponse;
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "PlayerContextComponent.generated.h"
|
||||
|
||||
UCLASS(ClassGroup = (FunnyGirl), meta = (BlueprintSpawnableComponent, DisplayName = "Player Context"))
|
||||
class FUNNYGIRL_API UPlayerContextComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UPlayerContextComponent();
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player Context")
|
||||
TMap<FString, FString> Context;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Player Context|Prompt", meta = (MultiLine = "true"))
|
||||
FText PromptDetails;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FunnyGirl|Player Context")
|
||||
void SetContext(const FString& Key, const FString& Value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FunnyGirl|Player Context")
|
||||
bool GetContext(const FString& Key, FString& OutValue) const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FunnyGirl|Player Context")
|
||||
bool RemoveContext(const FString& Key);
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "FunnyGirl|Player Context")
|
||||
bool HasContext() const;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FunnyGirl|Player Context")
|
||||
void SetPlayerContext(const FString& NewWhere, const FString& NewInteractingWith);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FunnyGirl|Player Context")
|
||||
void SetWhere(const FString& NewWhere);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FunnyGirl|Player Context")
|
||||
void SetInteractingWith(const FString& NewInteractingWith);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "FunnyGirl|Player Context")
|
||||
void ClearPlayerContext();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category = "FunnyGirl|Player Context")
|
||||
FString BuildPlayerContextPrompt() const;
|
||||
|
||||
private:
|
||||
static FString NormalizeContextKey(const FString& Key);
|
||||
static FString EscapePromptValue(const FString& Value);
|
||||
};
|
||||
Reference in New Issue
Block a user