-
Notifications
You must be signed in to change notification settings - Fork 6
[VISION] 반려동물 이미지 분석/보고서/추천 플로우 개선 및 폰트 적용 #40
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3,20 +3,25 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.github.petty.vision.helper.ImageValidator; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.github.petty.vision.helper.ImageValidator.ValidationResult; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.github.petty.vision.port.in.VisionUseCase; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import io.github.petty.vision.service.VisionServiceImpl; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import lombok.extern.slf4j.Slf4j; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.stereotype.Controller; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.bind.annotation.*; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.multipart.MultipartFile; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.web.server.ResponseStatusException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import org.springframework.http.HttpStatus; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import jakarta.servlet.http.HttpSession; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import java.io.IOException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Slf4j | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @Controller | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestMapping("/vision") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class VisionController { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final VisionUseCase vision; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final VisionServiceImpl visionService; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
23
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아키텍처 문제: 추상화와 구현체를 동시에 의존하고 있습니다. 컨트롤러가
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| private final ImageValidator imageValidator; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @GetMapping("/upload") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -28,14 +33,30 @@ public String page() { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @ResponseBody | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String getSpeciesInterim( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam("file") MultipartFile file, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam("petName") String petName | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam("petName") String petName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpSession session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) throws IOException { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 파일 유효성 검사 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ValidationResult vr = imageValidator.validate(file); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!vr.isValid()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new ResponseStatusException(HttpStatus.BAD_REQUEST, vr.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // UnifiedFlowController와 호환되도록 세션에 데이터 저장 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session.setAttribute("petName", petName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 파일을 임시로 저장 (나중에 analyze에서 사용) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| byte[] imageBytes = file.getBytes(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session.setAttribute("tempImageBytes", imageBytes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 이미지를 Base64로 인코딩하여 세션에 저장 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.warn("이미지 저장 실패", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+45
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 메모리 사용량 최적화가 필요합니다. 현재 구현은 동일한 이미지를 두 가지 형태(원본 바이트와 Base64 문자열)로 세션에 저장하고 있어 메모리를 비효율적으로 사용합니다. 대용량 이미지의 경우 세션 메모리 부족 문제가 발생할 수 있습니다. 다음 중 하나의 방법을 고려해보세요:
- // 파일을 임시로 저장 (나중에 analyze에서 사용)
- try {
- byte[] imageBytes = file.getBytes();
- session.setAttribute("tempImageBytes", imageBytes);
-
- // 이미지를 Base64로 인코딩하여 세션에 저장
- String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
- session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
- } catch (IOException e) {
- log.warn("이미지 저장 실패", e);
- }
+ // 이미지를 Base64로 인코딩하여 세션에 저장 (메모리 효율성을 위해 한 번만 저장)
+ try {
+ byte[] imageBytes = file.getBytes();
+ String imageBase64 = java.util.Base64.getEncoder().encodeToString(imageBytes);
+ session.setAttribute("petImageBase64", "data:image/jpeg;base64," + imageBase64);
+ } catch (IOException e) {
+ log.warn("이미지 저장 실패", e);
+ throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "이미지 처리 중 오류가 발생했습니다.");
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 기존 서비스 호출 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vision.interim(file.getBytes(), petName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -44,15 +65,30 @@ public String getSpeciesInterim( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @ResponseBody | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public String analyze( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam("file") MultipartFile file, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam("petName") String petName | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @RequestParam("petName") String petName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| HttpSession session | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 파일 유효성 검사 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ValidationResult vr = imageValidator.validate(file); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!vr.isValid()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new ResponseStatusException(HttpStatus.BAD_REQUEST, vr.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // 기존 서비스 호출 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vision.analyze(file, petName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Vision 분석 결과 생성 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| String visionReport = visionService.analyze(file, petName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // UnifiedFlowController와 호환되도록 세션에 결과 저장 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session.setAttribute("visionReport", visionReport); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| session.setAttribute("petName", petName); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.info("✅ Vision 분석 완료 - petName: {}, reportLength: {}", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| petName, visionReport != null ? visionReport.length() : 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return visionReport; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (Exception e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| log.error("❌ Vision 분석 실패", e); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "분석 중 오류가 발생했습니다: " + e.getMessage()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
이미지 인코딩 로직이 중복되어 있습니다.
VisionController의
/species엔드포인트에서 이미 이미지를 Base64로 인코딩하여 세션에 저장하고 있습니다. 여기서 다시 동일한 작업을 수행하는 것은 불필요한 중복입니다.이미 세션에 저장된 이미지를 재사용하거나, 공통 유틸리티 메서드로 추출하는 것을 권장합니다.
📝 Committable suggestion
🤖 Prompt for AI Agents