세션 로그 시스템 (stt_dedup·MFCC·캡션) — 코드레벨 동작 흐름 P1코드레벨

마지막 업데이트 2026-07-29

세션 로그 시스템 (stt_dedup·MFCC·캡션) — 코드레벨 동작 흐…: 입력: 개요 · 범위, 주요 처리 단계: 로그 페이지 · 재생, 결과: MFCC 검증 데이터 api/session-logs/[id]/{mfcc,m… 흐름
동작 흐름 요약
  1. 입력: 개요 · 범위
  2. 주요 처리 단계: 로그 페이지 · 재생
  3. 결과: MFCC 검증 데이터 api/session-logs/[id]/{mfcc,m…
작성일: 2026-06-14 대상: 개발자 — 핑퐁이 세션 로그 저장/조회 파악 핵심 파일: types/db/session-log.types.ts, hooks/use-session-logs.ts, api/session-logs/
💬 대화로 먼저 이해하기 — "진료 차트 비유" (비개발자·처음 읽는 사람용)
Q수업 중에 일어난 일들은 다 어디에 기록되나요?
A병원 진료 차트와 같아요. 한 수업(환자)의 모든 일 — 아동 발화, 핑퐁이 응답, 선생님 개입, 녹음·분석 결과, 이슈 — 이 하나의 기록 스트림(SessionLog)으로 DynamoDB에 시간순으로 쌓여요.
Q기록 종류가 그렇게 다양한데 한 차트에 섞이면 헷갈리지 않나요?
A모든 기록이 같은 서식을 쓰되, "누가 남겼나(role)"와 "무슨 종류인가(type)" 태그로 구분해요. 아동(user)·핑퐁이(assistant)·선생님(operator)·시스템(system)·이슈(issue) — 태그 조합만 보면 어떤 기록인지 알 수 있죠.
Q녹음 파일이나 MFCC 분석 데이터처럼 큰 자료도 차트에 붙이나요?
AX-ray 필름을 차트에 직접 붙이지 않듯이, 대용량 원시 데이터는 자료실(S3)에 보관하고 차트에는 보관 번호(S3 key)만 적어요. 요약(mfccRange)만 본문에 인라인으로 남기죠.
Q기록 번호는 아무렇게나 매겨도 되나요?
A안 돼요. id는 OpenAI item_id·STT request id 같은 소스 식별자를 그대로 써야 오디오↔전사 매칭(캡션)이 이어져요. 이런 규칙 위반 사례는 아래 "함정 · 주의" 섹션에 정리되어 있어요.

개요 · 범위

한 수업의 모든 상호작용(아동 발화·핑퐁이 응답·텍스트 입력·호스트 개입·STT 메타·녹음·오디오 분석·이슈)을 단일 SessionLog 레코드 스트림으로 DynamoDB에 저장하고, 로그 페이지(/main/log)에서 조회·재생한다.

한 테이블, role×type로 구분: 모든 로그가 같은 구조(SessionLogUpdate)를 공유하고 role+type 조합과 선택 필드로 의미가 갈린다. id는 OpenAI item_id 또는 STT request id 등 소스 식별자와 동일 → 전사-오디오 매칭(캡션)에 사용.

데이터 모델 session-log.types.ts

role · type

role대표 type의미
useraudio / text / auto / fallback / stt_dedup아동 발화·입력
assistantaudio / stt_verified핑퐁이 응답(+MFCC 검증)
operatorhost_text / host_mute / host_next_step / host_cancel_ai …호스트 개입
systemaudio(녹음) / audio_analysis녹음·분석 산출물
issue이슈 기록

type별 의미 (헷갈리는 것)

type의미
audio전사된 발화 턴(user/assistant)
auto자동 시작 멘트(AUTO_START_MESSAGE)
fallbackWeb Speech 폴백 전사(#18)
stt_dedupExternal STT dedup 발생 시 원본 텍스트 보존(#4/#9, was_deduped)
stt_verifiedMFCC 검증 통과 턴
audio_analysis오디오 분석 에이전트 결과(별도 문서)

선택 필드 (소스별)

  • 호스트 개입: hostId, interventionType, relatedToLogId(어떤 로그에 대한 개입인지).
  • STT 메타: sttLatencyMs, sttSessionId, sttRequestId, diarization(화자분리 정보).
  • MFCC: mfccRange(MfccRangeSummary: startMs/endMs/detectedEnglish/matchedPatternSequence…), mfccS3Key — assistant+audio 턴에서만.
  • 캡션: captionS3Key — 녹음 로그(role=system, type=audio)에서만(#3).
  • 오디오 분석: audioAnalysisS3Key — role=system, type=audio_analysis에서만.

저장·조회 use-session-logs.ts / api/session-logs/route.ts

  • createLog(logUpdate)POST /api/session-logssetSessionLog(DynamoDB). 세션 매니저(#1)의 데이터채널 이벤트 핸들러가 user/assistant 전사 시 호출.
  • fetchLogs(userId, lessonIndex, activityId, options)GET /api/session-logs?.... 옵션: sortOrder(asc/desc), filterRange(5days/all), includeIssues, issueTextOnly. activityId=null은 문자열 "null"로 전달.
  • updateLogWithIssueTextPOST /api/issue-texts(로그에 이슈 텍스트/카테고리 부착).
  • 녹음 로그: 서버(#3)가 saveRecordingLog로 role=system·type=audio·captionS3Key 레코드 생성. deleteRecordingLog로 S3 동반 삭제.
인증: withAuthMember(치료사 인증) 미들웨어. 조회는 userId+lessonIndex(+activityId) 키 기준.

MFCC 검증 데이터 api/session-logs/[id]/{mfcc,mfcc-upload-url,mfcc-download-url}

핑퐁이 턴의 MFCC(영어 발화 감지 등) 원시 데이터는 로그 본문이 아니라 S3에 저장한다. mfcc-upload-url(presigned 업로드) → mfccS3Key를 로그에 기록 → 조회 시 mfcc-download-url/mfcc로 가져온다. 요약(mfccRange)만 로그 본문에 인라인. MFCC 로직 자체는 MFCC 튜닝·기계음 영어 발화 감지.

로그 페이지 · 재생

  • /main/log(components/pages/session-log.tsx) — 로그 목록·필터·테이블. session-log-table, session-log-floating-player(오디오 재생).
  • 캡션 동기화: 녹음 mp3 재생 시 captionS3Key의 caption.json으로 전사를 위치에 매핑(logId = SessionLog.id 매칭, #3). 오디오↔전사 하이라이트.
  • 필터/개입 로직: entities/session-log/model/{use-session-log-filter,use-session-log-intervention}, 내보내기 features/session-log-export.

함정 · 주의

  • id는 소스 식별자: OpenAI item_id / STT request id 등을 그대로 쓴다(캡션·중복 방지). 임의 생성하면 매칭이 깨진다.
  • type별 선택 필드 제약: mfcc*는 assistant+audio, captionS3Key는 system+audio, audioAnalysisS3Key는 system+audio_analysis에서만. 잘못된 조합으로 저장하면 조회/재생 로직이 못 찾음.
  • stt_dedup는 원본 보존용: 정식 전사(text/audio)와 별도로 dedup 전 원본을 남긴다 → 카운트/표시 시 중복 집계 주의.
  • activityId=null 직렬화: 쿼리에서 문자열 "null"로 전달. 실제 null과 구분되는 약속.
  • 대용량은 S3: MFCC·캡션·분석 원시 데이터는 로그 본문이 아닌 S3. 로그엔 키만. S3 삭제와 로그 삭제 동기화(saveRecordingLog/deleteRecordingLog) 필요.

파일 · 라인 레퍼런스

파일역할
types/db/session-log.types.tsSessionLog/role/type/MfccRangeSummary 모델
hooks/use-session-logs.tscreateLog/fetchLogs/updateLogWithIssueText
api/session-logs/route.tsGET/POST(setSessionLog·saveRecordingLog)
api/session-logs/[id]/mfcc*MFCC S3 업·다운로드
components/pages/session-log.tsx로그 페이지·재생
entities/session-log/model/*, features/session-log-export/필터·개입·내보내기