Skip to content

Commit 505dd0b

Browse files
Fix service GPU device ordering, expand docs, add banner (v0.2.1) (#6)
* Pin CUDA device order in service startup Set CUDA_DEVICE_ORDER=PCI_BUS_ID in the service package __init__ (before any submodule imports torch), matching the CLI. Without it, CUDA's default FASTEST_FIRST ordering made REFINERY_DEVICE=cuda:N select a different physical GPU than nvidia-smi index N on multi-GPU hosts, so the service could load models onto the wrong card. * Fix and expand service-mode operations docs Correct the tmpfs example to --mount type=tmpfs,dst=/scratch, tmpfs-mode=1777 in service.md and deployment.md; a bare --tmpfs /scratch mounts root-owned and fails every job with PermissionError. Add a GPU-selection section, an end-to-end local-directory batch runbook, and troubleshooting entries (tmpfs perms, wrong-GPU, batch cap) to service.md. * Add project banner to README Add the Audio Refinery banner (118 KB JPG) centered at the top of the README. The image lives in docs/images/ because the repo-root assets/ tree is gitignored. * Prepare release v0.2.1 Patch release: service GPU-ordering fix plus service-mode doc corrections and the README banner. Bump version and add the CHANGELOG entry. * Reference side-effect import in service init test Assert on src.service.__name__ so the deliberate side-effect import (which triggers the CUDA_DEVICE_ORDER default) is no longer flagged as unused by CodeQL, and drop the now-unnecessary noqa. * Log alignment fallback and note default model Log the WhisperX forced-alignment failure at debug level (with the detected language and device) before falling back to transcription-only segments, instead of swallowing the exception silently. Document the default large-v3 model in the module docstring. * Normalize HuggingFace to Hugging Face Use the official two-word company name consistently across docs, source docstrings/help text, error messages, and tests. Error-string changes in diarizer.py and their test assertions move together. * Bump vulnerable transitive and dev dependencies Upgrade aiohttp 3.13.3 -> 3.13.5, requests 2.32.5 -> 2.34.2, Pygments 2.19.2 -> 2.20.0, and pytest 9.0.2 -> 9.0.3 to their patched versions, closing 13 Dependabot alerts. torch and transformers stay pinned (WhisperX); those alerts wait for v0.3.0. * Clarify CUDA_DEVICE_ORDER defaults and harden its test Reword "pins" to "defaults ... (respecting an explicit override)" in the service __init__ comment, service.md, and the CHANGELOG to match the os.environ.setdefault behavior. Rewrite the test with monkeypatch + importlib.reload so it deterministically covers both the default-when- unset and respect-explicit-override branches.
1 parent 1fbce29 commit 505dd0b

24 files changed

Lines changed: 204 additions & 92 deletions

CHANGELOG.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.2.1] - 2026-05-21
9+
10+
### Fixed
11+
12+
- Service mode now defaults `CUDA_DEVICE_ORDER` to `PCI_BUS_ID` at startup (matching the CLI, respecting an explicit override), so `REFINERY_DEVICE=cuda:N` selects the GPU at `nvidia-smi` index N rather than CUDA's default FASTEST_FIRST ordering. Previously a multi-GPU host could load models onto the wrong card.
13+
- WhisperX forced-alignment failures are now logged at debug level (with the detected language and device) before falling back to transcription-only segments, instead of being swallowed silently.
14+
15+
### Documentation
16+
17+
- Corrected the service-mode tmpfs example to `--mount type=tmpfs,dst=/scratch,tmpfs-mode=1777`. A bare `--tmpfs /scratch` mounts root-owned, so the non-root `refinery` user could not write scratch and every job failed with `PermissionError`. Applied the same fix in `docs/deployment.md`.
18+
- Added service-mode GPU-selection guidance, an end-to-end local-directory batch runbook, and troubleshooting entries (tmpfs permissions, wrong-GPU selection, batch-size cap) to `docs/service.md`.
19+
- Added the project banner to the README.
20+
21+
### Security
22+
23+
- Upgraded vulnerable transitive and dev dependencies to patched versions: `aiohttp` 3.13.3 → 3.13.5, `requests` 2.32.5 → 2.34.2, `Pygments` 2.19.2 → 2.20.0, and `pytest` 9.0.2 → 9.0.3. Closes 13 Dependabot alerts (10 `aiohttp` plus `requests`, `Pygments`, `pytest`). The `torch` and `transformers` alerts remain deferred to v0.3.0, when WhisperX removal lifts the `torch==2.1.2` / `transformers<4.40` pins.
24+
825
## [0.2.0] - 2026-05-20
926

