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 @@ -13,6 +13,7 @@ public record AnalysisLlmResponse(
public record QuestionAnalysisItem(
Long questionId,
String sentence,
String status,
String reason,
String improvement
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.jobdri.jobdri_api.domain.analysis.dto.response;

import com.jobdri.jobdri_api.domain.analysis.entity.QuestionAnalysis;
import com.jobdri.jobdri_api.domain.analysis.entity.QuestionAnalysisStatus;

public record QuestionAnalysisResponse(
Long questionAnalysisId,
String sentence,
String status,
String reason,
String improvement,
int start,
Expand All @@ -14,10 +16,18 @@ public static QuestionAnalysisResponse from(QuestionAnalysis questionAnalysis) {
return new QuestionAnalysisResponse(
questionAnalysis.getId(),
questionAnalysis.getSentence(),
statusValue(questionAnalysis.getStatus()),
questionAnalysis.getReason(),
questionAnalysis.getImprovement(),
questionAnalysis.getStart(),
questionAnalysis.getEnd()
);
}

private static String statusValue(QuestionAnalysisStatus status) {
if (status == null) {
return QuestionAnalysisStatus.MENTIONED.name().toLowerCase();
}
return status.name().toLowerCase();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public class QuestionAnalysis {
@Column(nullable = false, columnDefinition = "TEXT")
private String improvement;

@Enumerated(EnumType.STRING)
@Column(nullable = false, columnDefinition = "varchar(255) default 'MENTIONED'")
@Builder.Default
private QuestionAnalysisStatus status = QuestionAnalysisStatus.MENTIONED;

@Column(name = "start_index", nullable = false)
private int start;

Expand All @@ -44,6 +49,7 @@ public static QuestionAnalysis create(
String sentence,
String reason,
String improvement,
QuestionAnalysisStatus status,
int start,
int end
) {
Expand All @@ -53,6 +59,7 @@ public static QuestionAnalysis create(
.sentence(sentence)
.reason(reason)
.improvement(improvement)
.status(status)
.start(start)
.end(end)
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.jobdri.jobdri_api.domain.analysis.entity;

public enum QuestionAnalysisStatus {
PROVEN,
MENTIONED,
MISSING,
FABRICATED
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ private String buildPrompt(JobPosting jobPosting, List<Question> questions) {
{
"questionId": 1,
"sentence": "자소서 답변 안에 실제 존재하는 정확한 부분 문자열",
"status": "mentioned",
"reason": "문제 이유",
"improvement": "개선 예시 문장"
}
Expand Down Expand Up @@ -131,6 +132,7 @@ private String buildPrompt(JobPosting jobPosting, List<Question> questions) {
[중요 규칙]
- JSON 외 텍스트, 마크다운, 코드블럭을 출력하지 않는다.
- questionAnalyses의 questionId는 입력된 questionId 중 하나만 사용한다.
- questionAnalyses의 status는 proven, mentioned, missing, fabricated 중 하나만 사용한다.
- sentence는 answer에 포함된 정확한 substring만 사용한다.
- start/end index는 출력하지 않는다. 서버가 Java에서 계산한다.
- 원문 매칭이 불확실하면 questionAnalyses에 포함하지 않는다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.jobdri.jobdri_api.domain.analysis.entity.Analysis;
import com.jobdri.jobdri_api.domain.analysis.entity.Question;
import com.jobdri.jobdri_api.domain.analysis.entity.QuestionAnalysis;
import com.jobdri.jobdri_api.domain.analysis.entity.QuestionAnalysisStatus;
import com.jobdri.jobdri_api.domain.analysis.repository.AnalysisRepository;
import com.jobdri.jobdri_api.domain.analysis.repository.QuestionAnalysisRepository;
import com.jobdri.jobdri_api.domain.analysis.repository.QuestionRepository;
Expand Down Expand Up @@ -137,6 +138,7 @@ private List<QuestionAnalysis> buildQuestionAnalyses(
sentence,
defaultString(item.reason()),
defaultString(item.improvement()),
normalizeStatus(item.status()),
start,
start + sentence.length()
));
Expand Down Expand Up @@ -199,4 +201,16 @@ private String normalizeFeedback(String feedback) {
private String defaultString(String value) {
return value == null ? "" : value;
}

private QuestionAnalysisStatus normalizeStatus(String status) {
if (!StringUtils.hasText(status)) {
return QuestionAnalysisStatus.MENTIONED;
}

try {
return QuestionAnalysisStatus.valueOf(status.trim().toUpperCase());
} catch (IllegalArgumentException e) {
return QuestionAnalysisStatus.MENTIONED;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ void analyzeSavesAnalysis() {
new AnalysisLlmResponse.QuestionAnalysisItem(
question.getId(),
"Spring Boot API를 개발했습니다.",
"mentioned",
"성과 지표가 없어 구체성이 약합니다.",
"Spring Boot API를 개발해 응답 시간을 20% 개선했습니다."
)
Expand All @@ -109,6 +110,7 @@ void analyzeSavesAnalysis() {
assertThat(response.completeness()).isEqualTo(80);
assertThat(response.questions()).hasSize(1);
assertThat(response.questions().get(0).analyses()).hasSize(1);
assertThat(response.questions().get(0).analyses().get(0).status()).isEqualTo("mentioned");
assertThat(response.questions().get(0).analyses().get(0).start()).isEqualTo(0);
assertThat(response.questions().get(0).analyses().get(0).end())
.isEqualTo("Spring Boot API를 개발했습니다.".length());
Expand Down Expand Up @@ -159,6 +161,7 @@ void analyzeSkipsSentenceNotInAnswer() {
new AnalysisLlmResponse.QuestionAnalysisItem(
question.getId(),
"답변에 없는 문장입니다.",
"fabricated",
"원문에 없습니다.",
"원문 기반 문장으로 개선해야 합니다."
)
Expand Down Expand Up @@ -188,6 +191,7 @@ void analyzeReplacesExistingAnalysis() {
List.of(new AnalysisLlmResponse.QuestionAnalysisItem(
question.getId(),
"가입 완료율을 개선했습니다.",
"mentioned",
"수치가 부족합니다.",
"가입 완료율을 12% 개선했습니다."
))
Expand All @@ -201,6 +205,7 @@ void analyzeReplacesExistingAnalysis() {
List.of(new AnalysisLlmResponse.QuestionAnalysisItem(
question.getId(),
"API 응답 속도를 개선했습니다.",
"proven",
"성과 기준이 더 필요합니다.",
"API 응답 속도를 300ms 단축했습니다."
))
Expand All @@ -212,6 +217,7 @@ void analyzeReplacesExistingAnalysis() {
assertThat(second.analysisId()).isNotEqualTo(first.analysisId());
assertThat(second.score()).isEqualTo(88);
assertThat(second.feedback()).isEqualTo("두 번째 분석");
assertThat(second.questions().get(0).analyses().get(0).status()).isEqualTo("proven");
assertThat(analysisRepository.findByMockApplyId(mockApply.getId()).orElseThrow().getScore()).isEqualTo(88);
assertThat(questionAnalysisRepository.findAllByAnalysisId(second.analysisId())).hasSize(1);
assertThat(questionAnalysisRepository.findAllByAnalysisId(first.analysisId())).isEmpty();
Expand All @@ -232,6 +238,7 @@ void getAnalysis() {
List.of(new AnalysisLlmResponse.QuestionAnalysisItem(
question.getId(),
"서비스 개선 경험이 있습니다.",
"mentioned",
"구체성이 조금 부족합니다.",
"서비스 개선 경험으로 전환율을 10% 높였습니다."
))
Expand Down
Loading