현재 작업 전체 반영
This commit is contained in:
parent
5560638e54
commit
c0dddab594
85 changed files with 11322 additions and 539 deletions
|
|
@ -30,6 +30,7 @@ import {
|
|||
apiWsUrl,
|
||||
personaApi,
|
||||
sessionApi,
|
||||
type CrisisResource,
|
||||
type PersonaSummary,
|
||||
type SessionDetailResponse,
|
||||
type SessionStage,
|
||||
|
|
@ -65,6 +66,8 @@ interface VoiceEvent {
|
|||
stage?: SessionStage;
|
||||
effective_openness?: number;
|
||||
safety_flagged?: boolean;
|
||||
crisis_resource?: CrisisResource | null;
|
||||
conversation_stopped?: boolean;
|
||||
}
|
||||
|
||||
interface Utterance {
|
||||
|
|
@ -403,6 +406,7 @@ export default function Session() {
|
|||
const [utterances, setUtterances] = useState<Utterance[]>([]);
|
||||
const [openness, setOpenness] = useState(0);
|
||||
const [safety, setSafety] = useState<string | null>(null);
|
||||
const [crisisResource, setCrisisResource] = useState<CrisisResource | null>(null);
|
||||
const [turnError, setTurnError] = useState<string | null>(null);
|
||||
|
||||
// ── 음성/턴 UI 상태 ──
|
||||
|
|
@ -452,6 +456,8 @@ export default function Session() {
|
|||
setStarted(false);
|
||||
setUtterances([]);
|
||||
setElapsed(0);
|
||||
setSafety(null);
|
||||
setCrisisResource(null);
|
||||
setResumedSessionLoaded(false);
|
||||
setStartError(null);
|
||||
}, [navigate, routeIsSessionId, routeParam]);
|
||||
|
|
@ -537,6 +543,22 @@ export default function Session() {
|
|||
setSignalSeq((seq) => [...seq.slice(-4), tone]);
|
||||
}, []);
|
||||
|
||||
const applyCrisisGate = useCallback((resource?: CrisisResource | null) => {
|
||||
const fallback: CrisisResource = {
|
||||
title: "자살예방상담전화 109",
|
||||
number: "109",
|
||||
message: "지금은 연습을 멈추고 실제 안전 확인이 먼저입니다.",
|
||||
};
|
||||
const next = resource ?? fallback;
|
||||
setCrisisResource(next);
|
||||
setSafety(next.message);
|
||||
setPaused(true);
|
||||
setMicOn(false);
|
||||
setVoiceStatus("idle");
|
||||
setVoiceDetail("위기 신호가 감지되어 연습을 중단했습니다.");
|
||||
pushSignal("warn", "위기 안전게이트 작동");
|
||||
}, [pushSignal]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!routeIsSessionId) return;
|
||||
let alive = true;
|
||||
|
|
@ -567,6 +589,8 @@ export default function Session() {
|
|||
setElapsed(elapsedFromSession(detail));
|
||||
setStarted(true);
|
||||
setPaused(false);
|
||||
setSafety(null);
|
||||
setCrisisResource(null);
|
||||
setAvatarState("idle");
|
||||
setMicOn(false);
|
||||
setVoiceStatus("idle");
|
||||
|
|
@ -610,6 +634,8 @@ export default function Session() {
|
|||
setStage(res.stage);
|
||||
setOpenness(res.effective_openness);
|
||||
setUtterances([]);
|
||||
setSafety(null);
|
||||
setCrisisResource(null);
|
||||
setElapsed(0);
|
||||
if (res.degraded) {
|
||||
pushSignal("neutral", "서버 기록 제한");
|
||||
|
|
@ -700,9 +726,17 @@ export default function Session() {
|
|||
if (data.safety_flagged) {
|
||||
setSafety("방금 발화에서 위기 신호가 감지됐어요. 안전을 우선해 머물러 주세요.");
|
||||
}
|
||||
if (data.conversation_stopped || data.crisis_resource) {
|
||||
applyCrisisGate(data.crisis_resource);
|
||||
}
|
||||
},
|
||||
onSafety: () => {
|
||||
onSafety: (payload) => {
|
||||
setSafety("방금 발화에서 위기 신호가 감지됐어요. 안전을 우선해 머물러 주세요.");
|
||||
if (payload && typeof payload === "object") {
|
||||
const resource = (payload as { crisis_resource?: CrisisResource }).crisis_resource;
|
||||
const stopped = (payload as { conversation_stopped?: boolean }).conversation_stopped;
|
||||
if (resource || stopped) applyCrisisGate(resource);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -994,6 +1028,9 @@ export default function Session() {
|
|||
if (payload.safety_flagged) {
|
||||
setSafety("방금 발화에서 위기 신호가 감지됐어요. 안전을 우선해 머물러 주세요.");
|
||||
}
|
||||
if (payload.conversation_stopped || payload.crisis_resource) {
|
||||
applyCrisisGate(payload.crisis_resource);
|
||||
}
|
||||
const pendingId = pendingVoiceLearnerIdRef.current;
|
||||
if (pendingId != null) {
|
||||
setUtterances((prev) =>
|
||||
|
|
@ -1748,6 +1785,12 @@ export default function Session() {
|
|||
</span>
|
||||
<span className="sx-safety__text">
|
||||
<b>안전 점검</b> · {safety}
|
||||
{crisisResource ? (
|
||||
<span className="sx-crisis-resource">
|
||||
<strong>{crisisResource.title}</strong>
|
||||
<a href={`tel:${crisisResource.number}`}>{crisisResource.number}</a>
|
||||
</span>
|
||||
) : null}
|
||||
</span>
|
||||
</section>
|
||||
) : null}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue