Skip to content

Commit e61eea3

Browse files
authored
Merge pull request #60 from DIDIM-ai/fix/#59-filter-non-math-image
fix: GPT Vision 실패 시 image 및 log_solve 삭제 처리 (#59)
2 parents d11e1e5 + 0b299fe commit e61eea3

File tree

1 file changed

+53
-15
lines changed

1 file changed

+53
-15
lines changed

src/main/java/com/likelion/ai_teacher_a/domain/logsolve/service/LogSolveService.java

Lines changed: 53 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public Map<String, Object> executeMath(Long logSolveId, int grade) {
6666

6767
String gptContent = sendGptRequest(payload);
6868
Map<String, Object> result = parseGptJson(gptContent);
69+
validateMathJson(result);
6970
String resultJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(result);
7071

7172
logSolve.setResult(resultJson);
@@ -122,33 +123,70 @@ private String buildPromptByGrade(int grade) {
122123

123124

124125
public ResponseEntity<?> handleSolveImage(MultipartFile imageFile, User user, UserJr userJr, int grade) {
126+
Image image = null;
127+
LogSolve logSolve = null;
128+
125129
try {
126130
if (grade < 1 || grade > 6) {
127131
return ResponseEntity.badRequest().body(Map.of("message", "학년 정보가 올바르지 않습니다 (1~6학년만 허용)"));
128132
}
129133

130-
Long logSolveId = createLogAndReturnId(imageFile, user, userJr);
131-
executeMath(logSolveId, grade);
134+
ImageResponseDto imageDto = imageService.uploadToS3AndSave(imageFile, ImageType.ETC, user);
135+
image = imageRepository.findById(imageDto.getImageId())
136+
.orElseThrow(() -> new RuntimeException("이미지 없음"));
137+
138+
// 2. log_solve에 임시로 저장
139+
logSolve = logSolveRepository.save(
140+
LogSolve.builder()
141+
.image(image)
142+
.user(user)
143+
.userJr(userJr)
144+
.build()
145+
);
146+
147+
Map<String, Object> result = executeMath(logSolve.getLogSolveId(), grade);
148+
149+
String resultJson = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(result);
150+
logSolve.setResult(resultJson);
151+
logSolveRepository.save(logSolve);
152+
153+
return ResponseEntity.ok(Map.of("message", "AI 풀이 완료", "logSolveId", logSolve.getLogSolveId()));
132154

133-
return ResponseEntity.ok(Map.of("message", "AI 풀이 완료", "logSolveId", logSolveId));
134155
} catch (Exception e) {
135-
return ResponseEntity.internalServerError().body(Map.of("message", "AI 처리 실패", "error", e.getMessage()));
156+
try {
157+
if (logSolve != null) {
158+
logSolveRepository.delete(logSolve);
159+
}
160+
if (image != null && image.getUrl() != null) {
161+
s3Uploader.delete(image.getUrl());
162+
imageRepository.delete(image);
163+
}
164+
} catch (Exception cleanupEx) {
165+
log.warn("정리 중 오류 발생", cleanupEx);
166+
}
167+
168+
return ResponseEntity.internalServerError().body(Map.of(
169+
"message", "AI 처리 실패",
170+
"error", e.getMessage()
171+
));
136172
}
137173
}
138174

175+
private void validateMathJson(Map<String, Object> json) {
176+
List<String> requiredKeys = List.of(
177+
"problem_title", "problem_text", "answer",
178+
"core_concept", "parent_explanation", "explanation_steps"
179+
);
139180

140-
public Long createLogAndReturnId(MultipartFile imageFile, User user, UserJr userJr) throws IOException {
141-
ImageResponseDto imageDto = imageService.uploadToS3AndSave(imageFile, ImageType.ETC, user);
142-
Image image = imageRepository.findById(imageDto.getImageId())
143-
.orElseThrow(() -> new RuntimeException("이미지 없음"));
181+
for (String key : requiredKeys) {
182+
if (!json.containsKey(key) || json.get(key) == null || json.get(key).toString().isBlank()) {
183+
throw new IllegalArgumentException("수학 문제가 아닌 이미지입니다. 누락된 필드: " + key);
184+
}
185+
}
144186

145-
return logSolveRepository.save(
146-
LogSolve.builder()
147-
.image(image)
148-
.user(user)
149-
.userJr(userJr)
150-
.build()
151-
).getLogSolveId();
187+
if (!(json.get("explanation_steps") instanceof List<?> steps) || steps.isEmpty()) {
188+
throw new IllegalArgumentException("수학 문제가 아닌 이미지입니다. explanation_steps가 비어 있음");
189+
}
152190
}
153191

154192

0 commit comments

Comments
 (0)