Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
import java.time.LocalDate;
import java.util.List;

@Schema(description = "약물노트 그룹 카드 — 복용 시작일 + 병원 기준 묶음")
@Schema(description = "약물노트 그룹 카드 — 처방일 + 병원 기준 묶음")
public record MedicationNoteGroupResponse(

@Schema(description = "복용 시작일 (그룹 키)")
LocalDate startDate,
@Schema(description = "처방일 (파싱 성공 시 처방일, 실패 시 복용 시작일 fallback — 그룹 키)")
LocalDate prescriptionDate,

@Schema(description = "병원명 (없으면 null)")
String hospitalName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,18 @@ public List<MedicationNoteGroupResponse> searchNotes(Long userId, Long seniorId,
private List<MedicationNoteGroupResponse> toNoteGroupResponses(List<Medication> medications) {
Map<String, List<Medication>> grouped = new LinkedHashMap<>();
for (Medication m : medications) {
String key = m.getStartDate() + "|" + m.getHospitalName();
LocalDate groupDate = m.getPrescriptionDate() != null ? m.getPrescriptionDate() : m.getStartDate();
String key = groupDate + "|" + m.getHospitalName();
grouped.computeIfAbsent(key, k -> new ArrayList<>()).add(m);
}
return grouped.values().stream()
.map(group -> {
Medication first = group.get(0);
LocalDate groupDate = first.getPrescriptionDate() != null ? first.getPrescriptionDate() : first.getStartDate();
List<MedicationNoteItemResponse> items = group.stream()
.map(medicationConverter::toNoteItemResponse)
.toList();
return new MedicationNoteGroupResponse(first.getStartDate(), first.getHospitalName(), items);
return new MedicationNoteGroupResponse(groupDate, first.getHospitalName(), items);
})
.toList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,19 @@
import com.piuda.callcare.domain.ocrresult.entity.OcrResult;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.List;

@Component
public class OcrResultConverter {

// OcrResult + 파싱된 약 목록 → OcrResultResponse
public OcrResultResponse toResponse(OcrResult ocrResult, List<ParsedOcrData> parsedDrugs) {
// OcrResult + 파싱된 약 목록 + 처방일 → OcrResultResponse
public OcrResultResponse toResponse(OcrResult ocrResult, List<ParsedOcrData> parsedDrugs, LocalDate prescriptionDate) {
return new OcrResultResponse(
ocrResult.getId(),
ocrResult.getRawText(),
parsedDrugs
parsedDrugs,
prescriptionDate
);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.piuda.callcare.domain.ocrresult.dto;

import java.time.LocalDate;
import java.util.List;

public record OcrParseResult(
String rawText,
List<ParsedOcrData> parsedDrugs
List<ParsedOcrData> parsedDrugs,
LocalDate prescriptionDate // 처방일 파싱 성공 시 채워짐, 실패 시 null
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.piuda.callcare.domain.ocrresult.dto.ParsedOcrData;
import io.swagger.v3.oas.annotations.media.Schema;

import java.time.LocalDate;
import java.util.List;

@Schema(description = "OCR 분석 결과")
Expand All @@ -15,5 +16,8 @@ public record OcrResultResponse(
String rawText,

@Schema(description = "파싱된 약 목록 — 단일 약이면 1개, 표 처방전이면 여러 개")
List<ParsedOcrData> parsedDrugs
List<ParsedOcrData> parsedDrugs,

@Schema(description = "처방일 — 처방전에서 파싱 성공 시 채워짐, 실패 시 null (약 등록 시 prescriptionDate 기본값으로 사용)")
LocalDate prescriptionDate
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.piuda.callcare.domain.ocrresult.enums.OcrType;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -64,6 +65,14 @@ public class OcrParser {
"1회\\s*투약량\\s*\\d|1일\\s*투여\\s*횟수\\s*\\d|총\\s*투약\\s*일수\\s*\\d"
);

// 처방일 우선, 없으면 조제일 fallback
private static final Pattern PRESCRIPTION_DATE_PATTERN = Pattern.compile(
"(?:처방일|처방일자|처방전발행일)\\s*[:\\-]?\\s*(\\d{4})\\s*[.년\\-]\\s*(\\d{1,2})\\s*[.월\\-]?\\s*(\\d{1,2})"
);
private static final Pattern DISPENSE_DATE_PATTERN = Pattern.compile(
"(?:조제일|조제일자)\\s*[:\\-]?\\s*(\\d{4})\\s*[.년\\-]\\s*(\\d{1,2})\\s*[.월\\-]?\\s*(\\d{1,2})"
);

private static final List<String> DRUG_NAME_KEYWORDS = List.of("명칭", "약품명", "의약품");
private static final List<String> DOSAGE_KEYWORDS = List.of("투약량", "복용량", "1회");
private static final List<String> TIMES_KEYWORDS = List.of("투여횟수", "복용횟수", "횟수");
Expand All @@ -86,7 +95,7 @@ public OcrParseResult parse(List<NaverOcrApiResponse.Field> fields, OcrType ocrT
parsedDrugs = List.of(parseByRegex(rawText));
}

return new OcrParseResult(rawText, parsedDrugs);
return new OcrParseResult(rawText, parsedDrugs, extractPrescriptionDate(rawText));
}

// ── rawText 조립 ──────────────────────────────────────────────────────────
Expand Down Expand Up @@ -463,6 +472,27 @@ private Integer extractTotalDays(String text) {
return null;
}

// ── 처방일 추출 ───────────────────────────────────────────────────────────

// 처방일 우선 파싱, 없으면 조제일 fallback
private LocalDate extractPrescriptionDate(String rawText) {
LocalDate date = tryExtractDate(PRESCRIPTION_DATE_PATTERN, rawText);
return date != null ? date : tryExtractDate(DISPENSE_DATE_PATTERN, rawText);
}

private LocalDate tryExtractDate(Pattern pattern, String text) {
Matcher m = pattern.matcher(text);
if (!m.find()) return null;
try {
int year = Integer.parseInt(m.group(1));
int month = Integer.parseInt(m.group(2).trim());
int day = Integer.parseInt(m.group(3).trim());
return LocalDate.of(year, month, day);
} catch (Exception e) {
return null;
}
}

// ── 좌표 유틸 ─────────────────────────────────────────────────────────────

private double centerX(NaverOcrApiResponse.Field field) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ public OcrResultResponse processOcr(Long userId, Long seniorId, MultipartFile im
log.info("OCR 처리 완료 - ocrResultId: {}, ocrType: {}, 파싱된 약 수: {}",
saved.getId(), ocrType, parseResult.parsedDrugs().size());

return ocrResultConverter.toResponse(saved, parseResult.parsedDrugs());
return ocrResultConverter.toResponse(saved, parseResult.parsedDrugs(), parseResult.prescriptionDate());
}
}