mirror of
https://github.com/nad4-su/meeting-minutes.git
synced 2026-10-11 15:50:13 +09:00
P0에 남아 있던 세 가지. 실측 46분 회의 transcript에서 확인된 문제를 하나씩 코드로 막는다. ## 1. Chrome이 흘리는 것을 붙잡는다 **미확정 발화 보존** — Chrome은 `continuous`여도 침묵마다 세션을 닫는데, 그때 확정 전이던 문장을 그냥 버린다. 1시간 회의면 이 사이클이 수십 번 돌고 매번 마지막 한 문장씩 사라졌다. 세션이 끝날 때마다 직접 확정시킨다. **마지막 발화 보존** — `handleStop`이 렌더 시점의 `chunks`를 그대로 넘기는 바람에 회의 끝머리가 항상 빠졌다. `stopListening()`이 미확정분까지 굳힌 최종 청크를 돌려주도록 바꿨다. **인식 실패 가시화** — `isFinal: true`에 `transcript: ""`인 결과가 실측에서 19번 나왔다. "소리는 들었는데 못 알아듣겠다"는 신호다. 청크로 넣으면 요약 프롬프트가 오염되고, 조용히 버리면 유실이 보이지 않는다. 빼되 세어서 `⚠️ 인식 실패 N건` 배지로 노출한다. **미리보기로 강등** — 실시간 텍스트 패널에 (미리보기)를 붙였다. 확정본은 서버 STT 재전사가 만든다. ## 2. 타임스탬프 실측화 `startTime: Math.max(0, now - 2)` 하드코딩을 걷어냈다. interim이 처음 뜬 시각이 곧 발화 시작이므로 그것을 쓴다. 또 `startRecording()`이 캡처 시작 시각을 돌려주고 `startListening(timeOrigin)`이 그것을 받아, 전사 타임스탬프가 오디오 파일의 재생 위치와 같은 시간축을 쓴다. ## 3. 긴 회의가 마지막에 통째로 실패하지 않는다 `/api/summarize`가 10만 자를 넘으면 413으로 거부했다. 3시간 회의를 마치고 회의록을 만들려는 순간 아무것도 못 받는다는 뜻이다. 유실을 막자고 만든 파이프라인 끝에서 결과를 버리는 셈이었다. 구간별로 압축한 뒤(map) 압축본을 모아 평소와 똑같은 템플릿 경로로 회의록을 만든다(reduce). 최종 출력이 짧은 회의와 같은 프롬프트를 타므로 서식이 흔들리지 않는다. 상한은 50만 자(약 14시간)로 올렸다. 한 구간이라도 실패하면 전체를 실패로 돌린다. 일부만 빠진 압축본으로 회의록을 만들면 사용자는 무엇이 빠졌는지 모른 채 멀쩡해 보이는 문서를 받게 된다. ## 검증 브라우저에서 가짜 SpeechRecognition을 주입해 확인: - 빈 확정 2건 → 청크 0개 + "인식 실패 2건" 배지 - 미확정 마지막 발화가 중지 후 전사문에 남음 - 빈 `[MM:SS]` 줄이 하나도 없음 테스트 229 → 257 통과, 신규 타입 에러 0, 린트 baseline과 동일, 빌드 성공. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WzAH7GPWSYTe2AoBV6CZDP