멈추지 않고 끈질기게
[Unreal] 최종 프로젝트 6일차 - 목소리 분류 / 식물 상호작용 / 웹 통신 수정 본문
※ 해당 포스팅은 개인의 공부 정리용 글입니다. 틀린 내용이 있다면 추후 수정될 수 있습니다.
※ 해당 포스팅은 청년취업사관학교 교육 과정의 최종 프로젝트에 관한 내용을 포함하고 있습니다.
※ 해당 포스팅은 Unreal 5.4.1 버전을 기준으로 작성되었습니다.
0. 서론
오늘은 소소한 작업 몇 개를 제외하고는 거의 웹서버 갱신에 시간을 할애하였습니다. 팀원 분이 NPC 대화에 호감도 반영하는 로직을 추가하셔서, 해당 코드를 기준으로 기존의 웹서버의 NPC 통신 부분을 업데이트 하였습니다. 해당 과정에서 입력, 출력 모두 변화가 있다보니 언리얼과 통신하는 부분을 모두 수정하느라 시간이 조금 걸렸습니다.
1. NPC마다 다른 목소리 출력하기
기존에는 NPC에 상관없이 동일한 목소리를 출력하고 있었어서, NPC마다 다른 목소리를 출력하는 로직이 필요했습니다. 다만 현재 chat-gpt가 tts쪽으로 기능을 많이 제공하진 않아서, tts-1 모델에서 사용 가능한 6가지 옵션으로 NPC에 따라 다른 목소리가 나오게 하는 정도만 우선적으로 구현해보기로 했습니다.
voice_dict = {'미라':'alloy', '이준호':'echo', '빈칸1':'fable', '이춘식':'onyx', '빈칸2':'nova', '빈칸3':'shimmer'}
def talk2npc(npcName:str,dialog:str,preperence:int):#이름, 대화문, 현재 호감도
## 기타 내용
# tts
tts_result = client.audio.speech.create(#tts변환
model="tts-1",
voice=voice_dict[npcName],
input=response.answer,
speed=1.0,
)
## 기타 내용
간단하게 NPC 이름을 키로 받고 voice 모델 타입을 밸류로 갖는 딕셔너리를 선언하여, 입력받은 NPC 이름에 맞는 voice 모델로 출력하도록 수정했습니다. 테스트해보니 alloy부터 앞의 3개가 여자 목소리, onyx부터 3개가 남자 목소리인 듯 했습니다. 아무래도 목소리가 특징이 크게 구분되지는 않아서, 팀원분이 tts쪽으로 좀 더 발전시킬 수 없을지 연구중입니다.
2. 식물한테 말 걸어서 키우기
식물한테 말을 걸면 긍정적인지 부정적인지 정수 형태로 반환하는 체인을 작성하여, 언리얼에서 반환값을 로그로 찍어보는 데까지 테스트해보았습니다.
output_parser = StrOutputParser()
template = """
당신은 농장에서 자라는 식물입니다. 대화가 당신에게 긍정적인지 부정적인지 판단하고, 문자 없이 오로지 정수 형태로만 답변해주세요.
가장 긍정적인 대화를 10으로, 가장 부정적인 대화를 -10으로 합니다.
긍정적인지 부정적인지 판단하기 어렵다면, 0점으로 답변하세요.
대화:
{question}
"""
prompt_plant = PromptTemplate.from_template(template=template)
chain_plant = prompt_plant | model | output_parser
def talk2plant(speech):
result = chain_plant.invoke({"question":f"{speech}"})
return result
답변을 -10 ~ 10 사이의 정수로만 반환받다보니 통신 속도는 굉장히 빨랐습니다. STT로 직접 말을 거는 경우에는 약 2초정도 걸렸고, 텍스트로 보낼 경우에는 거의 즉각적인 답변을 받을 수 있었습니다. 나중에 작물 쪽 작업하는 분에게 성장 / 시듦 함수를 public으로 요청하여 머지한 후에 테스트해 볼 예정입니다.
3. 웹 통신 수정(호감도 반영)
팀원 분께서 NPC 대화 고도화 작업을 1차적으로 마무리하셨습니다. 현재 호감도를 입력으로 받아서 그에 맞게 대답하고, 입력받은 대화에 따라 호감도 상승 또는 하락치를 반환받도록 구현되었습니다. 해당 내용을 웹서버에 합치고, 언리얼에서 통신 파트를 수정하였습니다.
웹서버 쪽 코드는 수정내용이 많기도 하고 팀원분의 작업물이라 올리기 어렵고, 언리얼 쪽에서 통신 양식을 수정한 부분만 살짝 첨부하려고 합니다. 기존의 NPC 대화 반환 양식은 파일 경로와 답변 내용만 포함하고 있었지만, 호감도 및 감정이 추가되면서 변수가 많아져서 아예 게임모드쪽에 구조체를 선언하여 해당 양식으로 데이터를 파싱하도록 했습니다.
// NPC 통신용 구조체(게임 모드)
USTRUCT()
struct FNPCResponse
{
GENERATED_BODY()
FString Answer;
FString Emotion;
FString FilePath;
int32 Likeability;
};
// 파싱 코드(라이브러리)
void UJsonParserLibrary::ParseNPCResponse(const FString& Data, FNPCResponse& Response)
{
TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(Data);
TSharedPtr<FJsonObject> JsonObj = MakeShareable(new FJsonObject());
// Deserialize JsonGetObjectField
if (FJsonSerializer::Deserialize(JsonReader, JsonObj))
{
Response.Answer = JsonObj->GetStringField(TEXT("answer"));
Response.Emotion = JsonObj->GetStringField(TEXT("emotion"));
Response.FilePath = JsonObj->GetStringField(TEXT("file_path"));
Response.Likeability = JsonObj->GetIntegerField(TEXT("likability"));
}
}
이에 따라 NPC 대화를 출력하는 함수도 해당 구조체 타입으로 전달받도록 수정하고, NPC 호감도를 갱신하고 로그로 출력하도록 하였습니다. 감정표현도 아직은 사용하지 않고 있지만, 추후에 NPC 초상화를 감정에 맞는 초상화로 수정하고 감정에 맞는 애니메이션을 실행하도록 구현할 예정입니다.
// NPC 대화 출력 & 호감도 갱신
void AFarmLifeGameMode::SetLatestSpeech(const FNPCResponse& Response)
{
// 초기화용 호출이라면 바로 종료
if(nullptr == CurNPC)
{
GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, TEXT("Initialize Complete"));
return;
}
LatestSpeech = Response.Answer;
UE_LOG(LogTemp, Warning, TEXT("ReqText Complete : [%s] %s"), *CurNPC->GetNPCName(), *LatestSpeech);
// UI 갱신
if(ConversationUI->IsVisible())
{
ConversationUI->UpdateConversationUI(CurNPC->GetNPCName(), LatestSpeech);
CurNPC->LoadSpeechFileAndPlay(Response.FilePath);
}
// 호감도 갱신
CurNPC->UpdateLikeability(Response.Likeability);
UE_LOG(LogTemp, Warning, TEXT("[%s's likeability] : %d"), *CurNPC->GetNPCName(), CurNPC->GetLikeability());
UE_LOG(LogTemp, Warning, TEXT("[%s's emotion] : %s"), *CurNPC->GetNPCName(), *Response.Emotion);
}
'포트폴리오' 카테고리의 다른 글
[Unreal] 최종 프로젝트 8일차 - 대화 로직 재구성 / 페르소나 생성 자동화 (0) | 2024.05.22 |
---|---|
[Unreal] 최종 프로젝트 7일차 - 감정 애니메이션 / 대화 로직 재구성 (0) | 2024.05.21 |
[Unreal] 최종 프로젝트 5일차 - 타임 플로우 / NPC 행동 패턴 (0) | 2024.05.17 |
[Unreal] 최종 프로젝트 2일차 - wav 파일 런타임에 출력하기 (0) | 2024.05.13 |
[Unreal] 최종 프로젝트 1일차 - STT 구현 (1) | 2024.05.11 |