레포에 이슈를 올렸고, 이런 분석 결과가 나왔습니다 (GLM53-flash):
찾았습니다. 코드에 받아쓰기 경로가 있는데 데이터 제한, 시간 제한, 클라이언트 측 무음 게이트가 전혀 없고, 재연결될 때마다 전체를 다시 재생합니다. 분석 내용은 다음과 같습니다.
메커니즘
사용자가 작성기에서 마이크를 누르면, 클라이언트는 계속해서 녹음하고 PCM을 ~1초 단위의 base64 청크로 OpenChamber 서버에 스트리밍합니다:
-
packages/ui/src/lib/dictation/use-dictation-audio-source.ts:205-227 — 4096 샘플 블록마다 16kHz로 리샘플링되어 대기열에 추가됩니다. RMS 레벨은 파형에 대해서만 계산되며, 무음 구간도 음성과 똑같이 스트리밍됩니다.
-
packages/ui/src/hooks/useDictation.ts — 녹음은 확인, 취소, 또는 마운트 해제 시에만 종료됩니다. 최대 지속 시간, 유휴 시간 제한, 데이터 용량 제한이 어디에도 없습니다. 지속 시간 카운터는 그냥 계속 올라갑니다.
-
packages/ui/src/lib/dictation/dictation-stream-sender.ts:40,91-108 — 받아쓰기가 완료될 때까지 렌더러의 제한 없는 string[]에 세그먼트가 쌓입니다.
전송 속도는 16kHz × 2바이트 × 4/3 base64 ≈ 43KB/s로, 시간당 약 155MB입니다. 초저녁부터 아침까지 녹음을 켜두면 12~14시간이 되어 거의 정확히 2GB에 도달합니다.
두 가지 증폭 요인
첫째, 재연결 시마다 전체 재생. useDictation.ts:154-166은 녹음 중에 WS 연결이 다시 연결될 때마다 restartStream()을 호출하고, resetStreamForReplay()는 sendSeq = 0으로 설정하므로(dictation-stream-sender.ts:82-89), flush()가 버퍼링된 모든 세그먼트를 처음부터 다시 보냅니다. 밤사이 연결이 끊겼다 붙었다 하면(프록시 끊김, 절전/깨어남, 터널 재연결) 그때마다 전체 세션을 다시 업로드합니다. 3시간짜리 녹음을 5번 재전송하면 그것만으로도 ~2.3GB가 됩니다. flush 루프는 이벤트 루프 턴당 128개 청크를 처리하므로, 몇 시간 분량의 오디오 재생이 몇 초 만에 완료됩니다.
둘째, 재시도. 실패한 받아쓰기는 모든 세그먼트를 유지하며(useDictation.ts:196-206) retryFailedDictation이 모든 것을 다시 재생합니다. 실패한 오버레이를 밤새 띄워둔 렌더러는 메모리에 수백 MB의 문자열을 들고 있는 셈입니다.
서버 측 세부 사항: packages/web/server/lib/dictation/stream-manager.js는 무음 전용 세그먼트를 커밋하지 않고 지우므로, 조용한 방에서는 STT 제공업체로 거의 전송되지 않습니다. 하지만 클라이언트→서버 스트림 자체에는 무음 게이트가 없습니다.
2GB가 실제로 나가는 경로
이 부분이 받아쓰기만으로 설명이 가능한지 결정합니다:
-
서버 원격(릴레이, SSH 터널, 호스팅된 웹): 클라이언트→서버 WS 업로드는 WAN 트래픽입니다. 시간당 ~155MB, 13시간 밤새 2GB. 정확히 일치합니다.
-
원격 STT 기본 URL(사용자 지정 OpenAI 호환 엔드포인트)을 사용하는 서버 로컬 데스크톱: 마이크 근처에 실제 오디오가 있었다면 거의 같은 용량의 커밋된 음성 세그먼트가 제공업체로 나갑니다.
-
로컬 Whisper 모델과 로컬 UI만 사용하는 서버 로컬 데스크톱: 받아쓰기는 루프백이므로 2GB가 될 수 없습니다. 이 경우 다음 후보는 밤사이 LFS 객체를 git push 하는 것이거나(packages/web/server/lib/git/network-operations.ts:1360-1443, 실제 LFS 콘텐츠 크기만큼 실시간 스트리밍), 메시지 큐를 통해 재업로드되는 첨부 파일 데이터 URL입니다.
수정 제안
받아쓰기당 총 버퍼링 오디오 용량을 제한하고 그 이상은 자동 종료하세요; 이게 빠진 불변량입니다. 서버에는 세그먼트별 제한이 있지만 클라이언트 세션에는 없습니다. seq 0부터 재생하지 마세요: 서버는 수신한 가장 높은 연속 seq를 확인하고 거기서부터 재개할 수 있습니다. 청크는 이미 seq로 주소 지정되어 있으니까요. 그리고 클라이언트 측에서 무음 구간을 삭제하거나 압축하세요. 그러면 전송 비용이 실제로 누군가 말할 때와 비례하게 됩니다.
영향을 받는 기기에서 확인하려면, OpenChamber 서버 로그에서 밤사이 타임스탬프가 찍힌 받아쓰기 스트림 시작 및 STT 커밋을 확인하고, 누군가 발견했을 때 녹음 상태가 여전히 녹음 중이었는지 확인하세요.
하지만 실제 OC를 실행 중인 머신으로 조사를 옮겼는데, 음성 전사 관련 로그가 전혀 없어서 확인할 수 없었습니다.
또한, 리눅스 머신은 VM입니다.