Web STT: speaker diarization via pyannote; whisper_stt snapshot validation
- Add app/diarize.py: merge faster-whisper segments with pyannote (A/B/C) - Wire /api/jobs and /api/transcribe; job API returns speaker_diarization, diarize_skip_reason - UI: meta line shows diarization applied/skipped; hint for models path - requirements.txt: pyannote.audio; README APP_DIARIZE / APP_PYANNOTE_MODEL_DIR - whisper_stt.py: validate config.yaml before loading pipeline - requirements-whisper-stt.txt: minor doc updates if any Made-with: Cursor
This commit is contained in:
@@ -16,6 +16,31 @@ import whisper.audio as whisper_audio
|
||||
DEFAULT_DIARIZE_MODEL_DIR = "./models/pyannote-diarization-3.1"
|
||||
|
||||
|
||||
def _validate_pyannote_snapshot(model_dir: str) -> None:
|
||||
"""README만 있거나 중간에 끊긴 다운로드면 config.yaml 이 없다."""
|
||||
cfg = os.path.join(model_dir, "config.yaml")
|
||||
if os.path.isfile(cfg):
|
||||
return
|
||||
abs_dir = os.path.abspath(model_dir)
|
||||
print(
|
||||
f"오류: pyannote 모델 폴더가 불완전합니다 (config.yaml 없음): {abs_dir}\n"
|
||||
"Hugging Face에서 README만 받아졌거나, 다운로드가 중간에 끊긴 상태일 수 있습니다.\n\n"
|
||||
"프로젝트 루트에서 로그인 후 전체 스냅샷을 다시 받으세요:\n"
|
||||
" hf auth login\n"
|
||||
" hf download pyannote/speaker-diarization-3.1 \\\n"
|
||||
f" --local-dir {DEFAULT_DIARIZE_MODEL_DIR}\n\n"
|
||||
"기존 폴더를 비우고 받으려면(주의: 폴더 안 파일 전부 삭제):\n"
|
||||
f" rm -rf \"{abs_dir}\"/*\n"
|
||||
" hf download pyannote/speaker-diarization-3.1 \\\n"
|
||||
f" --local-dir {DEFAULT_DIARIZE_MODEL_DIR}\n\n"
|
||||
"https://hf.co/pyannote/speaker-diarization-3.1 에서 모델 약관 동의가 되어 있어야 합니다.\n"
|
||||
"화자 구분 없이 Whisper만 쓰려면:\n"
|
||||
" python whisper_stt.py 입력.m4a 출력.txt --no-diarize\n",
|
||||
file=sys.stderr,
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def _resolve_ffmpeg_exe() -> str:
|
||||
"""PATH의 ffmpeg 또는 imageio-ffmpeg 번들 바이너리."""
|
||||
path = shutil.which("ffmpeg")
|
||||
@@ -177,6 +202,7 @@ def _run_diarization(audio_path: str, *, diarize_model_dir: str | None) -> list[
|
||||
from pyannote.audio import Pipeline
|
||||
|
||||
model_dir = _resolve_local_diarize_dir(diarize_model_dir)
|
||||
_validate_pyannote_snapshot(model_dir)
|
||||
print(f"[4/4] 화자 분리(pyannote) — 로컬 모델: {model_dir}", flush=True)
|
||||
|
||||
print("[4/4] 화자 분리 실행 중... (수 분 걸릴 수 있음)", flush=True)
|
||||
@@ -186,8 +212,8 @@ def _run_diarization(audio_path: str, *, diarize_model_dir: str | None) -> list[
|
||||
except Exception as e:
|
||||
print(
|
||||
f"오류: pyannote 파이프라인을 불러오지 못했습니다: {e}\n\n"
|
||||
"모델 파일이 손상되었거나 하위 가중치가 빠졌을 수 있습니다.\n"
|
||||
"다시 받기:\n"
|
||||
"config.yaml 은 있는데도 실패하면 하위 체크포인트(segmentation·embedding 등)가 빠졌을 수 있습니다.\n"
|
||||
"폴더를 비운 뒤 전체 재다운로드:\n"
|
||||
" hf download pyannote/speaker-diarization-3.1 \\\n"
|
||||
f" --local-dir {DEFAULT_DIARIZE_MODEL_DIR}\n",
|
||||
file=sys.stderr,
|
||||
|
||||
Reference in New Issue
Block a user