이거 구현하려고 이틀동안 고생했다..
일단, 기본적으로 이번 코드에서 알아야하는 구문은 Callback함수이다.
유니티에서 Callback함수는 다음과 같이 선언한다.
public UnityAction<string, string> callback = null;
Callback함수는 비동기 작업때, 즉, 네트워크 연결 작업에서 네트워크연결이 완료된 후 작업을 처리해야할 때 사용한다.
일단, 전체코드는 다음과 같이 구성했다.
코드는 조금 길어서 접은글로 대체하겠다.
using System;
using System.Collections;
using UnityEngine;
using Google.Apis.Dialogflow.v2;
using Google.Apis.Dialogflow.v2.Data;
using Google.Apis.Auth.OAuth2;
using Google.Api;
using UnityEngine.Events;
using UnityEngine.UI;
public class DialogflowManager : MonoBehaviour
{
public TextAsset jsonCredntialAsset;
public string projectID;
public static string FallbackIntent = "Default Fallback Intent";
public Text answerText; //답변을 받을 텍스트
public InputField questionInput; //질문을 넣을 인풋필드;
private DialogflowService service = null;
private UnityAction<string,string> callback = null;
private string sessionID; //세션아이디 Guid.newGuid로 받아옴.
private string sessionPath => $"projects/{projectID}/agent/sessions/{sessionID}"; //세션경로를 위의 변수를 받아와서 설정
private void Start() {
GetService();
answerText.text ="질문을 입력해주세요!";
}
private void GetService(){
var credentials = GoogleCredential.FromJson(jsonCredntialAsset.text);
var initializer = new Google.Apis.Services.BaseClientService.Initializer();
initializer.ApplicationName = projectID;
initializer.HttpClientInitializer = credentials.CreateScoped(DialogflowService.Scope.CloudPlatform);
service = new DialogflowService(initializer);
SetNewSession();
}
public void SetNewSession(){
//현재는 그냥 세션아이디만 받아오게.
callback = null;
sessionID = Guid.NewGuid().ToString();
//prevMessage부분은 Chatgpt가 필요해서 일단 주석.
}
public void SendTextBtn(){
Post(questionInput.text, callback);
}
public void Post (string inputText, UnityAction<string,string> callback){
ServicePost(inputText, callback);
}
private async void ServicePost(string inputText, UnityAction<string,string> callback){
if(inputText.Length <= 0){ //인풋에 아무것도 없으면
callback?.Invoke(string.Empty, string.Empty); //callback이 null이라면 null반환, 아니라면 Invoke함수에 들어간 string을 각각 반환
return;
}
this.callback = callback;
GoogleCloudDialogflowV2DetectIntentRequest request = new GoogleCloudDialogflowV2DetectIntentRequest(){
QueryInput = new GoogleCloudDialogflowV2QueryInput(){
Text = new GoogleCloudDialogflowV2TextInput(){
Text = inputText,
LanguageCode = "ko"
}
}
};
var requestIntent = service.Projects.Agent.Sessions.DetectIntent(request, sessionPath);
try{
//chatGPT는 생략
var response = await requestIntent.ExecuteAsync();
var result = response.QueryResult;
Debug.Log($"Post result: {result.Intent.DisplayName} / {result.FulfillmentText}");
answerText.text = $"{result.FulfillmentText}";
if(result.FulfillmentText.Length > 0 && result.Intent.DisplayName != FallbackIntent){
//chatgpt생략
}
} catch(Exception e){
Debug.LogWarning($"Post Error: {e.Message}");
}
finally{
}
}
}
일단, 우리가 Dialogflow를 쓰기 위해서 세션ID와, 프로젝트ID가 필요하다.
처음 start함수에 들어가있는 함수를 살펴보자.
private void Start() {
GetService();
answerText.text ="질문을 입력해주세요!";
}
private void GetService(){
var credentials = GoogleCredential.FromJson(jsonCredntialAsset.text);
var initializer = new Google.Apis.Services.BaseClientService.Initializer();
initializer.ApplicationName = projectID;
initializer.HttpClientInitializer = credentials.CreateScoped(DialogflowService.Scope.CloudPlatform);
service = new DialogflowService(initializer);
SetNewSession();
}
public void SetNewSession(){
//현재는 그냥 세션아이디만 받아오게.
callback = null;
sessionID = Guid.NewGuid().ToString();
//prevMessage부분은 Chatgpt가 필요해서 일단 주석.
}
GetService()함수를 먼저 호출해, 서버와 연결 작업을 시작한다.
이떄, 우리는 jsonCredntialAsset에 담겨있는 json파일을 서버로 넘겨 인증절차를 거친 뒤, 우리가 만들어둔 서버와 연결할 수 있게 된다.
이런식으로 DialogflowManager를 구성하였는데 Json Credntial Asset에 우리가 이전글에서 받아왔던 json인증키파일을 등록해주면 된다.
또한, 키를 받은 프로젝트의 ID를 아래 string박스에 입력해주면 된다.
그렇게 하여 처음 연결을 위한 이니셜라이저를 각각 초기화해주고, 서버와 연결한다.
이후, 대화의 동작은 다음과 같다.
public void SendTextBtn(){
Post(questionInput.text, callback);
}
public void Post (string inputText, UnityAction<string,string> callback){
ServicePost(inputText, callback);
}
private async void ServicePost(string inputText, UnityAction<string,string> callback){
if(inputText.Length <= 0){ //인풋에 아무것도 없으면
callback?.Invoke(string.Empty, string.Empty); //callback이 null이라면 null반환, 아니라면 Invoke함수에 들어간 string을 각각 반환
return;
}
this.callback = callback;
GoogleCloudDialogflowV2DetectIntentRequest request = new GoogleCloudDialogflowV2DetectIntentRequest(){
QueryInput = new GoogleCloudDialogflowV2QueryInput(){
Text = new GoogleCloudDialogflowV2TextInput(){
Text = inputText,
LanguageCode = "ko"
}
}
};
var requestIntent = service.Projects.Agent.Sessions.DetectIntent(request, sessionPath);
try{
//chatGPT는 생략
var response = await requestIntent.ExecuteAsync();
var result = response.QueryResult;
Debug.Log($"Post result: {result.Intent.DisplayName} / {result.FulfillmentText}");
answerText.text = $"{result.FulfillmentText}";
if(result.FulfillmentText.Length > 0 && result.Intent.DisplayName != FallbackIntent){
//chatgpt생략
}
} catch(Exception e){
Debug.LogWarning($"Post Error: {e.Message}");
}
finally{
}
}
맨 위의 SendTextBtn은 버튼에 붙이기 위한 함수를 선언해둔것이다. (왜인지 public으로 선언된 Post함수가 버튼에 등록이 안되서 저렇게 구현했다. 만약 Post함수가 버튼에 등록된다면 작성하지 않아도 무방하다.)
그리고 Post함수를 통해 서버로 InputField의 Text값을 비동기 전송하여 값을 받아와 Answer박스에 넣는다.
코드 중간에 GoogleCloudDialogflowV2DetectIntentRequest라는 객체를 쓰고 있는데, 이건 Google Cloud Dialogflow V2 API에서 DetectIntent 메서드에 전달하는 요청 객체이다. 이 요청 객체는 사용자의 입력을 Dialogflow로 보내고, 해당 입력에 대한 인텐트를 분석하여 응답을 받기 위해 사용하였다.
그리고, 다음 구문을 사용하였는데
QueryInput = new GoogleCloudDialogflowV2QueryInput(){
Text = new GoogleCloudDialogflowV2TextInput(){
Text = inputText,
LanguageCode = "ko"
}
}
QueryInput클래스는 사용자의 입력을 정의하기 위해 사용하였다.
입력값을 Dialogflow로 전달하려고 사용하였고, 사용자가 입력한 실제 택스트와, 택스트로 입력된 언어의 타입을 전달한다.
이렇게 만들어진 request를 내장 함수인, DetectIntent에 전달하여 답변을 받아 answer에 출력한다.
이때, 보내는 값은, 입력값과 세션 아이디를 함께 보내야 한다.
아직도 이해가 안가는 부분이 상당부분이지만, 그래도 우리가 이전에 셋팅한 값은 정확히 잘 나오는것을 확인할 수 있었다.
이전엔 이렇게 구현하였고, 이제 유니티에서 몇살이냐고 물어보자.
잘 답변하는것을 알 수 있다.
유니티에서 구현했을 땐, 버튼을 많이 만들었지만, 나중에 음성인식도 구현할거라 미리 이렇게 구성해놓은것이고, 지금 사용하는 버튼은 SendText버튼밖에 없다.
위에서 만들어둔 함수를 SendText버튼에 등록시켜주고 실행해서 버튼을 클릭하면 답변이 생성될 것이다.
지금은 인텐트를 몇개 설정 안해둬서 이상한 질문을 하면 답변을 못한다. (정확히는 인텐트에 등록되지 않은 질문을 하면 답변을 하지 못한다.)
이런식으로 말이다.
그래서 인텐트에서 케이스를 더 추가하거나, 아니면 ChatGPT와 연결하여 좀 더 다양한 답변을 할 수 있도록 구성하려고 한다.
'Develop > Dialogflow' 카테고리의 다른 글
[Dialogflow] npc대화를 인공지능으로 설정해보자! - 2. 유니티설정 (0) | 2024.06.17 |
---|---|
[Dialogflow] npc대화를 인공지능으로 설정해보자! - 1. dialogflow 생성과 가입 (0) | 2024.06.14 |