diff --git a/src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt b/src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt index 368f39f..188ed31 100644 --- a/src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt +++ b/src/main/kotlin/simplerag/ragback/domain/prompt/controller/PromptController.kt @@ -3,8 +3,8 @@ package simplerag.ragback.domain.prompt.controller import jakarta.validation.Valid import org.springframework.http.HttpStatus import org.springframework.web.bind.annotation.* -import simplerag.ragback.domain.prompt.dto.PromptCreateRequest -import simplerag.ragback.domain.prompt.dto.PromptPreviewResponse +import simplerag.ragback.domain.index.dto.IndexUpdateRequest +import simplerag.ragback.domain.prompt.dto.* import simplerag.ragback.domain.prompt.service.PromptService import simplerag.ragback.global.response.ApiResponse @@ -23,4 +23,38 @@ class PromptController( return ApiResponse.ok(savedPrompt) } + @GetMapping("/{promptId}") + fun getPrompt( + @PathVariable promptId: Long, + ): ApiResponse { + val promptDetail = promptService.getPrompt(promptId) + return ApiResponse.ok(promptDetail) + } + + @GetMapping + fun getPrompts( + @RequestParam cursor: Long, + @RequestParam take: Int, + ): ApiResponse { + val promptPreviewResponseList = promptService.getPrompts(cursor, take) + return ApiResponse.ok(promptPreviewResponseList) + } + + @PutMapping("/{promptId}") + fun updatePrompt( + @RequestBody @Valid promptUpdateRequest: PromptUpdateRequest, + @PathVariable promptId: Long, + ): ApiResponse { + val updatedPrompt = promptService.updatePrompt(promptUpdateRequest, promptId) + return ApiResponse.ok(updatedPrompt) + } + + @DeleteMapping("/{promptId}") + fun deletePrompt( + @PathVariable promptId: Long, + ): ApiResponse { + promptService.deletePrompt(promptId) + return ApiResponse.ok(null, "프롬프트가 삭제되었습니다.") + } + } \ No newline at end of file diff --git a/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt b/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt index 95ea0b1..7e9864a 100644 --- a/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt +++ b/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptRequestDTO.kt @@ -9,5 +9,13 @@ data class PromptCreateRequest( val name: String, val preSet: PreSet, @field:Size(max = 20000) - val systemPrompt: String, + val systemPrompt: String?, +) + +data class PromptUpdateRequest( + @field:Size(max = 100) + val name: String, + val preSet: PreSet, + @field:Size(max = 20000) + val systemPrompt: String?, ) \ No newline at end of file diff --git a/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt b/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt index 43d73ff..3ad6036 100644 --- a/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt +++ b/src/main/kotlin/simplerag/ragback/domain/prompt/dto/PromptResponseDTO.kt @@ -1,15 +1,49 @@ package simplerag.ragback.domain.prompt.dto import simplerag.ragback.domain.prompt.entity.Prompt +import simplerag.ragback.domain.prompt.entity.enums.PreSet + +data class PromptPreviewResponseList( + val promptPreviewResponseList: List, + val cursor: Long?, + val hasNext: Boolean +) { + companion object { + fun from(prompts: List, cursor: Long?, hasNext: Boolean): PromptPreviewResponseList = + PromptPreviewResponseList( + promptPreviewResponseList = prompts.map { prompt -> + PromptPreviewResponse.from(prompt) + }, + cursor = cursor, + hasNext = hasNext, + ) + } +} data class PromptPreviewResponse( val id: Long, + val name: String, ) { companion object { fun from( prompt: Prompt ): PromptPreviewResponse { - return PromptPreviewResponse(prompt.id) + return PromptPreviewResponse(prompt.id, prompt.name) + } + } +} + +data class PromptDetailResponse( + val id: Long, + val name: String, + val preSet: PreSet, + val systemPrompt: String, +) { + companion object { + fun from( + prompt: Prompt + ): PromptDetailResponse { + return PromptDetailResponse(prompt.id, prompt.name, prompt.preSet, prompt.systemPrompt) } } } \ No newline at end of file diff --git a/src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt b/src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt index 637d652..2f7476d 100644 --- a/src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt +++ b/src/main/kotlin/simplerag/ragback/domain/prompt/entity/Prompt.kt @@ -3,22 +3,25 @@ package simplerag.ragback.domain.prompt.entity import simplerag.ragback.domain.prompt.entity.enums.PreSet import jakarta.persistence.* import simplerag.ragback.domain.prompt.dto.PromptCreateRequest +import simplerag.ragback.domain.prompt.dto.PromptUpdateRequest import simplerag.ragback.global.entity.BaseEntity +import simplerag.ragback.global.error.ErrorCode +import simplerag.ragback.global.error.PromptException @Entity @Table(name = "prompts") class Prompt( @Column(name = "name", length = 100, nullable = false) - val name: String, + var name: String, @Enumerated(EnumType.STRING) @Column(name = "pre_set", nullable = false) - val preSet: PreSet, + var preSet: PreSet, @Column(name = "system_prompt", nullable = false) @Lob - val systemPrompt: String, + var systemPrompt: String, ) : BaseEntity() { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -26,25 +29,41 @@ class Prompt( val id: Long = 0 companion object { - fun from( - promptCreateRequest: PromptCreateRequest - ): Prompt { - - val prompt = if (promptCreateRequest.preSet == PreSet.CUSTOM) { - Prompt( - promptCreateRequest.name, - promptCreateRequest.preSet, - promptCreateRequest.systemPrompt - ) - } else { - Prompt( + fun from(promptCreateRequest: PromptCreateRequest): Prompt = + when (promptCreateRequest.preSet) { + PreSet.CUSTOM -> Prompt( promptCreateRequest.name, promptCreateRequest.preSet, - promptCreateRequest.preSet.defaultSystemPrompt + promptCreateRequest.systemPrompt ?: "" ) + else -> { + if(!promptCreateRequest.systemPrompt.isNullOrBlank()) { + throw PromptException(ErrorCode.CUSTOM_SYSTEM_PROMPT) + } + Prompt( + promptCreateRequest.name, + promptCreateRequest.preSet, + promptCreateRequest.preSet.defaultSystemPrompt + ) + } } + } - return prompt + fun update(promptUpdateRequest: PromptUpdateRequest) { + when (promptUpdateRequest.preSet) { + PreSet.CUSTOM -> { + this.name = promptUpdateRequest.name + this.systemPrompt = promptUpdateRequest.systemPrompt ?: "" + this.preSet = promptUpdateRequest.preSet + } + else -> { + if(!promptUpdateRequest.systemPrompt.isNullOrBlank()) { + throw PromptException(ErrorCode.CUSTOM_SYSTEM_PROMPT) + } + this.name = promptUpdateRequest.name + this.systemPrompt = promptUpdateRequest.preSet.defaultSystemPrompt + this.preSet = promptUpdateRequest.preSet + } } } } \ No newline at end of file diff --git a/src/main/kotlin/simplerag/ragback/domain/prompt/repository/PromptRepository.kt b/src/main/kotlin/simplerag/ragback/domain/prompt/repository/PromptRepository.kt index fb893ff..9a0d21c 100644 --- a/src/main/kotlin/simplerag/ragback/domain/prompt/repository/PromptRepository.kt +++ b/src/main/kotlin/simplerag/ragback/domain/prompt/repository/PromptRepository.kt @@ -1,6 +1,10 @@ package simplerag.ragback.domain.prompt.repository +import org.springframework.data.domain.Pageable +import org.springframework.data.domain.Slice import org.springframework.data.jpa.repository.JpaRepository import simplerag.ragback.domain.prompt.entity.Prompt -interface PromptRepository: JpaRepository \ No newline at end of file +interface PromptRepository: JpaRepository { + fun findByIdGreaterThanOrderById(cursor: Long, pageable: Pageable): Slice +} \ No newline at end of file diff --git a/src/main/kotlin/simplerag/ragback/domain/prompt/service/PromptService.kt b/src/main/kotlin/simplerag/ragback/domain/prompt/service/PromptService.kt index acb988d..ed28d81 100644 --- a/src/main/kotlin/simplerag/ragback/domain/prompt/service/PromptService.kt +++ b/src/main/kotlin/simplerag/ragback/domain/prompt/service/PromptService.kt @@ -1,11 +1,16 @@ package simplerag.ragback.domain.prompt.service +import org.springframework.data.domain.PageRequest +import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import simplerag.ragback.domain.prompt.dto.PromptCreateRequest -import simplerag.ragback.domain.prompt.dto.PromptPreviewResponse +import simplerag.ragback.domain.document.dto.DataFileDetailResponseList +import simplerag.ragback.domain.document.dto.TagDTO +import simplerag.ragback.domain.prompt.dto.* import simplerag.ragback.domain.prompt.entity.Prompt import simplerag.ragback.domain.prompt.repository.PromptRepository +import simplerag.ragback.global.error.ErrorCode +import simplerag.ragback.global.error.PromptException @Service @Transactional(readOnly = true) @@ -21,4 +26,36 @@ class PromptService( val savedPrompt = promptRepository.save(prompt) return PromptPreviewResponse.from(savedPrompt) } + + fun getPrompt(promptId: Long): PromptDetailResponse { + val prompt = promptRepository.findByIdOrNull(promptId) ?: throw PromptException(ErrorCode.NOT_FOUND) + return PromptDetailResponse.from(prompt) + } + + fun getPrompts( + cursor: Long, + take: Int + ): PromptPreviewResponseList { + val prompts = promptRepository.findByIdGreaterThanOrderById(cursor, PageRequest.of(0, take)) + + val nextCursor = prompts.content.lastOrNull()?.id + + return PromptPreviewResponseList.from(prompts.content, nextCursor, prompts.hasNext()) + } + + @Transactional + fun updatePrompt( + promptUpdateRequest: PromptUpdateRequest, + promptId: Long + ): PromptPreviewResponse { + val prompt = promptRepository.findByIdOrNull(promptId) ?: throw PromptException(ErrorCode.NOT_FOUND) + prompt.update(promptUpdateRequest) + return PromptPreviewResponse.from(prompt) + } + + @Transactional + fun deletePrompt(promptId: Long) { + val prompt = promptRepository.findByIdOrNull(promptId) ?: throw PromptException(ErrorCode.NOT_FOUND) + promptRepository.delete(prompt) + } } \ No newline at end of file diff --git a/src/main/kotlin/simplerag/ragback/global/error/CustomException.kt b/src/main/kotlin/simplerag/ragback/global/error/CustomException.kt index c824906..e6ec4ec 100644 --- a/src/main/kotlin/simplerag/ragback/global/error/CustomException.kt +++ b/src/main/kotlin/simplerag/ragback/global/error/CustomException.kt @@ -20,4 +20,9 @@ class FileException( override val errorCode: ErrorCode, override val message: String, override val cause: Throwable? = null, -) : CustomException(errorCode, message, cause) \ No newline at end of file +) : CustomException(errorCode, message, cause) + +class PromptException( + override val errorCode: ErrorCode, + override val cause: Throwable? = null, +) : CustomException(errorCode, errorCode.message, cause) diff --git a/src/main/kotlin/simplerag/ragback/global/error/ErrorCode.kt b/src/main/kotlin/simplerag/ragback/global/error/ErrorCode.kt index 308a7ed..65ff8e5 100644 --- a/src/main/kotlin/simplerag/ragback/global/error/ErrorCode.kt +++ b/src/main/kotlin/simplerag/ragback/global/error/ErrorCode.kt @@ -25,5 +25,8 @@ enum class ErrorCode( S3_UNSUPPORTED_CONTENT_TYPE(HttpStatus.BAD_REQUEST, "S3_007", "지원하지 않는 Content-Type 입니다."), // index - OVERLAP_OVERFLOW(HttpStatus.BAD_REQUEST, "INDEX_001", "overlap 크기는 chunking 크기를 넘을 수 없습니다.") + OVERLAP_OVERFLOW(HttpStatus.BAD_REQUEST, "INDEX_001", "overlap 크기는 chunking 크기를 넘을 수 없습니다."), + + // prompt + CUSTOM_SYSTEM_PROMPT(HttpStatus.BAD_REQUEST, "PROMPT_001", "preset이 Custom이 아닐 때 systemPrompt의 조작이 불가능합니다.") }