mattrguerra/transcription-pipelinemainPrivate on GitHub, published here in full

SETUP.md

Language Markdown4.7 KB118 lines

docs/SETUP.md

  1. # Setup
  2. Written for a Mac (Apple Silicon or Intel). Linux works the same apart from
  3. the Keychain and launchd steps.
  4. ## 1. Install
  5. ```bash
  6. git clone https://github.com/mattrguerra/transcription-pipeline.git ~/transcription-pipeline
  7. cd ~/transcription-pipeline
  8. python3.12 -m venv .venv # brew install python@3.12 if you don't have it
  9. .venv/bin/pip install -e ".[test]"
  10. ```
  11. Use Python 3.10 to 3.13; 3.12 is the safest. WhisperX does not support 3.14
  12. yet, and a newer Homebrew `python3` may be 3.14, so name the version.
  13. This pulls in WhisperX, faster-whisper, pyannote.audio and PyTorch (a few GB).
  14. No system ffmpeg is needed: the `imageio-ffmpeg` package ships its own binary,
  15. and a Homebrew `ffmpeg` is used instead when there is one.
  16. The first transcription downloads the models into `~/.cache/huggingface`:
  17. faster-whisper large-v3-turbo (about 1.6 GB), the wav2vec2 alignment model for
  18. the language, and the diarization model. Alignment also fetches NLTK's
  19. `punkt_tab` sentence data once. After that everything runs offline, except
  20. the DeepInfra engine if you choose it.
  21. ## 2. Speaker separation: a Hugging Face token
  22. pyannote's models are free but gated behind their terms.
  23. 1. Make a Hugging Face account and a **read** token (Settings, Access Tokens).
  24. 2. While signed in, open
  25. [pyannote/speaker-diarization-community-1](https://huggingface.co/pyannote/speaker-diarization-community-1)
  26. and accept the terms. (If you set `TP_DIARIZE_MODEL=pyannote/speaker-diarization-3.1`,
  27. accept that model's terms and those of
  28. [pyannote/segmentation-3.0](https://huggingface.co/pyannote/segmentation-3.0) instead.)
  29. 3. Put the token in the Keychain:
  30. ```bash
  31. security add-generic-password -a "$USER" -s transcription-pipeline.huggingface -w
  32. ```
  33. `-w` with no value prompts for it, so the token never lands in shell history.
  34. The pipeline reads `HF_TOKEN` from the environment first, then the Keychain.
  35. Nothing is ever read from a file in the repo.
  36. Without a token, run with `--no-diarize`: you get the transcript without
  37. speaker labels.
  38. ## 3. Optional: DeepInfra
  39. Local transcription is the default and nothing leaves the machine. DeepInfra's
  40. hosted Whisper large-v3-turbo is **recommended when quality matters most**: in
  41. use it has transcribed noticeably better than faster-whisper running locally
  42. with int8. The trade is that the audio is uploaded for that
  43. one step (as 16 kHz FLAC). Alignment and speaker separation still run locally.
  44. ```bash
  45. security add-generic-password -a "$USER" -s transcription-pipeline.deepinfra -w
  46. transcribe call.m4a --engine deepinfra
  47. ```
  48. or set `TP_ENGINE=deepinfra` for the watch folder. Errors come back in plain
  49. words: a rejected or rotated key (401/403), rate limited or out of credit
  50. (429), file too large (413).
  51. ## 4. Check it works
  52. ```bash
  53. .venv/bin/pytest -q # unit tier, no models
  54. TP_INTEGRATION=1 .venv/bin/pytest -q tests/integration # real models on real speech
  55. ```
  56. The integration tier transcribes `tests/fixtures/two-speakers.flac` (two
  57. LibriSpeech readers, four turns). With the Hugging Face token in the
  58. Keychain it also runs real pyannote diarization and checks that it finds both
  59. voices and switches at the right words.
  60. ## 5. The watch folder
  61. ```bash
  62. mkdir -p ~/Transcription/inbox
  63. ```
  64. 1. Edit `scheduling/run-inbox.sh`: `TP_ROOT`, `TP_VAULT_INBOX` (or delete that
  65. line), `TP_ENGINE`.
  66. 2. Copy `scheduling/com.example.transcription-pipeline.plist` to
  67. `~/Library/LaunchAgents/`, replace `YOU` with your user name, and load it:
  68. ```bash
  69. launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.transcription-pipeline.plist
  70. ```
  71. Now anything dropped in `~/Transcription/inbox` is transcribed. The layout:
  72. | Folder | What goes there |
  73. |---|---|
  74. | `inbox/` | Drop recordings here: any audio or video ffmpeg reads. |
  75. | `transcripts/` | `.txt`, `.md`, `.json` (plus `.srt` / `.vtt` if you add them to `TP_FORMATS`). |
  76. | `done/` | The recording, once transcribed. |
  77. | `failed/` | The recording plus `<name>.error.txt` saying why. Move it back to `inbox/` to retry. |
  78. The vault inbox gets a copy of the `.md` transcript, with frontmatter
  79. (`type: transcript`, `recorded`, `duration`, `speakers`, `engine`, `source`),
  80. so it flows into the rest of the vault like any other note.
  81. To stop it: `launchctl bootout gui/$(id -u)/com.example.transcription-pipeline`.
  82. The log is `~/Transcription/pipeline.log`.
  83. ## Apple Silicon notes
  84. - faster-whisper runs on the **CPU with int8**. CTranslate2 has no Metal
  85. backend, so there is no GPU path for this step on a Mac.
  86. - pyannote runs on the CPU. It supports MPS, but WhisperX's CPU path is the
  87. one tested here.
  88. - Keep the inbox outside iCloud Drive. With "Optimize Mac Storage" on, a
  89. synced file can be a placeholder rather than the audio itself.