1027
### Added
@@ -54,7 +71,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5471
- Centralized Demucs scratch directory resolution in CLI — RAM disk detection and fallback confirmation now happen in one place
5572
- Worker status reporting and failure aggregation in `pipeline-parallel` refactored for improved accuracy
5673
- `python-dotenv` import in Slack notifier is now conditional — avoids import-time failure when the package is absent
57-
- DEPLOYMENT.md expanded: HuggingFace token setup, NVIDIA driver requirements, cloud instance guidelines, and Docker usage
74+
- DEPLOYMENT.md expanded: Hugging Face token setup, NVIDIA driver requirements, cloud instance guidelines, and Docker usage
5875
- Combined report fields documented in README under the Parallel Pipeline section
5976

6077
### Fixed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ audio-refinery/
2626
│ ├── separator.py # Demucs vocal separation wrapper
2727
│ ├── diarizer.py # Pyannote speaker diarization wrapper
2828
│ ├── transcriber.py # WhisperX transcription wrapper
29-
│ ├── sentiment_analyzer.py # HuggingFace sentiment analysis
29+
│ ├── sentiment_analyzer.py # Hugging Face sentiment analysis
3030
│ ├── pipeline.py # Batch pipeline orchestration (947 lines)
3131
│ ├── gpu_utils.py # GPU queries via nvidia-smi
3232
│ ├── notifier.py # Slack webhook notifications

README.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
<p align="center">
2+
<img src="docs/images/audio-refinery-banner.jpg" alt="Audio Refinery — whimsical audio processing for AI" width="820">
3+
</p>
4+
15
# Audio Refinery
26

37
GPU-accelerated audio processing pipeline: vocal separation (Demucs), speaker diarization (Pyannote), transcription (WhisperX), and text sentiment analysis. Its primary use case is building AI-ready audio databases — transforming raw recordings into structured, speaker-attributed JSON with word-level timestamps that feed directly into RAG pipelines, vector stores, and fine-tuning datasets. The pipeline uses a Ghost Track strategy: AI models run against a clean, music-free vocal stem to maximize accuracy, then the resulting metadata is applied back to the original audio, preserving its acoustic character. Designed to run on 24 GB consumer GPUs with all models resident in VRAM simultaneously, it processes large corpora in batch with no model reload overhead between files.
@@ -48,7 +52,7 @@ source .venv/bin/activate
4852
# Install all deps (uv sync, whisperx, CUDA torch wheels, pre-commit hooks)
4953
make dev-setup
5054

51-
# Copy the env template and add your HuggingFace token
55+
# Copy the env template and add your Hugging Face token
5256
cp .env.example .env
5357
# Edit .env and set HF_TOKEN=hf_your_token_here
5458

@@ -65,11 +69,11 @@ audio-refinery --help
6569

6670
## Prerequisites
6771

68-
### HuggingFace access token (required for diarization)
72+
### Hugging Face access token (required for diarization)
6973

70-
Pyannote speaker diarization models are gated on HuggingFace. This applies to **both** CLI and service mode. Complete these steps once:
74+
Pyannote speaker diarization models are gated on Hugging Face. This applies to **both** CLI and service mode. Complete these steps once:
7175

