Atomic Integrated Analysis with LiteRTDemo
Analyze By Demo
This chapter will dissect every real plugin interaction contact point in the LiteRTDemo project through "diagram-text-code" integrated atomic driving.
Topology Step 1
Fig 1: LiteRTDemo Plugin Interaction Topology (Atomic Contact Mapping)
Architecture Step 2
Fig 2: Atomic System Operation Flow (Startup | Usage | Shutdown)
1. Physical Link Initialization
2. Usage Timing & Sequence
3. Physical Shutdown & Recycling
Practical Step 3
Developer Integration Guide: Learning from the Demo
This section breaks down all custom code in the Demo project by lifecycle. Rule: All application logic must be present.
Asset Initialization & Physical Loading
Note: You need to learn how to initialize an AI and perform a unique, one-time initialization at the appropriate location in your project.
PublicDependencyModuleNames.AddRange(new string[] {
"Core", "CoreUObject", "Engine",
"LiteRTLMUnreal" // Core plugin binary package
});
void FUmgMcpLiteRtLmAiProvider::EnsureModelLoadedAsync(const FString& AbsPath, TFunction<void(bool)> OnComplete) {
FLiteRtLmConfig Config = FLiteRtLmUnrealApi::GetAutoConfig();
Config.ModelPath = AbsPath;
Config.Backend = TEXT("gpu");
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [Config, OnComplete]() {
bool bSuccess = FLiteRtLmUnrealApi::LoadModel(Config);
AsyncTask(ENamedThreads::GameThread, [bSuccess, OnComplete]() {
if (OnComplete) OnComplete(bSuccess);
});
});
}
Command Dispatch: Finger to Plugin
Note: You need to learn how to initiate a conversation request to the AI. Specifically, this will require you to update method for async/sync, which is the core input for users.
void UUmgMcpActiveMessageSubsystem::ExecuteSendMessage() {
auto ChatInput = RegisteredChatInput.Pin();
if (!ChatInput.IsValid()) return;
FText InputText = ChatInput->GetText();
if (!InputText.IsEmpty()) {
RequestQuestion(InputText.ToString());
ChatInput->ClearText();
}
}
void UUmgMcpActiveMessageSubsystem::RequestQuestion(const FString& QuestionText) {
bIsGenerating = true;
TSharedPtr<FUmgMcpAgent> ActiveAgent = SessionSubsystem->GetMainAgent();
if (ActiveAgent.IsValid()) {
UpdateActiveMessageMeta(ActiveAgent->Name, LOCTEXT("Thinking", "Thinking..."), true);
TSharedPtr<FJsonObject> RequestObj = MakeShared<FJsonObject>();
RequestObj->SetStringField(TEXT("role"), TEXT("user"));
RequestObj->SetStringField(TEXT("content"), QuestionText);
ActiveAgent->Answer(RequestObj);
}
}
void FUmgMcpLiteRtLmAiProvider::Send(const TArray<FUmgMcpChatMessage>& Messages, ...) {
FLiteRtLmUnrealApi::SendChatRequest(
AgentPtr, Messages, ToolsJson, OnChunk, OnDone, Params
);
}
Streaming Feedback: Chunk to Pixel
Note: You need to learn how to obtain results from AI and preferably render them in real-time. Here you need to distinguish between two concepts: Streaming Output and Answer Completion. Streaming output is incremental output for enhancing experience; Answer Completion is the final stock output for implementing business logic.
FLiteRtLmChunkCallback OnChunk = [this](const FString& Chunk) {
AsyncTask(ENamedThreads::GameThread, [this, Chunk]() {
ActiveSubsystem->AppendActiveMessageText(Chunk);
});
};
void UUmgMcpActiveMessageSubsystem::AppendActiveMessageText(const FString& PartialText) {
if (ActiveMessageWidget.IsValid()) {
ActiveMessageWidget->AppendToCurrentTextOutputBlock(PartialText);
if (RegisteredHub.IsValid()) RegisteredHub.Pin()->RefreshVisibility();
}
}
void SUmgMcpAgentResponseGroup::AppendToCurrentTextOutputBlock(const FString& Text) {
CurrentFullText += Text;
InternalTextWidget->SetText(FText::FromString(CurrentFullText));
}
Resource Release
void FUmgMcpLiteRtLmAiProvider::UnloadModel() {
FLiteRtLmUnrealApi::UnloadModel();
}
void UWinyunqDialogueWidget::SetTargetNPC(ULiteRtLmComponent* InNPC) {
if (CurrentNPC) CurrentNPC->OnTextChunkReceived.RemoveAll(this);
}