feat(web): speaker diarization via pyannote (parity with whisper_stt)
- Add app/diarize.py: local snapshot, A/B labels, disclaimer text - transcribe_file and async jobs support diarize flag; Form diarize on API - UI checkbox (default on); requirements: pyannote.audio, huggingface_hub - README: env vars and model notes Made-with: Cursor
This commit is contained in:
47
README.md
47
README.md
@@ -4,8 +4,9 @@
|
||||
|
||||
- **백엔드**: FastAPI (업로드/검증/STT 수행)
|
||||
- **STT 엔진**: `faster-whisper` (Whisper 모델)
|
||||
- **화자 분리(웹 기본 켜짐)**: `pyannote` — `whisper_stt.py`와 동일하게 로컬 `./models/pyannote-diarization-3.1` + HF 토큰·게이트 동의 필요. UI/API에서 끌 수 있음(`diarize=false`).
|
||||
- **프론트**: 단일 HTML (파일 선택 → 전사 → 결과 표시/다운로드)
|
||||
- **선택 CLI**: `whisper_stt.py` — OpenAI Whisper 기반 로컬 전사(**기본: 화자 구분**, 로컬 `./models/pyannote-diarization-3.1`)
|
||||
- **선택 CLI**: `whisper_stt.py` — OpenAI Whisper 기반 로컬 전사(**기본: 화자 구분**, 동일 pyannote 스냅샷)
|
||||
|
||||
## 동작 개요 (pseudocode)
|
||||
|
||||
@@ -151,16 +152,60 @@ conda activate stt # 또는 ncue
|
||||
uvicorn app.main:app --reload --host 127.0.0.1 --port 8025
|
||||
```
|
||||
|
||||
또는 저장소 루트에서 **`./run.sh`** (백그라운드 + `server.log`, 기본 포트 `8025`, `PORT`·`CONDA_ENV` 등으로 조정).
|
||||
|
||||
브라우저에서 `http://127.0.0.1:8025` 접속.
|
||||
|
||||
웹 UI는 **faster-whisper** 전사만 수행합니다. 화자 구분이 필요하면 **`whisper_stt.py`**(로컬 CLI)를 사용하세요.
|
||||
|
||||
### HTTPS 도메인(`https://ncue.net/stt/…`)에서 503 (Service Unavailable)
|
||||
|
||||
브라우저가 **503**을 보여 줄 때, 대부분 **리버스 프록시(nginx 등)가 백엔드(uvicorn)에 붙지 못했다**는 뜻입니다. 이 저장소의 앱은 일반적으로 **503을 직접 내지 않습니다.**
|
||||
|
||||
**흔한 원인**
|
||||
|
||||
1. **`run.sh`를 다른 머신에서만 실행한 경우**
|
||||
`run.sh`는 uvicorn을 **`127.0.0.1:8025`**에만 띄웁니다. **nginx가 돌아가는 서버와 같은 호스트**에서 프로세스가 떠 있어야 `https://도메인/stt/` 프록시가 연결됩니다. 노트북에서만 `./run.sh`를 켜 두면 공개 도메인 쪽 업스트림은 비어 있어 **503**이 납니다.
|
||||
|
||||
2. **프로세스가 곧바로 종료된 경우**
|
||||
DB 설정 오류, import 실패 등으로 uvicorn이 뜨자마자 죽으면 프록시도 503을 냅니다. **서버에서** `tail -n 100 server.log` 로 스택 트레이스를 확인하세요.
|
||||
|
||||
3. **포트·프록시 설정 불일치**
|
||||
nginx `upstream` / `proxy_pass`가 가리키는 포트가 실제 uvicorn 포트(`PORT`, 기본 8025)와 같아야 합니다.
|
||||
|
||||
**같은 서버에서 빠른 점검**
|
||||
|
||||
```bash
|
||||
curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8025/healthz
|
||||
# 200 이어야 정상
|
||||
ss -lntp | grep 8025
|
||||
# 또는: lsof -iTCP:8025 -sTCP:LISTEN
|
||||
```
|
||||
|
||||
**nginx 예시** (`/stt/` 아래로 서비스할 때, 접두사를 벗겨 uvicorn의 `/`·`/api/…`에 넘깁니다)
|
||||
|
||||
```nginx
|
||||
location /stt/ {
|
||||
proxy_pass http://127.0.0.1:8025/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
```
|
||||
|
||||
`proxy_pass`에 **끝 슬래시(`/`)**가 있어야 `location /stt/`와 짝이 맞아 경로가 올바르게 넘어갑니다. 설정을 고친 뒤 **`nginx -t` 후 reload** 하세요.
|
||||
|
||||
공개 URL은 가능하면 **`https://예시/stt/`** 처럼 **슬래시까지 포함**해 두면, UI의 상대 경로(`healthz`, `api/…`)가 같은 접두사 아래로 잘 붙습니다.
|
||||
|
||||
---
|
||||
|
||||
## 옵션·환경 변수
|
||||
|
||||
- **모델**: 기본 `small` (정확도/속도 균형). `APP_WHISPER_MODEL=base|small|medium|large-v3` 등으로 변경 가능.
|
||||
- **디바이스**: 기본 CPU. Apple Silicon에서 Metal은 `faster-whisper` 단독으로는 제한이 있어 CPU 기본값을 권장.
|
||||
- **화자 분리**: `pip install -r requirements.txt`에 `pyannote.audio`가 포함됩니다. 모델 폴더는 `WHISPER_DIARIZE_MODEL_DIR` / `PYANNOTE_MODEL_DIR` 또는 기본 `./models/pyannote-diarization-3.1`. 다른 경로는 `APP_PYANNOTE_MODEL_DIR`로 지정 가능. HF 토큰(`HF_TOKEN` 등)과 gated 저장소 동의는 `whisper_stt.py` 절·`requirements-whisper-stt.txt` 주석과 동일합니다.
|
||||
- **기타**: `APP_WHISPER_DEVICE`, `APP_WHISPER_COMPUTE_TYPE`, 업로드 크기 등은 `app/main.py` 및 `.env` 예시를 참고.
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user