72-
1. Create a HuggingFace account at [huggingface.co](https://huggingface.co) if you don't have one.
76+
1. Create a Hugging Face account at [huggingface.co](https://huggingface.co) if you don't have one.
7377
2. Accept the license for each gated model (must be logged in):
7478
- [pyannote/speaker-diarization-3.1](https://huggingface.co/pyannote/speaker-diarization-3.1)
7579
- [pyannote/segmentation-3.0](https://huggingface.co/pyannote/segmentation-3.0)
@@ -109,16 +113,16 @@ selection rationale, and data model.
109113

110114
## Documentation
111115

112-
| Document | Description |
113-
|----------------------------------------|--------------------------------------------------------------------|
114-
| [Index](docs/index.md) | Navigation hub for all documentation |
115-
| [CLI Reference](docs/cli.md) | Every command, flag, and example for workstation use |
116-
| [Service Guide](docs/service.md) | HTTP API, container deployment, env vars, ops, troubleshooting |
117-
| [Architecture](docs/architecture.md) | Ghost Track pipeline design, model selection rationale, data model |
118-
| [Use Cases](docs/use-cases.md) | Who uses this and for what |
119-
| [Performance](docs/performance.md) | Throughput benchmarks, scaling options, optimization guide |
120-
| [Deployment](docs/deployment.md) | Production patterns, async workers, Docker, monitoring |
121-
| [Development](docs/development.md) | Dev setup, testing, contributing, release process |
116+
| Document | Description |
117+
|--------------------------------------|--------------------------------------------------------------------|
118+
| [Index](docs/index.md) | Navigation hub for all documentation |
119+
| [CLI Reference](docs/cli.md) | Every command, flag, and example for workstation use |
120+
| [Service Guide](docs/service.md) | HTTP API, container deployment, env vars, ops, troubleshooting |
121+
| [Architecture](docs/architecture.md) | Ghost Track pipeline design, model selection rationale, data model |
122+
| [Use Cases](docs/use-cases.md) | Who uses this and for what |
123+
| [Performance](docs/performance.md) | Throughput benchmarks, scaling options, optimization guide |
124+
| [Deployment](docs/deployment.md) | Production patterns, async workers, Docker, monitoring |
125+
| [Development](docs/development.md) | Dev setup, testing, contributing, release process |
122126

123127
---
124128

@@ -150,4 +154,4 @@ See [docs/development.md](docs/development.md) for the full developer guide, inc
150154

151155
**audio-refinery** is released under the [MIT License](LICENSE).
152156

153-
**Dependency note:** The Pyannote model weights (`pyannote/speaker-diarization-3.1` and `pyannote/segmentation-3.0`) are gated on HuggingFace under separate terms. If you run this tool in a commercial data product, verify that your HuggingFace account's accepted terms cover your use case. The MIT license on this software does not extend to the model weights — those are governed by their respective HuggingFace model cards.
157+
**Dependency note:** The Pyannote model weights (`pyannote/speaker-diarization-3.1` and `pyannote/segmentation-3.0`) are gated on Hugging Face under separate terms. If you run this tool in a commercial data product, verify that your Hugging Face account's accepted terms cover your use case. The MIT license on this software does not extend to the model weights — those are governed by their respective Hugging Face model cards.

SECURITY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ Security issues relevant to this project include:
2424

2525
## Out of Scope
2626

27-
- Issues in third-party models (Demucs, Pyannote, WhisperX, HuggingFace) — report those upstream
27+
- Issues in third-party models (Demucs, Pyannote, WhisperX, Hugging Face) — report those upstream
2828
- Issues requiring physical access to the machine running the pipeline

docs/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ WhisperX augments Whisper with a forced alignment stage:
124124
The combination of these three outputs — text, word-level timestamps, and speaker labels — is
125125
what makes the `TranscriptionResult` JSON useful for downstream search, editing, and analysis.
126126

127-
### Stage 4: Sentiment Analysis (HuggingFace Transformers)
127+
### Stage 4: Sentiment Analysis (Hugging Face Transformers)
128128

129129
**Model:** `cardiffnlp/twitter-roberta-base-sentiment-latest` (default; configurable)
130130

docs/cli.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ batch runs over a local directory of WAV files. For the long-lived HTTP service
88

99
This page assumes you have already installed the package — see
1010
[Installation](../README.md#installation) in the README and the
11-
[HuggingFace token setup](../README.md#prerequisites), which diarization
11+
[Hugging Face token setup](../README.md#prerequisites), which diarization
1212
requires in either mode.
1313

1414
## Contents
@@ -61,7 +61,7 @@ RAM-tight machines a fast SSD is a fine target.
6161
## Demucs model weights
6262

6363
The first run auto-downloads the `htdemucs` weights (~80 MB) to
64-
`~/.cache/torch/hub/checkpoints/`. No HuggingFace token or manual download is
64+
`~/.cache/torch/hub/checkpoints/`. No Hugging Face token or manual download is
6565
required for separation.
6666

6767
---
@@ -151,7 +151,7 @@ Options:
151151
(e.g. 'cuda:0'). [default: cuda]
152152
--min-speakers INTEGER Minimum number of speakers (optional hint for Pyannote).
153153
--max-speakers INTEGER Maximum number of speakers (optional hint for Pyannote).
154-
--hf-token TEXT HuggingFace token (overrides HF_TOKEN env var).
154+
--hf-token TEXT Hugging Face token (overrides HF_TOKEN env var).
155155
-o, --output-file FILE Write DiarizationResult JSON to this file.
156156
--help Show this message and exit.
157157
```
@@ -168,8 +168,8 @@ audio-refinery diarize /path/to/vocals.wav -d cuda:0 -o /tmp/diarization.json
168168

169169
### Troubleshooting
170170

171-
- **`HuggingFace token not found`** — Follow the HF setup steps in the README.
172-
- **`Failed to load Pyannote pipeline`** — Check that you accepted both model licenses on HuggingFace.
171+
- **`Hugging Face token not found`** — Follow the HF setup steps in the README.
172+
- **`Failed to load Pyannote pipeline`** — Check that you accepted both model licenses on Hugging Face.
173173

174174
---
175175

@@ -278,7 +278,7 @@ Arguments:
278278
TRANSCRIPTION_FILE TranscriptionResult JSON written by step 3 [required]
279279
280280
Options:
281-
--model TEXT HuggingFace text-classification model name.
281+
--model TEXT Hugging Face text-classification model name.
282282
[default: cardiffnlp/twitter-roberta-base-sentiment-latest]
283283
-d, --device TEXT Compute device: 'cpu', 'cuda', or 'cuda:N'. [default: cpu]
284284
-o, --output-file FILE Write SentimentResult JSON to this file.
@@ -368,7 +368,7 @@ Options:
368368
WhisperX CTranslate2 compute type [default: float16]
369369
--batch-size INTEGER WhisperX batch size [default: 16]
370370
--language TEXT Language code (e.g. 'en') or 'auto' [default: en]
371-
--hf-token TEXT HuggingFace token for Pyannote (overrides HF_TOKEN env var)
371+
--hf-token TEXT Hugging Face token for Pyannote (overrides HF_TOKEN env var)
372372
--no-resume Re-process all files, ignoring existing outputs
373373
--keep-scratch Keep Demucs stems on the scratch disk after the run
374374
--whisper-model TEXT WhisperX model name [default: large-v3]
@@ -633,7 +633,7 @@ Options:
633633
WhisperX CTranslate2 compute type [default: float16]
634634
--batch-size INTEGER WhisperX batch size [default: 16]
635635
--language TEXT Language code (e.g. 'en') or 'auto' [default: en]
636-
--hf-token TEXT HuggingFace token for Pyannote (overrides HF_TOKEN env var)
636+
--hf-token TEXT Hugging Face token for Pyannote (overrides HF_TOKEN env var)
637637
--no-resume Re-process all files, ignoring existing outputs
638638
--keep-scratch Keep Demucs stems on the scratch disk after the run
639639
--whisper-model TEXT WhisperX model name [default: large-v3]

docs/deployment.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ the full endpoint reference, output schemas, and environment-variable table.
106106

107107
### Container prerequisites
108108

109-
#### HuggingFace token
109+
#### Hugging Face token
110110

111-
Pyannote speaker diarization uses gated models that require HuggingFace
111+
Pyannote speaker diarization uses gated models that require Hugging Face
112112
authentication:
113113

114114
1. Create a free account at [huggingface.co](https://huggingface.co)
@@ -182,7 +182,7 @@ Hub as `lunarcommand/audio-refinery:<version>`.
182182
docker run --gpus all -p 8000:8000 \
183183
-e REFINERY_API_KEYS=your-secret-key \
184184
-e HF_TOKEN="${HF_TOKEN}" \
185-
--tmpfs /scratch -e REFINERY_SCRATCH_DIR=/scratch \
185+
--mount type=tmpfs,dst=/scratch,tmpfs-mode=1777 -e REFINERY_SCRATCH_DIR=/scratch \
186186
lunarcommand/audio-refinery:latest
187187
```
188188

@@ -229,7 +229,7 @@ the command — useful for containerized batch jobs over a bind-mounted director
229229
```bash
230230
docker run --rm --gpus '"device=0"' \
231231
-v /data/audio:/data \
232-
--tmpfs /scratch -e REFINERY_SCRATCH_DIR=/scratch \
232+
--mount type=tmpfs,dst=/scratch,tmpfs-mode=1777 -e REFINERY_SCRATCH_DIR=/scratch \
233233
-e HF_TOKEN="${HF_TOKEN}" \
234234
-e SLACK_WEBHOOK_URL="${SLACK_WEBHOOK_URL}" \
235235
lunarcommand/audio-refinery:latest \

docs/development.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ audio-refinery/
9696
│ ├── separator.py # Demucs vocal separation wrapper
9797
│ ├── diarizer.py # Pyannote speaker diarization wrapper
9898
│ ├── transcriber.py # WhisperX transcription wrapper
99-
│ ├── sentiment_analyzer.py # HuggingFace sentiment analysis
99+
│ ├── sentiment_analyzer.py # Hugging Face sentiment analysis
100100
│ ├── pipeline.py # Batch pipeline orchestration
101101
│ ├── gpu_utils.py # GPU queries via nvidia-smi
102102
│ ├── notifier.py # Slack webhook notifications
@@ -270,7 +270,7 @@ Hooks run:
270270
- **ffmpeg-python**: FFmpeg subprocess wrapper
271271
- **click** (>=8.1): CLI framework
272272
- **rich** (>=13.0): Terminal formatting, tables, and progress spinners
273-
- **transformers** (>=4.30.0): HuggingFace models for sentiment analysis
273+
- **transformers** (>=4.30.0): Hugging Face models for sentiment analysis
274274

275275
### Conflicting Dependencies (Install Separately)
276276

@@ -480,7 +480,7 @@ uv run mypy src/ --ignore-missing-imports --show-error-codes
480480
- [Demucs](https://github.com/facebookresearch/demucs) — Vocal separation model
481481
- [Pyannote.audio](https://github.com/pyannote/pyannote-audio) — Speaker diarization
482482
- [WhisperX](https://github.com/m-bain/whisperX) — Transcription with alignment
483-
- [HuggingFace Transformers](https://huggingface.co/docs/transformers) — Sentiment model
483+
- [Hugging Face Transformers](https://huggingface.co/docs/transformers) — Sentiment model
484484
- [Click](https://click.palletsprojects.com/) — CLI framework
485485
- [Rich](https://rich.readthedocs.io/) — Terminal UI library
486486
- [Pydantic](https://docs.pydantic.dev/) — Data validation

docs/dockerhub-overview.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Wait for `GET /health` to return `200` (model warmup, ~10–30 s), then
2323

2424
- NVIDIA GPU — **24 GB VRAM recommended** (holds all models resident)
2525
- NVIDIA driver ≥ 525.85.12 and the NVIDIA Container Toolkit on the host
26-
- A HuggingFace token for the gated Pyannote models (`HF_TOKEN`)
26+
- A Hugging Face token for the gated Pyannote models (`HF_TOKEN`)
2727

2828
## Tags
2929

@@ -35,7 +35,7 @@ Wait for `GET /health` to return `200` (model warmup, ~10–30 s), then
3535
| Variable | Purpose |
3636
|----------|---------|
3737
| `REFINERY_API_KEYS` | **required** — bearer-token allowlist |
38-
| `HF_TOKEN` | **required**HuggingFace token for diarization |
38+
| `HF_TOKEN` | **required**Hugging Face token for diarization |
3939
| `REFINERY_WHISPER_MODEL` | Whisper variant (default `large-v3`) |
4040
| `REFINERY_SCRATCH_DIR` | per-job scratch; mount a tmpfs for throughput |
4141

@@ -44,5 +44,5 @@ Full environment reference, CLI usage, and architecture:
4444

4545
## License
4646

47-
MIT. Pyannote model weights are gated under separate HuggingFace terms — verify
47+
MIT. Pyannote model weights are gated under separate Hugging Face terms — verify
4848
your account's accepted terms cover your use case.
115 KB
Loading

0 commit comments

Comments
 (0)