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 @@ -7,8 +7,8 @@ public class DcaBriefEvaluationPrompt {
public static OpenAiPrompt buildDcaBriefEvaluationPrompt(DcaOpenAiRequest.BrandBriefPayload brief) {
String system = """
You are a professional assistant that analyzes a competition entry into three fields:
interpretation, consistency, weakness. Respond ONLY in Korean and return JSON with
keys: interpretation, consistency, weakness.
interpretation, consistency. Respond ONLY in Korean and return JSON with
keys: interpretation, consistency.

Global rules
- Always output all three fields.
Expand All @@ -34,24 +34,6 @@ public static OpenAiPrompt buildDcaBriefEvaluationPrompt(DcaOpenAiRequest.BrandB
- Evaluate alignment between the interpreted brief and execution (planning intent ↔ media/message/engagement design).
- Include at least one concrete example referencing story flow, media characteristics, or participation design.
- Focus on how consistently the brief’s core direction is carried through—not on micro design polish.

3) weakness
- Exactly 1–2 sentences.\s
- Write in a short, critical, and declarative style (e.g., "~이 부족하다", "~이 약하다", "~이 드러나지 않는다").
- Always ground the weakness in a specific element of the submission (e.g., medium used, participation path, message framing).
- Focus only on major misalignments with the brief’s core requirements or weak linkage to the brand’s essential value.
- Do NOT include trivial design issues, technical usability, or time/place limitations.
- Avoid phrasing like "~할 수 있다", "~기 때문이다"; always state issues directly and decisively.
- If the work is overall strong, still provide one subtle risk framed in the same short, critical style.

# Good Weakness (use this style)
- "캐릭터 아이프렌즈로 귀여움과 친근함은 살렸으나, 브랜드와 직접적 연계가 약해 장기적 팬덤 구축까지는 한계가 있음."
- "버스 창문이 닫힐 때 전달되는 ‘채워짐’의 순간은 시각적으로 임팩트 있지만, 창문이 열리면 메시지가 단절되어 브랜드 기억 지속성이 약할 수 있다."

# Bad Weakness (do NOT write like this)
- "더 창의적이어야 한다." # ambiguous
- "앱 사용성이 떨어질 수 있다." # minor/Design Points
- "문제가 없다고 본다." # uncritical
""";

String briefBlock = (brief == null) ? "" : """
Expand All @@ -71,7 +53,6 @@ public static OpenAiPrompt buildDcaBriefEvaluationPrompt(DcaOpenAiRequest.BrandB
Analyze the following submission and output a JSON object with:
- "interpretation": exactly 2 sentences ([brief core] → [how reflected in campaign]).
- "consistency": 3–4 sentences with concrete examples of alignment.
- "weakness": **at least 1 sentence** (prefer 2), each naming a concrete element and its impact on brief/brand alignment; avoid design-only or time/place-specific remarks.
""".formatted(briefBlock);

return new OpenAiPrompt(system, user);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ public static OpenAiPrompt buildDcaDetailEvaluationPrompt(
If you assign ≤5, you must justify with one clear weakness/risk factor (do not list more than one).
- Below 5: Not allowed.

Rationale rule:
- If score == 6 → add exactly one short weakness.
- If score ≥ 7 → no weaknesses, no “그러나/하지만/다만” style contrast.

Conservativeness:
- Do NOT inflate scores without clear evidence.
- Be conservative: most scores should be 8 or below.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ public List<DetailEvaluationResponse.DetailEvaluation> getStrengths(Long workId)
personalWorkValidator.validatePersonalWorkAccessible(workId, currentUserProvider.getCurrentUser());
personalWorkValidator.validateEvaluationExists(workId);

List<DetailEval> strengths = detailEvalRepository.findTopStrengths(workId, PageRequest.of(0, 3));
List<DetailEval> strengths = detailEvalRepository.findTopStrengths(workId, PageRequest.of(0, 6));
List<DetailEval> selected = adjustIfSameEvalTop3(strengths);

return strengths.stream().map(StrengthWeaknessMapper::toResponse).toList();
return selected.stream().map(StrengthWeaknessMapper::toResponse).toList();

}

Expand All @@ -38,23 +39,70 @@ public List<DetailEvaluationResponse.DetailEvaluation> getWeaknesses(Long workId
personalWorkValidator.validatePersonalWorkAccessible(workId, currentUserProvider.getCurrentUser());
personalWorkValidator.validateEvaluationExists(workId);

List<DetailEval> weaknesses = detailEvalRepository.findBottomWeaknesses(workId, PageRequest.of(0, 3));
List<DetailEval> bounded = applyBoundaryRule(weaknesses);
List<DetailEval> weaknesses = detailEvalRepository.findBottomWeaknesses(workId, PageRequest.of(0, 6));
List<DetailEval> selected = applyBoundaryThenReplaceIfSameEval(weaknesses);

return selected.stream().map(StrengthWeaknessMapper::toResponse).toList();
}

return bounded.stream().map(StrengthWeaknessMapper::toResponse).toList();
}

private List<DetailEval> applyBoundaryRule(List<DetailEval> sortedAscTop3) {
int n = sortedAscTop3.size();
if (n <= 2) return sortedAscTop3;
private List<DetailEval> adjustIfSameEvalTop3(List<DetailEval> top6) {

int s2 = sortedAscTop3.get(1).getScore();
int s3 = sortedAscTop3.get(2).getScore();
List<DetailEval> first3 = top6.subList(0, 3);
Long e1 = first3.get(0).getEvaluation().getId();
Long e2 = first3.get(1).getEvaluation().getId();
Long e3 = first3.get(2).getEvaluation().getId();

if (s2 != s3) {
return sortedAscTop3.subList(0, 2);
// 셋 다 같은 evaluation이면 교체
if (e1.equals(e2) && e2.equals(e3)) {
for (int i = 3; i < Math.min(6, top6.size()); i++) {
DetailEval cand = top6.get(i);
if (!cand.getEvaluation().getId().equals(e1)) {
List<DetailEval> adjusted = new java.util.ArrayList<>(first3);
adjusted.set(2, cand);
return adjusted;
}
}
return first3;
}
return first3;
}

private List<DetailEval> applyBoundaryThenReplaceIfSameEval(List<DetailEval> bottom6) {

// 경계 규칙 적용
List<DetailEval> top3Slice = bottom6.subList(0, 3);
List<DetailEval> base = applyBoundaryRule(top3Slice);

if (base.size() < 3) return base;

Long e1 = base.get(0).getEvaluation().getId();
Long e2 = base.get(1).getEvaluation().getId();
Long e3 = base.get(2).getEvaluation().getId();

boolean allSameEval = e1.equals(e2) && e2.equals(e3);
if (!allSameEval) return base;

int s3 = base.get(2).getScore();

for (int i = 3; i < Math.min(6, bottom6.size()); i++) {
DetailEval cand = bottom6.get(i);
if (cand.getScore() == s3 && !cand.getEvaluation().getId().equals(e1)) {
List<DetailEval> adjusted = new java.util.ArrayList<>(base);
adjusted.set(2, cand);
return adjusted;
}
}

return base.subList(0, 2);
}

private List<DetailEval> applyBoundaryRule(List<DetailEval> top3) {
int s2 = top3.get(1).getScore();
int s3 = top3.get(2).getScore();

if (s2 != s3) return top3.subList(0, 2);

return sortedAscTop3;
return top3;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ public class BriefAnalysis extends BaseEntity {
@Column(name = "consistency", nullable = false, length = 300)
private String consistency;

@Column(name = "weakness", nullable = false, length = 300)
private String weakness;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "work_id", nullable = false, unique = true)
private Work work;
Expand All @@ -35,12 +32,10 @@ public class BriefAnalysis extends BaseEntity {
public BriefAnalysis(
String interpretation,
String consistency,
String weakness,
Work work
) {
this.interpretation = interpretation;
this.consistency = consistency;
this.weakness = weakness;
this.work = work;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ public record DcaBriefEvaluationResponse(
description = "반영 일관성",
example = "캠페인은 타이머와 빼빼로를 결합하여 '잠시 톡! 끊어가도 괜찮아'라는 메시지를 통해 영타겟에게 휴식의 중요성을 전달하고 있다. 이는 브랜드의 본질적 가치인 '나눔/연결의 가치'를 유지하면서도 새로운 경험을 제공하려는 시도이다. 또한, 패키지 디자인과 메시지 전달 방식이 젊은 층의 일상과 잘 맞아떨어져 자발적 참여를 유도하고 있다. 이러한 요소들은 브랜드의 감성적 연결을 강화하는 데 일조하고 있다."
)
String consistency,

@Schema(
description = "보완점",
example = "타이머와의 결합이 신선하지만, 빼빼로 자체의 매력보다는 부가적인 요소에 의존하는 경향이 있어 브랜드의 본질적 가치와의 직접적 연계가 약할 수 있다."
)
String weakness
String consistency
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public static BriefAnalysis toEntity(Work work, DcaBriefEvaluationResponse resp)
return BriefAnalysis.builder()
.interpretation(resp.interpretation())
.consistency(safeTrim(resp.consistency(), MAX_LEN))
.weakness(safeTrim(resp.weakness(), MAX_LEN))
.work(work)
.build();
}
Expand All @@ -21,7 +20,6 @@ public static DcaBriefEvaluationResponse toResponse(BriefAnalysis e) {
return DcaBriefEvaluationResponse.builder()
.interpretation(e.getInterpretation())
.consistency(safeTrim(e.getConsistency(), MAX_LEN))
.weakness(safeTrim(e.getWeakness(), MAX_LEN))
.build();
}

Expand Down
Loading