회기 후속 검증과 표시 경계 보강

This commit is contained in:
Yun Chan 2026-08-10 01:55:21 +09:00
parent 4cd354881f
commit aa81af2958
10 changed files with 70 additions and 21 deletions

View file

@ -54,6 +54,15 @@ export function displayPiiSafeText(text: string) {
/\[NAME\]는 건지\s+잘 \[NAME\]는데요/g,
"되는 건지 잘 모르겠는데요",
);
// 평가 문장에 이미 역할 명사가 있으면 이름 토큰을 다시 "익명 내담자"로
// 풀지 않는다. 특히 "내담자 [NAME]을 받을 여백"은 저장 마스킹 뒤
// 사람에게 "내담자 반응을 받을 여백"으로 보여야 한다.
next = next
.replace(/내담자\s+\[NAME\](?:을|를)/g, "내담자 반응을")
.replace(/내담자\s+\[NAME\](?:이|가)/g, "내담자가")
.replace(/내담자\s+\[NAME\](?:은|는)/g, "내담자는")
.replace(/내담자\s+\[NAME\]의/g, "내담자의")
.replace(/내담자\s+\[NAME\]/g, "내담자");
for (const [placeholder, label] of Object.entries(DISPLAY_PLACEHOLDERS)) {
next = replacePlaceholderWithNaturalParticle(next, placeholder, label);
}

View file

@ -67,6 +67,7 @@ import {
REVIEW_READY_POLL_INTERVAL_MS,
REVIEW_READY_POLL_LIMIT,
displayEvaluationRetryError,
displayGeneratedReviewText,
displayReviewSummary,
displayTranscriptText,
noteAuthorLabel,
@ -367,15 +368,15 @@ function SupervisorCallout({ note }: { note: ReviewNote }) {
>
<div className="sr-note__head">
<Icon name={iconName} size={13} strokeWidth={2.2} />
{note.title}
{displayGeneratedReviewText(note.title)}
<span className="sr-note__tag">{tag}</span>
</div>
<div className="sr-note__body">
<ReviewMarkdown text={note.body} />
<ReviewMarkdown text={displayGeneratedReviewText(note.body)} />
{note.quote ? (
<blockquote className="sr-note__quote">
<span> </span>
<p>{note.quote}</p>
<p>{displayGeneratedReviewText(note.quote)}</p>
</blockquote>
) : null}
</div>
@ -430,9 +431,11 @@ function JumpablePoint({
return (
<div className="sr-point">
<div>
<div className="sr-point__h">{point.title}</div>
<div className="sr-point__h">
{displayGeneratedReviewText(point.title)}
</div>
<div className="sr-point__d">
{point.body}
{displayGeneratedReviewText(point.body)}
{point.jumpTo && targetTs ? (
<button
type="button"
@ -619,7 +622,7 @@ function CaseWorksheetCard({
onClick={() => onJump(evidence.turnId)}
>
{evidence.speaker === "learner" ? "학습자" : "내담자"}{" "}
· {evidence.quote}
· {displayGeneratedReviewText(evidence.quote)}
</button>
) : null}
</div>
@ -2026,7 +2029,9 @@ export default function SessionReview() {
})}
>
<div className="sr-nextline__lab"> </div>
<div className="sr-nextline__q">{data.nextLine}</div>
<div className="sr-nextline__q">
{displayGeneratedReviewText(data.nextLine)}
</div>
</div>
) : null}
</Card>
@ -2044,7 +2049,7 @@ export default function SessionReview() {
{data.clientFeedback ? (
<>
<p className="sr-feedback__quote">
&ldquo;{data.clientFeedback}&rdquo;
&ldquo;{displayGeneratedReviewText(data.clientFeedback)}&rdquo;
</p>
<div className="sr-feedback__src">
<Icon name="info" size={13} strokeWidth={2} />

View file

@ -125,7 +125,11 @@ export function displayReviewSummary(summary: string) {
) {
return "저장된 축어록은 확인했지만 deep-loop 평가 AI 산출물을 표시하지 못했습니다. AI 평가 재시도가 필요합니다.";
}
return displayPiiSafeText(summary);
return displayGeneratedReviewText(summary);
}
export function displayGeneratedReviewText(text: string) {
return displayPiiSafeText(text);
}
export function displayEvaluationRetryError(message: string) {