-
Notifications
You must be signed in to change notification settings - Fork 1
refactor: AiHealthDataExtractorService
#213
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
base: main
Are you sure you want to change the base?
Conversation
### Desc - `OpenAiChatService`를 사용하여 LLM API를 호출하고, 분석 결과를 받아와 DTO로 직렬화하는 `AiHealthDataExtractorService`를 수정하고자 합니다. - LLM API에 의존적인 코드들은 `OpenAiChatService`에서, 그리고 추상화된 LLM API를 호출하여 분석하는 것은 `CareCallAnalysisService`에서 담당하니 이에 맞게 구조를 재구성합니다. - `AiHealthDataExtractorService`를 삭제 - 프롬프트 빌더만 별도로 `CareCallDataExtractionPrompt`으로 분리 - `OpenAiChatService`를 호출하여 분석을 수행하는 주체가 `CareCallAnalysisService`가 되도록 변경 - Spring AI 마이그레이션 이후 불필요한 `cleanContent`과 같은 메소드 정리 - `HealthDataController`쪽도 후속 작업 예정입니다
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Caution Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted. Error details |
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.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/main/java/com/example/medicare_call/service/ai/CareCallDataExtractionPrompt.java (1)
3-5: 유틸리티 클래스로서 인스턴스화 방지 고려.정적 상수만 포함하는 유틸리티 클래스이므로,
private생성자를 추가하여 불필요한 인스턴스화를 방지하는 것이 좋습니다.♻️ 유틸리티 클래스 패턴 적용
-public class CareCallDataExtractionPrompt { +public final class CareCallDataExtractionPrompt { + + private CareCallDataExtractionPrompt() { + // Utility class - prevent instantiation + } public static final String SYSTEM_MESSAGE = "당신은 의료 통화 내용에서 건강 데이터를 추출하는 전문가입니다. 주어진 통화 내용에서 건강 관련 정보를 정확히 추출하여 JSON 형태로 응답해주세요.";
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/main/java/com/example/medicare_call/controller/HealthDataController.javasrc/main/java/com/example/medicare_call/service/ai/CareCallDataExtractionPrompt.javasrc/main/java/com/example/medicare_call/service/data_processor/CareCallAnalysisService.javasrc/test/java/com/example/medicare_call/service/ai/AiHealthDataExtractorServiceTest.javasrc/test/java/com/example/medicare_call/service/data_processor/CareCallAnalysisServiceTest.javasrc/test/java/com/example/medicare_call/service/data_processor/HealthDataExtractionIntegrationTest.java
💤 Files with no reviewable changes (1)
- src/test/java/com/example/medicare_call/service/ai/AiHealthDataExtractorServiceTest.java
🧰 Additional context used
🧬 Code graph analysis (2)
src/test/java/com/example/medicare_call/service/data_processor/CareCallAnalysisServiceTest.java (1)
src/main/java/com/example/medicare_call/service/ai/CareCallDataExtractionPrompt.java (1)
CareCallDataExtractionPrompt(3-94)
src/main/java/com/example/medicare_call/service/data_processor/CareCallAnalysisService.java (1)
src/main/java/com/example/medicare_call/service/ai/CareCallDataExtractionPrompt.java (1)
CareCallDataExtractionPrompt(3-94)
🔇 Additional comments (10)
src/test/java/com/example/medicare_call/service/data_processor/HealthDataExtractionIntegrationTest.java (1)
35-35: 변경 사항이 잘 반영되었습니다.새로운
CareCallAnalysisService.extractHealthData(LocalDate, String, List<String>)시그니처에 맞춰 테스트가 올바르게 업데이트되었습니다. 모킹 설정과 검증 로직이 일관성 있게 유지되고 있네요.Also applies to: 99-103
src/test/java/com/example/medicare_call/service/data_processor/CareCallAnalysisServiceTest.java (3)
59-60:@Value필드 주입을 위한 ReflectionTestUtils 사용 확인.
@Value("${openai.model}")필드를 테스트에서 설정하기 위해ReflectionTestUtils를 사용하는 것은 괜찮은 접근입니다. 다만, 테스트 프로파일의application-test.yml에 해당 프로퍼티를 설정하는 방법도 고려해볼 수 있어요.
69-81: 테스트 흐름이 명확합니다.OpenAI 응답 모킹과 검증 로직이 새로운 서비스 구조에 맞게 잘 작성되었네요.
contains(callRecord.getTranscriptionText())를 사용해 프롬프트에 통화 내용이 포함되는지 검증하는 부분이 좋습니다.
102-114: 예외 처리 테스트가 추가된 점 좋습니다.OpenAI 응답이 null일 때
RuntimeException이 발생하고 저장 로직이 호출되지 않는 것을 검증하네요. 서비스 코드에 TODO 주석으로 표시된 대로, 추후 커스텀 예외로 개선되면 테스트도 함께 업데이트하면 될 것 같아요.src/main/java/com/example/medicare_call/controller/HealthDataController.java (2)
46-50:medicationNames에 빈 리스트를 전달하는 것이 의도된 동작인지 확인 필요.
extractHealthData호출 시Collections.emptyList()를 전달하고 있는데, 이 경우 프롬프트에 "등록된 약 없음"으로 표시됩니다. 만약 이 엔드포인트에서도 Elder의 복약 스케줄을 활용해야 한다면, 별도로 조회하여 전달해야 할 수 있어요.단순 추출 API라면 현재 구현이 맞지만, 사용자의 복약 정보를 활용한 정확한 추출이 필요하다면 검토해 주세요.
78-86: 테스트 엔드포인트의 책임 분리가 잘 되었습니다.추출과 저장이 명확하게 분리되어
CareCallAnalysisService는 추출만,CareCallAnalysisResultSaveService는 저장만 담당하도록 구조화되었네요.src/main/java/com/example/medicare_call/service/ai/CareCallDataExtractionPrompt.java (1)
7-93: 프롬프트 템플릿이 체계적으로 구성되었습니다.추출 대상 데이터, 응답 형식, 특수 규칙(복약 데이터 분리 등)이 명확하게 정의되어 있어 LLM의 일관된 응답을 유도할 수 있겠네요.
src/main/java/com/example/medicare_call/service/data_processor/CareCallAnalysisService.java (3)
84-84: JSON 파싱 실패 시 예외 처리 고려.
beanOutputConverter.convert(content)가 OpenAI 응답이 예상 JSON 형식과 다를 경우 예외를 발생시킬 수 있습니다.@Retryable이 적용되어 재시도는 되지만, 파싱 실패와 API 실패를 구분하여 처리하면 디버깅에 도움이 될 수 있어요.
54-61: 리팩토링이 깔끔하게 완료되었습니다.복약 스케줄 조회 및
extractHealthData→processAndSaveHealthData흐름이 명확하게 분리되었네요. 스트림을 통한 중복 제거(distinct())도 적절합니다.
32-35: 필드 초기화 및 설정 주입 확인.
BeanOutputConverter를 필드에서 직접 초기화하는 것은 stateless한 변환기이므로 문제없습니다.openaiModel은@Value를 통해 주입받아 유연하게 설정 가능하네요.
| if (response != null && response.getResult() != null) { | ||
| String content = response.getResult().getOutput().getText(); | ||
| log.info("OpenAI 응답: {}", content); | ||
|
|
||
| return beanOutputConverter.convert(content); | ||
| } else { | ||
| // TODO: Custom Error Code 추가해서 예외 처리 | ||
| throw new RuntimeException("OpenAI API 응답이 비어있습니다"); | ||
| } |
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.
응답 로깅 시 민감한 건강 정보 노출 주의.
Line 82에서 OpenAI 응답 전체를 로깅하고 있는데, 이 응답에는 혈당 수치, 복약 정보 등 민감한 건강 데이터가 포함될 수 있습니다. 프로덕션 환경에서는 로그 레벨을 DEBUG로 변경하거나, 민감 정보를 마스킹하는 것을 고려해 주세요.
🔒 로그 레벨 변경 제안
if (response != null && response.getResult() != null) {
String content = response.getResult().getOutput().getText();
- log.info("OpenAI 응답: {}", content);
+ log.debug("OpenAI 응답: {}", content);
return beanOutputConverter.convert(content);
} else {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (response != null && response.getResult() != null) { | |
| String content = response.getResult().getOutput().getText(); | |
| log.info("OpenAI 응답: {}", content); | |
| return beanOutputConverter.convert(content); | |
| } else { | |
| // TODO: Custom Error Code 추가해서 예외 처리 | |
| throw new RuntimeException("OpenAI API 응답이 비어있습니다"); | |
| } | |
| if (response != null && response.getResult() != null) { | |
| String content = response.getResult().getOutput().getText(); | |
| log.debug("OpenAI 응답: {}", content); | |
| return beanOutputConverter.convert(content); | |
| } else { | |
| // TODO: Custom Error Code 추가해서 예외 처리 | |
| throw new RuntimeException("OpenAI API 응답이 비어있습니다"); | |
| } |
Desc
OpenAiChatService를 사용하여 LLM API를 호출하고, 분석 결과를 받아와 DTO로 직렬화하는AiHealthDataExtractorService를 수정하고자 합니다.OpenAiChatService에서, 그리고 추상화된 LLM API를 호출하여 분석하는 것은CareCallAnalysisService에서 담당하니 이에 맞게 구조를 재구성합니다.AiHealthDataExtractorService를 삭제CareCallDataExtractionPrompt으로 분리OpenAiChatService를 호출하여 분석을 수행하는 주체가CareCallAnalysisService가 되도록 변경cleanContent과 같은 메소드 정리HealthDataController쪽도 후속 작업 예정입니다Summary by CodeRabbit
리팩토르
✏️ Tip: You can customize this high-level summary in your review settings.