今回も以下の続き
furcraeaUEOpenAIBPLibrary.h
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "furcraeaUEOpenAIBPLibrary.generated.h"
UCLASS()
class UfurcraeaUEOpenAIBPLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
UfurcraeaUEOpenAIBPLibrary(const FObjectInitializer& ObjectInitializer);
UFUNCTION(BlueprintCallable, Category = "furcraeaUEOpenAI")
static FString furcraeaUEOpenAISampleFunction(FString Param);
private:
static FString SendChatCompletionRequest(FString UserMessage);
static void OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful);
static void ResponseMessageToPythonCode(FString ResponseMessage);
static bool RunMyPython(int32& ProcessId,
FString FullPathOfProgramToRun, TArray<FString> CommandlineArgs, bool Hidden);
};
furcraeaUEOpenAIBPLibrary.cpp
#include "furcraeaUEOpenAIBPLibrary.h"
#include "HttpModule.h"
#include "Interfaces/IHttpRequest.h"
#include "Interfaces/IHttpResponse.h"
#include "Json.h"
#include "JsonUtilities.h"
#include "String.h"
#include "Misc/FileHelper.h"
#include "Misc/Paths.h"
#include "Engine/Engine.h"
#include "PythonBridge.h"
//IMPLEMENT_GAME_MODULE(FDefaultGameModuleImpl, furcraeaUEOpenAIBPLibrary);
UfurcraeaUEOpenAIBPLibrary::UfurcraeaUEOpenAIBPLibrary(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
UE_LOG(LogTemp, Warning, TEXT("Hello World! UfurcraeaUEOpenAIBPLibrary ObjectInitializer"));
}
FString UfurcraeaUEOpenAIBPLibrary::furcraeaUEOpenAISampleFunction(FString Param)
{
FString UserMessage = Param;
FString ResponseMessage = TEXT("");
UE_LOG(LogTemp, Warning, TEXT("Hello World! furcraeaUEOpenAISampleFunction"));
ResponseMessage= SendChatCompletionRequest(UserMessage);
return ResponseMessage;
}
FString UfurcraeaUEOpenAIBPLibrary::SendChatCompletionRequest(FString UserMessage)
{
FString ApiKey = TEXT("sk-から始まるキー");
if (!FModuleManager::Get().IsModuleLoaded("Http"))
{
FModuleManager::Get().LoadModule("Http");
}
FHttpModule* Http = &FHttpModule::Get();
if (!Http)
{
UE_LOG(LogTemp, Error, TEXT("Failed to get FHttpModule instance"));
return FString();
}
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> HttpRequest = Http->CreateRequest();
HttpRequest->SetURL("https://api.openai.com/v1/chat/completions");
HttpRequest->SetVerb("POST");
HttpRequest->SetHeader("Content-Type", "application/json");
HttpRequest->SetHeader("Authorization", "Bearer " + ApiKey);
FString Content = FString::Printf(TEXT(R"(
{
"model": "gpt-4o-mini",
"messages": [{"role": "user", "content": "%s"}],
"temperature": 0.7
}
)"), *UserMessage);
HttpRequest->SetContentAsString(Content);
//HttpRequest->OnProcessRequestComplete().BindUObject(this, &UfurcraeaUEOpenAIBPLibrary::OnResponseReceived);
HttpRequest->OnProcessRequestComplete().BindLambda([](FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
OnResponseReceived(Request, Response, bWasSuccessful);
});
HttpRequest->ProcessRequest();
return FString();
}
void UfurcraeaUEOpenAIBPLibrary::OnResponseReceived(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
if (bWasSuccessful && Response.IsValid())
{
FString ResponseContent = Response->GetContentAsString();
TSharedPtr<FJsonObject> JsonObject;
TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(ResponseContent);
if (FJsonSerializer::Deserialize(Reader, JsonObject) && JsonObject.IsValid())
{
FString MessageContent = JsonObject->GetArrayField("choices")[0]->AsObject()->GetObjectField("message")->GetStringField("content");
UE_LOG(LogTemp, Warning, TEXT("OnResponseReceived() Response Message: %s"), *MessageContent);
ResponseMessageToPythonCode(MessageContent);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to parse JSON response"));
}
}
else
{
UE_LOG(LogTemp, Error, TEXT("Request failed"));
}
}
static std::string replaceOtherStr(std::string& replacedStr, std::string from, std::string to) {
const unsigned int pos = replacedStr.find(from);
const int len = from.length();
if (pos == std::string::npos || from.empty()) {
return replacedStr;
}
return replacedStr.replace(pos, len, to);
}
void UfurcraeaUEOpenAIBPLibrary::ResponseMessageToPythonCode(FString ResponseMessage)
{
//ResponseMessage の文字列から「```python」で始まり「```」で終わるまでの文字列を抜き出して
// FString から標準文字列に変換
FString aFString= ResponseMessage;
std::string aString = TCHAR_TO_ANSI(*aFString);
long aStartIndex = aString.find("```python");
long aEndIndex = aString.rfind("```");
long aLength = aEndIndex - aStartIndex;
std::string aPythonCode =aString.substr(aStartIndex+9, aLength-9);
replaceOtherStr(aPythonCode, "?", "//");
// 標準文字列から FString に変換
FString PythonCode = FString(aPythonCode.c_str());
UE_LOG(LogTemp, Warning, TEXT("ResponseMessageToPythonCode() StartIndex: %u"), aStartIndex);
UE_LOG(LogTemp, Warning, TEXT("ResponseMessageToPythonCode() EndIndex: %u"), aEndIndex);
if (aStartIndex != 0 && aEndIndex != 0)
{
//FString PythonCode2 = ResponseMessage.Mid(StartIndex + 1, PythonCodeLength);
UE_LOG(LogTemp, Warning, TEXT("ResponseMessageToPythonCode() 1 PythonCode: %s"), *PythonCode);
//UE_LOG(LogTemp, Warning, TEXT("ResponseMessageToPythonCode() 2 PythonCode2: %s"), *PythonCode2);
// Define the file path in the Saved directory
FString FilePath = FPaths::ProjectSavedDir() / TEXT("ExtractedPythonCode.py");
// Save the Python code to the file
if (FFileHelper::SaveStringToFile(PythonCode, *FilePath))
{
UE_LOG(LogTemp, Warning, TEXT("Python code saved to: %s"), *FilePath);
// Ensure the file path is correctly formatted for the exec command
FString RelativeFilePath = FPaths::ConvertRelativePathToFull(FilePath);
FString Command = FString::Printf(TEXT("py \"%s\""), *RelativeFilePath);
//FString Command = FString::Printf(TEXT("\"%s\""), *RelativeFilePath);
//GEngine->Exec(nullptr, *Command);
UPythonBridge* bridge = UPythonBridge::Get();
bridge->FunctionImplementedInPython();
bridge->ExecuteCommand(RelativeFilePath);
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed to save Python code to file"));
}
}
else
{
UE_LOG(LogTemp, Warning, TEXT("ResponseMessageToPythonCode() PythonCode: in None"));
}
}
PythonBridge.h (https://forums.unrealengine.com/t/running-a-python-script-with-c/114117/4)
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine.h"
#include "UObject/NoExportTypes.h"
#include "PythonBridge.generated.h"
/**
*
*/
UCLASS(Blueprintable)
class FURCRAEAUEOPENAI_API UPythonBridge : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = Python)
static UPythonBridge* Get();
UFUNCTION(BlueprintImplementableEvent, Category = Python)
void FunctionImplementedInPython() const;
UFUNCTION(BlueprintImplementableEvent, Category = Python)
void ExecuteCommand(const FString& CommandName) const;
};
PythonBridge.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "PythonBridge.h"
UPythonBridge* UPythonBridge::Get()
{
TArray<UClass*> PythonBridgeClasses;
GetDerivedClasses(UPythonBridge::StaticClass(), PythonBridgeClasses);
int32 NumClasses = PythonBridgeClasses.Num();
if (NumClasses > 0)
{
return Cast<UPythonBridge>(PythonBridgeClasses[NumClasses - 1]->GetDefaultObject());
}
return nullptr;
}
/*
void UPythonBridge::FunctionImplementedInPython() const
{
UE_LOG(LogTemp, Warning, TEXT("Hello World! FunctionImplementedInPython"));
}
void UPythonBridge::ExecuteCommand(const FString& CommandName) const
{
UE_LOG(LogTemp, Warning, TEXT("Hello World! ExecuteCommand"));
}
*/
Project/Content/Python/init_unreal.py
import unreal
@unreal.uclass()
class PythonBridgeImplementation(unreal.PythonBridge):
@unreal.ufunction(override=True)
def function_implemented_in_python(self):
print("function_implemented_in_python")
@unreal.ufunction(override=True)
def execute_command(self, command_name):
print("execute_command command_name="+command_name)
exec(open(command_name).read())
で完成!! Cubeがちゃんと並ぶかは五分五分です。
AIのコマンド
https://dev.epicgames.com/documentation/en-us/unreal-engine/python-api/?application_version=5.3に乗ってるpythonでpep8に準拠してunrealengine5.3のpythonでレベルにcubeを10個並べて
出力されたpython
import unreal
def spawn_cubes(num_cubes=10, spacing=200.0):
# //??????????
actor_spawned = []
world = unreal.EditorLevelLibrary.get_editor_world()
# ??????????????????
cube_mesh = unreal.EditorAssetLibrary.load_asset('/Engine/BasicShapes/Cube')
for i in range(num_cubes):
# ??????????????
spawn_location = unreal.Vector(i * spacing, 0, 0)
# ?????????
cube_actor = unreal.EditorLevelLibrary.spawn_actor_from_object(cube_mesh, spawn_location)
actor_spawned.append(cube_actor)
return actor_spawned
# ?????10????
spawned_cubes = spawn_cubes()
管理用
https://drive.google.com/file/d/1qjtYztc1AuBDFLBygc1z_0taEzsa0Y4Q/view?usp=sharing
参考URL
https://forums.unrealengine.com/t/running-a-python-script-with-c/114117/4