Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: AI 서버 연동 로직 구현 (#35) #36

Merged
merged 1 commit into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
kotlin("jvm")
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

35 changes: 0 additions & 35 deletions clients/client-example/src/main/resources/client-example.yml

This file was deleted.

22 changes: 22 additions & 0 deletions clients/client/src/main/kotlin/org/mediscan/client/AiServiceApi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.mediscan.client

import org.springframework.cloud.openfeign.FeignClient
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RequestPart
import org.springframework.web.multipart.MultipartFile

@FeignClient(name = "ai-service", url = "127.0.0.1:8000")
internal interface AiServiceApi {
@RequestMapping(
method = [RequestMethod.POST],
value = ["/predict"],
consumes = [MediaType.MULTIPART_FORM_DATA_VALUE],
)
fun predictPill(
@RequestPart frontImage: MultipartFile,
@RequestPart backImage: MultipartFile,
@RequestPart pillCsv: MultipartFile,
): AiServiceResponseDto
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.mediscan.client

import org.mediscan.client.model.AiServiceClientResult
import org.springframework.stereotype.Component
import org.springframework.web.multipart.MultipartFile

@Component
class AiServiceClient internal constructor(
private val aiServiceApi: AiServiceApi,
) {
fun predict(
pillCsv: MultipartFile,
frontImage: MultipartFile,
backImage: MultipartFile,
): List<AiServiceClientResult> {
return aiServiceApi.predictPill(frontImage, backImage, pillCsv).result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.mediscan.client

import org.springframework.web.multipart.MultipartFile

internal data class AiServiceRequestDto(
val frontImage: MultipartFile,
val backImage: MultipartFile,
val pillCsv: MultipartFile,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.mediscan.client

import org.mediscan.client.model.AiServiceClientResult

internal data class AiServiceResponseDto(
val result: List<AiServiceClientResult>,
)
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.mediscan.client.example
package org.mediscan.client

import org.springframework.cloud.openfeign.EnableFeignClients
import org.springframework.context.annotation.Configuration

@EnableFeignClients
@Configuration
internal class ExampleConfig
internal class FeignConfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.mediscan.client.model

data class AiServiceClientResult(
val rank: Long,
val code: String,
val accuracy: Double,
)
2 changes: 1 addition & 1 deletion core/core-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dependencies {
implementation(project(":support:monitoring"))
implementation(project(":support:logging"))
implementation(project(":storage:db-core"))
implementation(project(":clients:client-example"))
implementation(project(":clients:client"))

testImplementation(project(":tests:api-docs"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.mediscan.core.api.controller.v1.response

data class PillIdentificationResponseDto(
val pillId: String,
val rank: Long,
val pillName: String?,
val itemImage: String?,
val className: String?,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,29 @@ package org.mediscan.core.api.domain

import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVPrinter
import org.apache.commons.io.output.ByteArrayOutputStream
import org.springframework.stereotype.Component
import java.io.OutputStreamWriter
import java.io.File
import java.io.FileWriter

@Component
class PillManager {
fun createCsvInMemory(pillShape: String, pillFrontMarking: String?, pillBackMarking: String?): ByteArray {
val outputStream = ByteArrayOutputStream()
val writer = OutputStreamWriter(outputStream)
fun createCsvFile(pillShape: String, pillFrontMarking: String?, pillBackMarking: String?, filePath: String) {
val file = File(filePath)
val parentDir = file.parentFile
if (!parentDir.exists()) {
parentDir.mkdirs()
}
val writer = FileWriter(file)
val csvPrinter =
CSVPrinter(writer, CSVFormat.DEFAULT.builder().setHeader("shape", "f_text", "b_text", "drug_code").build())
CSVPrinter(writer, CSVFormat.DEFAULT.builder().setHeader("shape", "f_text", "b_text", "drug_code").setDelimiter('\t').build())

csvPrinter.printRecord(
pillShape,
pillFrontMarking.let { it ?: "none" },
pillBackMarking.let { it ?: "none" },
pillFrontMarking ?: "none",
pillBackMarking ?: "none",
"none",
)
csvPrinter.flush()
csvPrinter.close()

return outputStream.toByteArray()
}
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,55 @@
package org.mediscan.core.api.domain

import org.mediscan.client.AiServiceClient
import org.mediscan.core.api.controller.v1.response.PillDetailResponseDto
import org.mediscan.core.api.controller.v1.response.PillIdentificationResponseDto
import org.mediscan.core.api.controller.v1.response.PillSearchResponseDto
import org.mediscan.core.api.support.utils.FileMultipartFile
import org.mediscan.core.enums.Color
import org.springframework.stereotype.Service
import java.io.File

@Service
class PillService(
private val pillManager: PillManager,
private val pillReader: PillReader,
private val aiServiceClient: AiServiceClient,
) {
fun identifyPill(
pillIdentificationData: PillIdentificationData,
): List<PillIdentificationResponseDto> {
val createCsvInMemory = pillManager.createCsvInMemory(
val csvFileName = "./data/pill.csv"

pillManager.createCsvFile(
pillIdentificationData.pillShape,
pillIdentificationData.frontMarking,
pillIdentificationData.backMarking,
csvFileName,
)
var result: MutableList<PillIdentificationResponseDto> = mutableListOf()

val rank1: Pill = pillReader.readPill("198600161")
val rank2: Pill = pillReader.readPill("199301111")
val rank3: Pill = pillReader.readPill("199302061")
val rank4: Pill = pillReader.readPill("199501735")
val rank5: Pill = pillReader.readPill("199302671")
try {
val aiServiceClientResult = aiServiceClient.predict(
FileMultipartFile(File(csvFileName), "text/csv"),
pillIdentificationData.frontImage,
pillIdentificationData.backImage,
)
val responseDtoList = mutableListOf<PillIdentificationResponseDto>()
for (result in aiServiceClientResult) {
val pill = pillReader.readPill(result.code)
val responseDto = PillIdentificationResponseDto(
pill.itemSeq,
result.rank,
pill.itemName,
pill.itemImage,
pill.className,
(result.accuracy * 100).toLong(),
)
responseDtoList.add(responseDto)
}

result.add(PillIdentificationResponseDto(rank1.itemSeq, rank1.itemName, rank1.itemImage, rank1.className, 60))
result.add(PillIdentificationResponseDto(rank2.itemSeq, rank2.itemName, rank2.itemImage, rank2.className, 56))
result.add(PillIdentificationResponseDto(rank3.itemSeq, rank3.itemName, rank3.itemImage, rank3.className, 55))
result.add(PillIdentificationResponseDto(rank4.itemSeq, rank4.itemName, rank4.itemImage, rank4.className, 47))
result.add(PillIdentificationResponseDto(rank5.itemSeq, rank5.itemName, rank5.itemImage, rank5.className, 47))
return result
return responseDtoList
} finally {
File(csvFileName).delete()
}
}

fun searchPill(
Expand Down
Loading
Loading