OpenAI API와의 통신을 담당한다.
Assistant 생성, thread 생성, message 생성, run 생성 등을 제공한다.
Assistant API는 다음과 같은 과정을 통해 이용 가능하다.
// 핵심 코드: getResponse
public String getResponse(String threadId, String runId) throws InterruptedException {
JsonObject object = null;
String status = JsonParser.parseString(openAiClient.checkRun(threadId, runId)).getAsJsonObject().get("status").getAsString();
while(!status.equals("completed")) {
Thread.sleep(1000);
object = JsonParser.parseString(openAiClient.checkRun(threadId, runId)).getAsJsonObject();
status = object.get("status").getAsString();
}
JsonObject jsonObject = JsonParser.parseString(openAiClient.listMessages(threadId)).getAsJsonObject();
log.info("jsonObject: {}", jsonObject);
JsonArray data = jsonObject.getAsJsonArray("data");
String result = data.get(0).getAsJsonObject()
.get("content").getAsJsonArray()
.get(0).getAsJsonObject()
.get("text").getAsJsonObject()
.get("value").getAsString();
if(result == null){
log.error("에러 발생");
return null; // Return null if the messageId is not found or doesn't have text content
}
return result;
}
주요 역할:
GPT-3와의 상호작용을 관리한다.
사용자가 입력한 질문에 대해 GPT-3의 응답을 처리한다.
핵심 메서드:
askQuestion(String question): 주어진 질문에 대해 GPT-3의 응답을 반환한다.
JSON 객체를 구성하여 질문을 OpenAI API로 전송하고, 응답을 처리한다.
주요 역할:
발음 평가를 수행한다.
주어진 오디오 파일을 기반으로 발음을 평가하고 점수를 반환한다.
발음 평가 API는 ETRI에서 제공한다.
https://aiopen.etri.re.kr/guide/Pronunciation
@Service
@Slf4j
public class PronunciationEvalService {
private final String openApiURL;
private final String accessKey;
private final String languageCode;
private final String audioFilePath;
public PronunciationEvalService(@Value("${etri.url}") String openApiURL,
@Value("${etri.access-key}") String accessKey,
@Value("${etri.language-code}") String languageCode,
@Value("${etri.file-path}") String audioFilePath) {
this.openApiURL = openApiURL;
this.accessKey = accessKey;
this.languageCode = languageCode;
this.audioFilePath = audioFilePath;
}
public String evaluate(String audioFileName){
Gson gson = new Gson();
Map<String, Object> request = new HashMap<>();
Map<String, String> argument = new HashMap<>();
String filePath = audioFilePath + "/" + audioFileName;
String audioContents = null;
try {
Path path = Paths.get(filePath);
byte[] audioBytes = Files.readAllBytes(path);
audioContents = Base64.getEncoder().encodeToString(audioBytes);
} catch (IOException e) {
e.printStackTrace();
}
argument.put("language_code", languageCode);
argument.put("audio", audioContents);
request.put("argument", argument);
URL url;
Integer responseCode = null;
String responBody = null;
try {
url = new URL(openApiURL);
HttpURLConnection con = (HttpURLConnection)url.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
con.setRequestProperty("Authorization", accessKey);
DataOutputStream wr = new DataOutputStream(con.getOutputStream());
wr.write(gson.toJson(request).getBytes("UTF-8"));
wr.flush();
wr.close();
responseCode = con.getResponseCode();
InputStream is = con.getInputStream();
byte[] buffer = new byte[is.available()];
int byteRead = is.read(buffer);
responBody = new String(buffer);
JsonObject object = JsonParser.parseString(responBody).getAsJsonObject();
String result = object.get("return_object").getAsJsonObject().get("score").getAsString();
log.info("평가 결과: {}", result);
return result;
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return responBody;
}
}
오늘 구현한 내용 중에서 가장 핵심적인 부분을 차지한 것은 바로 JsonObject
이다.
Gson을 사용하는 경우, 다음과 같은 메소드들을 제공한다.
fromJson()
: JSON 문자열을 Java 객체로 변환
toJson
: Java 객체를 JSON 문자열로 변환
JsonParser.parseString()
: JSON 문자열을 jsonElement로 변환
JsonElement VS JsonObject
JsonElement는 JSON 데이터의 모든 형태를 표현할 수 있는 추상 클래스이다.
즉, JsonObject는 JsonElement의 자식 클래스이다.
JsonElement는 다음과 같은 자식 클래스를 갖고 있다.
- JsonObject
- JsonArray
- JsonNull