diff --git a/src/main/kotlin/me/misik/api/api/response/ParsedOcrResponse.kt b/src/main/kotlin/me/misik/api/api/response/ParsedOcrResponse.kt index a3c1461..144cb5a 100644 --- a/src/main/kotlin/me/misik/api/api/response/ParsedOcrResponse.kt +++ b/src/main/kotlin/me/misik/api/api/response/ParsedOcrResponse.kt @@ -1,10 +1,11 @@ package me.misik.api.api.response data class ParsedOcrResponse( - val parsed: List + val status: Boolean, + val parsed: List, ) { data class KeyValuePair( val key: String, val value: String, ) -} \ No newline at end of file +} diff --git a/src/main/kotlin/me/misik/api/app/CreateReviewFacade.kt b/src/main/kotlin/me/misik/api/app/CreateReviewFacade.kt index 7888747..16dd8a7 100644 --- a/src/main/kotlin/me/misik/api/app/CreateReviewFacade.kt +++ b/src/main/kotlin/me/misik/api/app/CreateReviewFacade.kt @@ -11,13 +11,14 @@ import me.misik.api.core.OcrParser import me.misik.api.domain.CreateReviewCache import me.misik.api.domain.Review import me.misik.api.domain.ReviewService +import me.misik.api.domain.prompt.Prompt import me.misik.api.domain.prompt.PromptService +import me.misik.api.domain.prompt.PromptType import me.misik.api.domain.request.CreateReviewRequest import me.misik.api.domain.request.OcrTextRequest import org.slf4j.LoggerFactory import org.springframework.stereotype.Service - @Service class CreateReviewFacade( private val chatbot: Chatbot, @@ -73,11 +74,18 @@ class CreateReviewFacade( } } - fun parseOcrText(ocrText: OcrTextRequest): ParsedOcrResponse = parseOcrWithRetry(ocrText, 0) + fun parseOcrText(ocrText: OcrTextRequest): ParsedOcrResponse { + val prompt = promptService.findAllByType(PromptType.OCR).first() + return parseOcrWithRetry(prompt, ocrText, 0) + } - private fun parseOcrWithRetry(ocrText: OcrTextRequest, retryCount: Int): ParsedOcrResponse { + private fun parseOcrWithRetry( + prompt: Prompt, + ocrText: OcrTextRequest, + retryCount: Int, + ): ParsedOcrResponse { return runCatching { - val response = ocrParser.createParsedOcr(OcrParser.Request.from(ocrText.text)) + val response = ocrParser.createParsedOcr(OcrParser.Request.of(prompt, ocrText.text)) val responseContent = response.result?.message?.content ?: "" logger.info("ocr responseContent $responseContent") @@ -85,13 +93,14 @@ class CreateReviewFacade( val parsedOcr = objectMapper.readValue(responseContent, ParsedOcrResponse::class.java) ?: throw IllegalStateException("Invalid OCR text format") + require(parsedOcr.status) { "Wrong ocr request \"$ocrText\"" } require(parsedOcr.parsed.isEmpty().not()) { "Parsed OCR content is empty" } parsedOcr }.getOrElse { logger.error("OCR Parsing fail", it) if (retryCount < MAX_RETRY_COUNT) { - return@getOrElse parseOcrWithRetry(ocrText, retryCount + 1) + return@getOrElse parseOcrWithRetry(prompt, ocrText, retryCount + 1) } throw it } diff --git a/src/main/kotlin/me/misik/api/core/OcrParser.kt b/src/main/kotlin/me/misik/api/core/OcrParser.kt index e2175b2..56706c2 100644 --- a/src/main/kotlin/me/misik/api/core/OcrParser.kt +++ b/src/main/kotlin/me/misik/api/core/OcrParser.kt @@ -1,5 +1,6 @@ package me.misik.api.core +import me.misik.api.domain.prompt.Prompt import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.service.annotation.PostExchange @@ -33,32 +34,12 @@ fun interface OcrParser { } companion object { - val cachedParsingSystemMessage = Message.createSystem( - """ - 리뷰에 쓸만한 정보를 추출해줘. key에는 방문 장소명, 품명 등이 포함될 수 있어. key는 최대 3개만 뽑아줘. - 응답 형식은 반드시 다음과 같은 JSON이야. 응답에는 해당 JSON만 있어야해. - { - "parsed": [ - { - "key": "품명", - "value": "카야토스트+음료세트" - }, - { - "key": "가격", - "value": "3000" - }, - ... - ] - } - 응답의 총 길이는 300자를 넘으면 안돼. - """ - ) - fun from(ocrText: String): Request { + fun of(prompt: Prompt, ocrText: String): Request { return Request( messages = listOf( - cachedParsingSystemMessage, - Message.createUser(ocrText) + Message.createSystem(prompt.command), + Message.createUser(ocrText), ) ) } @@ -71,15 +52,16 @@ fun interface OcrParser { ) { data class Status( val code: String, - val message: String + val message: String, ) + data class Result( val message: Message? ) { data class Message( val role: String, - val content: String + val content: String, ) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/me/misik/api/domain/prompt/Prompt.kt b/src/main/kotlin/me/misik/api/domain/prompt/Prompt.kt index 324eb8f..9744f08 100644 --- a/src/main/kotlin/me/misik/api/domain/prompt/Prompt.kt +++ b/src/main/kotlin/me/misik/api/domain/prompt/Prompt.kt @@ -7,17 +7,21 @@ import me.misik.api.domain.ReviewStyle @Entity @Table( name = "prompt", - uniqueConstraints = [UniqueConstraint(columnNames = ["style"])] + uniqueConstraints = [UniqueConstraint(columnNames = ["style"])], ) class Prompt( @Id @Column(name = "id") val id: Long, - @Column(name = "style", columnDefinition = "VARCHAR(20)", nullable = false) @Enumerated(EnumType.STRING) + @Column(name = "style", columnDefinition = "VARCHAR(20)", nullable = false) val style: ReviewStyle, @Column(name = "command", columnDefinition = "TEXT", nullable = false) val command: String, + + @Enumerated(EnumType.STRING) + @Column(name = "type", columnDefinition = "VARCHAR(20)", nullable = false) + val type: PromptType, ) : AbstractTime() diff --git a/src/main/kotlin/me/misik/api/domain/prompt/PromptRepository.kt b/src/main/kotlin/me/misik/api/domain/prompt/PromptRepository.kt index 23e373a..d7c536b 100644 --- a/src/main/kotlin/me/misik/api/domain/prompt/PromptRepository.kt +++ b/src/main/kotlin/me/misik/api/domain/prompt/PromptRepository.kt @@ -8,4 +8,7 @@ import org.springframework.data.repository.query.Param interface PromptRepository : JpaRepository { @Query("SELECT p FROM Prompt p WHERE p.style = :reviewStyle") fun findByReviewStyleOrNull(@Param("reviewStyle") reviewStyle: ReviewStyle?): Prompt? -} \ No newline at end of file + + @Query("SELECt p FROM Prompt p WHERE p.type = :promptType") + fun findAllByType(@Param("promptType") promptType: PromptType): List +} diff --git a/src/main/kotlin/me/misik/api/domain/prompt/PromptService.kt b/src/main/kotlin/me/misik/api/domain/prompt/PromptService.kt index 60f11a5..cdc210e 100644 --- a/src/main/kotlin/me/misik/api/domain/prompt/PromptService.kt +++ b/src/main/kotlin/me/misik/api/domain/prompt/PromptService.kt @@ -7,8 +7,11 @@ import org.springframework.transaction.annotation.Transactional @Service @Transactional(readOnly = true) class PromptService( - private val promptRepository: PromptRepository + private val promptRepository: PromptRepository, ) { + fun getByStyle(reviewStyle: ReviewStyle): Prompt = promptRepository.findByReviewStyleOrNull(reviewStyle) ?: throw IllegalArgumentException("Cannot find prompt by review style \"$reviewStyle\"") -} \ No newline at end of file + + fun findAllByType(promptType: PromptType): List = promptRepository.findAllByType(promptType) +} diff --git a/src/main/kotlin/me/misik/api/domain/prompt/PromptType.kt b/src/main/kotlin/me/misik/api/domain/prompt/PromptType.kt new file mode 100644 index 0000000..b7bb231 --- /dev/null +++ b/src/main/kotlin/me/misik/api/domain/prompt/PromptType.kt @@ -0,0 +1,7 @@ +package me.misik.api.domain.prompt + +enum class PromptType { + OCR, + REVIEW_CREATE, + ; +} diff --git a/src/main/resources/ddl/prompt.ddl b/src/main/resources/ddl/prompt similarity index 100% rename from src/main/resources/ddl/prompt.ddl rename to src/main/resources/ddl/prompt