mirror of
https://github.com/nad4-su/meeting-minutes.git
synced 2026-10-11 15:50:13 +09:00
feat: 대면 회의 화자 분리 (로컬 diarization)
마이크 한 트랙에 여러 사람이 섞여 들어오는 대면 회의에서 화자를 나눈다. pyannote-segmentation-3.0 + 3D-Speaker CAM++ 를 ONNX Runtime으로 로컬 Next.js 프로세스에서 실행한다. GPU도 파이썬도 필요 없고 오디오가 외부로 나가지 않는다. 실측 (Apple Silicon, 2스레드, 4인 한국어 아닌 샘플 57초): - 처리 1.5초 → RTF 0.03, 실시간의 33배 - 자동 추정은 화자 5명(과다 계수), 참석자 수를 주면 4명(정확) → 참석자 수 입력을 1급 기능으로 노출 구성: - lib/diarization.ts — sherpa-onnx-node 래퍼, 모델 캐시, 참석자 수 힌트 - lib/audio-session.ts — 녹음 중 PCM 조각을 세션별로 누적 (메모리) - api/diarize/chunk — 4초짜리 Int16 PCM 조각 업로드 - api/diarize — 누적 오디오 전체 분석, GET은 모델 설치 여부 확인 - public/pcm-worklet.js — 16kHz Int16 PCM 추출 AudioWorklet - hooks/useDiarization.ts — 수집·분석 상태 관리 - transcript-formatter: assignSpeakers() — 시간 겹침으로 화자 배정. 겹치는 구간이 없으면 라벨을 비운다 (틀린 라벨보다 없는 편이 낫다) - LiveRecorder: 사용 안 함 / 원격 회의 / 대면 회의 3모드 + 참석자 수 - scripts/setup-diarization.mjs — 모델 34MB 내려받기 (npm run setup:diarization) 설계 변경: 롤링 재-diarization 대신 녹음 종료 시 1회 전체 분석. 구간을 잘라 반복하면 실행마다 화자 번호가 달라져 이어 붙일 수 없고, 누적분 재분석은 비용이 회의 길이에 비례해 커진다. 대신 실시간 화자 표시는 없다. 모델은 라이선스와 용량 때문에 저장소에 넣지 않고 gitignore 한다. 테스트 176 → 184. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a8cfab8a4a
commit
4af0a03de5
19 files changed
+1110
-75
No files matched your search
+16
@@ -52,6 +52,7 @@
|
||||
| 액션 아이템 | PostgreSQL (`action_items`) | 외부 송출 없음 |
|
||||
| API 키 | 브라우저 LocalStorage 또는 `.env` | 요청 시 선택한 프로바이더에만 전송 |
|
||||
| 음성 데이터 | 메모리 (실시간), `/app/uploads` (파일 업로드) | **Chrome Web Speech API → Google 서버** ⚠️ |
|
||||
| 화자 분리용 PCM | 서버 프로세스 메모리 (녹음 중에만) | **외부 송출 없음** — 로컬에서 분석하고 분석 후 즉시 폐기 |
|
||||
|
||||
### ⚠️ 주의: Web Speech API의 음성 외부 전송
|
||||
|
||||
@@ -77,6 +78,21 @@ Chrome의 `SpeechRecognition` API는 **음성 데이터를 Google 서버로 전
|
||||
- 중계 라우터는 요청을 대신 전달하는 구조상 **평문 프롬프트를 볼 수 있는 주체가 한 곳 늘어납니다.** 로깅·보관 정책은 각 서비스 약관을 직접 확인하세요.
|
||||
- 사내 컴플라이언스가 외부 전송을 제한한다면 **로컬 모델** 프리셋을 사용하세요.
|
||||
|
||||
### 화자 분리 오디오는 로컬에만 머뭅니다
|
||||
|
||||
대면 회의 화자 분리는 `pyannote-segmentation-3.0` + `CAM++` ONNX 모델을 로컬
|
||||
Next.js 프로세스에서 실행합니다. 외부 API를 호출하지 않으므로 **오디오가 네트워크로
|
||||
나가지 않습니다.**
|
||||
|
||||
- 녹음 중 PCM 조각이 서버 프로세스 **메모리**에 쌓입니다 (디스크에 쓰지 않음)
|
||||
- 분석이 끝나면 즉시 폐기하며, 6시간 지난 세션은 자동 정리됩니다
|
||||
- 세션 최대 길이는 3시간으로 제한됩니다
|
||||
- 단일 사용자 로컬 실행 전제입니다. 여러 사용자가 붙는 환경이라면 세션 ID를
|
||||
추측해 다른 사람의 오디오에 접근할 수 있으므로, 노출 배포 시 인증이 선행되어야 합니다
|
||||
|
||||
전사 텍스트는 여전히 Web Speech API를 거치므로 Google로 갑니다. 화자 분리만
|
||||
로컬이라는 점에 유의하세요.
|
||||
|
||||
### base URL은 서버가 대신 호출합니다 (SSRF 주의)
|
||||
|
||||
OpenAI 호환 프리셋의 base URL은 브라우저가 아니라 **Next.js Route Handler(서버)** 가 fetch 합니다.
|
||||
|
||||
Reference in new issue
Block a user