From a64f77204d79d209c47a8386e71750096ed60b59 Mon Sep 17 00:00:00 2001 From: thguss Date: Sun, 20 Oct 2024 17:43:47 +0900 Subject: [PATCH] hotfix: updated correcting method --- .../domain/diary/CorrectionService.java | 37 +---------- .../port/output/web/openai/OpenAiPort.java | 5 ++ .../output/web/gpt/adapter/OpenAiAdapter.java | 64 +++++++++++++++++++ .../gpt/adapter/dto/CorrectionsResponse.java | 10 +++ 4 files changed, 81 insertions(+), 35 deletions(-) create mode 100644 smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/dto/CorrectionsResponse.java diff --git a/smeem-application/src/main/java/com/smeem/application/domain/diary/CorrectionService.java b/smeem-application/src/main/java/com/smeem/application/domain/diary/CorrectionService.java index 68c2d1a6..6d18d248 100644 --- a/smeem-application/src/main/java/com/smeem/application/domain/diary/CorrectionService.java +++ b/smeem-application/src/main/java/com/smeem/application/domain/diary/CorrectionService.java @@ -1,8 +1,5 @@ package com.smeem.application.domain.diary; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import com.smeem.application.config.SmeemProperties; import com.smeem.application.port.input.CorrectionUseCase; import com.smeem.application.port.input.dto.response.diary.CorrectionsResponse; @@ -10,8 +7,6 @@ import com.smeem.application.port.output.persistence.CorrectionPort; import com.smeem.application.port.output.persistence.DiaryPort; import com.smeem.application.port.output.web.openai.OpenAiPort; -import com.smeem.common.exception.ExceptionCode; -import com.smeem.common.exception.SmeemException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -27,7 +22,6 @@ public class CorrectionService implements CorrectionUseCase { private final CachePort cachePort; private final CorrectionPort correctionPort; private final DiaryPort diaryPort; - private final ObjectMapper objectMapper; private final OpenAiPort openAiPort; private final SmeemProperties smeemProperties; @@ -65,34 +59,7 @@ private int updateCacheWithCorrectionCount(String key, long memberId, LocalDate } private List createCorrections(Diary diary) { - try { - String message = promptForCorrectingDiary(diary.getContent()); - String openAiResponse = openAiPort.prompt(message) - .replace("```json", "") - .replace("```", ""); - - List corrections = objectMapper.readValue(openAiResponse, new TypeReference<>() { - }); - - return correctionPort.saveAll(corrections, diary); - } catch (JsonProcessingException exception) { - throw new SmeemException(ExceptionCode.JSON_PARSE_ERROR, exception.getMessage()); - } - } - - private String promptForCorrectingDiary(String content) { - int startIndex = 0; - int endIndex = content.length() - 1; - - return String.format(""" - Paragraph : %s - Start Index : %d - End Index : %d - - JSON response description: - - original_sentence: Separate sentence from paragraph. - - corrected_sentence: corrected sentence including correct expressions. - - reason: this value MUST be Korean. reason is why the sentence is corrected. - """, content, startIndex, endIndex); + List corrections = openAiPort.promptCorrections(diary.getContent()); + return correctionPort.saveAll(corrections, diary); } } diff --git a/smeem-application/src/main/java/com/smeem/application/port/output/web/openai/OpenAiPort.java b/smeem-application/src/main/java/com/smeem/application/port/output/web/openai/OpenAiPort.java index 4fcca5af..178dcfb3 100644 --- a/smeem-application/src/main/java/com/smeem/application/port/output/web/openai/OpenAiPort.java +++ b/smeem-application/src/main/java/com/smeem/application/port/output/web/openai/OpenAiPort.java @@ -1,5 +1,10 @@ package com.smeem.application.port.output.web.openai; +import com.smeem.application.domain.diary.Correction; + +import java.util.List; + public interface OpenAiPort { String prompt(String message); + List promptCorrections(String content); } diff --git a/smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/OpenAiAdapter.java b/smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/OpenAiAdapter.java index 498be6bc..9fa7b098 100644 --- a/smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/OpenAiAdapter.java +++ b/smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/OpenAiAdapter.java @@ -1,16 +1,29 @@ package com.smeem.output.web.gpt.adapter; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.smeem.application.domain.diary.Correction; import com.smeem.application.port.output.web.openai.OpenAiPort; import com.smeem.common.exception.ExceptionCode; import com.smeem.common.exception.SmeemException; +import com.smeem.output.web.gpt.adapter.dto.CorrectionsResponse; import lombok.RequiredArgsConstructor; import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.openai.OpenAiChatModel; +import org.springframework.ai.openai.OpenAiChatOptions; +import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.ResponseFormat; import org.springframework.stereotype.Component; +import java.util.List; + @Component @RequiredArgsConstructor public class OpenAiAdapter implements OpenAiPort { private final ChatClient chatClient; + private final OpenAiChatModel chatModel; + private final ObjectMapper objectMapper; @Override public String prompt(String message) { @@ -23,4 +36,55 @@ public String prompt(String message) { throw new SmeemException(ExceptionCode.OPEN_AI_SERVICE_AVAILABLE, exception.getMessage()); } } + + @Override + public List promptCorrections(String content) { + String jsonSchema = """ + { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "original_sentence": {"type": "string"}, + "corrected_sentence": {"type": "string"}, + "reason": {"type": "string"} + }, + "required": ["original_sentence", "corrected_sentence", "reason"], + "additionalProperties": false + } + } + }, + "required": ["results"], + "additionalProperties": false + } + """; + + OpenAiChatOptions options = OpenAiChatOptions.builder() + .withResponseFormat(new ResponseFormat(ResponseFormat.Type.JSON_SCHEMA, jsonSchema)) + .build(); + + Prompt prompt = new Prompt(getCorrectionPrompt(content), options); + ChatResponse call = chatModel.call(prompt); + String response = call.getResult().getOutput().getContent(); + + try { + return objectMapper.readValue(response, CorrectionsResponse.class).results(); + } catch (JsonProcessingException e) { + throw new SmeemException(ExceptionCode.OPEN_AI_SERVICE_AVAILABLE, e.getMessage()); + } + } + + private String getCorrectionPrompt(String content) { + return String.format(""" + Paragraph : %s + + JSON response description: + - original_sentence: Separate sentence from paragraph. + - corrected_sentence: corrected sentence including correct expressions. + - reason: this value MUST be Korean. reason is why the sentence is corrected. + """, content); + } } diff --git a/smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/dto/CorrectionsResponse.java b/smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/dto/CorrectionsResponse.java new file mode 100644 index 00000000..e010c234 --- /dev/null +++ b/smeem-output-web/gpt/src/main/java/com/smeem/output/web/gpt/adapter/dto/CorrectionsResponse.java @@ -0,0 +1,10 @@ +package com.smeem.output.web.gpt.adapter.dto; + +import com.smeem.application.domain.diary.Correction; + +import java.util.List; + +public record CorrectionsResponse( + List results +) { +}