Provider-agnostic local speech-to-text (ASR): a Transcriber trait, a deterministic dev stub (zero native deps), and (feature-gated) an in-process whisper.cpp engine. Local-only by default — privileged audio never leaves the process.
| Tier | infrastructure |
| Role | port |
| Path | crates/infrastructure/transcription |
| Edition | 2021 |
| Targets | infrastructure_transcription, whisper_smoke |
| Public items | 10 across 0 modules |
| Tests | 20 |
What it is for
infrastructure-transcription — provider-agnostic local speech-to-text (ASR).
The surface is deliberately small: one Transcriber trait, plain input/output types (TranscriptionInput, Transcript), and a dependency-free StubTranscriber so the full ingest → transcribe → store → index pipeline builds and tests with zero native deps. The real in-process whisper.cpp impl lands behind the whisper-rs feature (WhisperRsTranscriber) and drops in behind the same trait; a faster-whisper subprocess escape hatch is reserved behind faster-whisper but is NOT the default.
Design + rationale: ADR 0019. Like the embedding surface, the default path performs NO external network egress — privileged audio stays local, which the legal consumer mandates (sending evidence audio to an external ASR API risks privilege waiver + confidentiality breach).
use infrastructure_transcription::{AudioSource, StubTranscriber, TranscribeOptions,
Transcriber, TranscriptionInput};
# async fn demo() -> Result<(), infrastructure_transcription::TranscriptionError> {
let t = StubTranscriber::new("es");
let input = TranscriptionInput::from_bytes(b"fake audio".to_vec());
let out = t.transcribe(&input, &TranscribeOptions::default()).await?;
assert!(!out.text.is_empty());
assert_eq!(out.language, "es");
# Ok(()) }
Capabilities
AudioSource
infrastructure-transcription — provider-agnostic local speech-to-text (ASR).
| Item |
|---|
pub enum AudioSource |
Segment
infrastructure-transcription — provider-agnostic local speech-to-text (ASR).
| Item |
|---|
pub struct Segment |
TranscribeOptions
infrastructure-transcription — provider-agnostic local speech-to-text (ASR).
| Item |
|---|
pub struct TranscribeOptions |
TranscribeOptions :: fn default() -> Self |
Transcriber
infrastructure-transcription — provider-agnostic local speech-to-text (ASR).
| Item |
|---|
pub trait Transcriber |
Transcript
infrastructure-transcription — provider-agnostic local speech-to-text (ASR).
| Item |
|---|
pub struct Transcript |
TranscriptionInput
infrastructure-transcription — provider-agnostic local speech-to-text (ASR).
| Item |
|---|
pub struct TranscriptionInput |
TranscriptionInput :: fn from_path(path : impl Into <PathBuf>) -> Self |
TranscriptionInput :: fn from_bytes(bytes : Vec <u8>) -> Self |
TranscriptionInput :: fn with_hint(mut self, hint : impl Into <String>) -> Self |
How to use it
From this crate's own rustdoc:
use infrastructure_transcription::{AudioSource, StubTranscriber, TranscribeOptions,
Transcriber, TranscriptionInput};
# async fn demo() -> Result<(), infrastructure_transcription::TranscriptionError> {
let t = StubTranscriber::new("es");
let input = TranscriptionInput::from_bytes(b"fake audio".to_vec());
let out = t.transcribe(&input, &TranscribeOptions::default()).await?;
assert!(!out.text.is_empty());
assert_eq!(out.language, "es");
# Ok(()) }
Module structure
No public modules: the crate root is its whole surface.
Public surface
`crate root`
| Item | What it is |
|---|---|
pub enum AudioSource | Where the audio bytes come from |
pub struct TranscriptionInput | One transcription request: the audio plus an optional container/codec hint. |
TranscriptionInput :: fn from_path(path : impl Into <PathBuf>) -> Self | Build an input from a filesystem path. |
TranscriptionInput :: fn from_bytes(bytes : Vec <u8>) -> Self | Build an input from in-memory bytes. |
TranscriptionInput :: fn with_hint(mut self, hint : impl Into <String>) -> Self | Attach a container/codec hint. |
pub struct TranscribeOptions | Knobs for a transcription run |
TranscribeOptions :: fn default() -> Self | — |
pub struct Segment | A single time-coded span of transcript text. |
pub struct Transcript | The result of a transcription: the full text, detected/forced language, and (optionally) time-coded segments. |
pub trait Transcriber | An audio → text transcriber |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
StubTranscriber | dev::StubTranscriber |
TranscriptionError | error::TranscriptionError |
{WhisperRsConfig,WhisperRsTranscriber} | whisper_rs::{WhisperRsConfig,WhisperRsTranscriber} |
{detect_repetition_loop,RepetitionLoop} | repetition::{detect_repetition_loop,RepetitionLoop} |
{find_chunks,ChunkPolicy,ChunkRange} | chunk::{find_chunks,ChunkPolicy,ChunkRange} |
Boundary
Depends on no other workspace tier.
Shares tier infrastructure with 82 other crates: infrastructure-acquire, infrastructure-adapters-google-calendar, infrastructure-adapters-google-gmail, infrastructure-adapters-google-places, infrastructure-adapters-google-trends, infrastructure-adapters-shodan, infrastructure-adapters-yelp, infrastructure-agent, … (82 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | infrastructure |
| Architectural role (taxonomy) | port |
| Location | crates/infrastructure/transcription |
| Vocabulary in force (lexicon) | current |
Dependencies
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
async-trait | ^0.1 | — | no | always |
hound | ^3 | — | yes | always |
ogg | ^0.9 | — | yes | always |
opus | ^0.3 | — | yes | always |
serde | ^1 | derive, derive | no | always |
thiserror | ^2 | — | no | always |
tokio | ^1 | full, rt | yes | always |
whisper-rs | ^0.14 | — | yes | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
tokio | ^1 | full, macros, rt-multi-thread | no | always |
Build. None.
Depended on by. 1 workspace crate.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR n_application_transcription["application-transcription"] -->|uses| SELF SELF["infrastructure-transcription"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
| Feature | Enables | On by default |
|---|---|---|
cuda | whisper-rs, whisper-rs/cuda | no |
default | — | yes |
faster-whisper | — | no |
whisper-rs | dep:whisper-rs, dep:ogg, dep:opus, dep:hound, dep:tokio | no |
flowchart LR n_cuda["cuda"] --> n_whisper_rs["whisper-rs"] n_cuda["cuda"] --> n_whisper_rs_cuda["whisper-rs/cuda"] n_default["default"] n_faster_whisper["faster-whisper"] n_whisper_rs["whisper-rs"] --> n_dep_whisper_rs["dep:whisper-rs"] n_whisper_rs["whisper-rs"] --> n_dep_ogg["dep:ogg"] n_whisper_rs["whisper-rs"] --> n_dep_opus["dep:opus"] n_whisper_rs["whisper-rs"] --> n_dep_hound["dep:hound"] n_whisper_rs["whisper-rs"] --> n_dep_tokio["dep:tokio"]
Targets
| Kind | Name | Source |
|---|---|---|
| lib | infrastructure_transcription | `src/lib.rs` |
| test | whisper_smoke | `tests/whisper_smoke.rs` |
Error model
No public error type was detected: no public item declares a type named *Error, and no public signature returns one.
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | none detected |
| async runtime | yes |
| database access | none detected |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
1 workspace crate depends on this one: application-transcription.
Verification
| Kind | Count |
|---|---|
| Unit tests | 19 |
| Integration tests | 1 |
| Examples | 0 |
| Doctests | 1 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
crate root | 6 | 0 | 3 |
What the tests establish, by name:
real_clip—tests/whisper_smoke.rsaudio_shorter_than_target_is_one_unforced_chunk—src/chunk.rsempty_input_yields_no_chunks—src/chunk.rsevery_sample_is_covered_by_at_least_one_chunk—src/chunk.rsforced_splits_overlap_so_a_boundary_word_is_not_dropped—src/chunk.rsforces_a_split_at_the_hard_cap_when_no_silence_gap_exists—src/chunk.rssplits_at_a_real_silence_gap_after_the_target_length—src/chunk.rsdefault_language_and_forced_language—src/dev.rsdeterministic_same_audio—src/dev.rsdifferent_audio_differs—src/dev.rsempty_audio_rejected—src/dev.rsover_cap_rejected—src/dev.rspath_input_hashes_path_deterministically—src/dev.rstranslate_sets_english—src/dev.rsa_sentence_occurring_a_few_times_non_pathologically_is_not_flagged—src/repetition.rsbelow_threshold_consecutive_repeats_are_not_flagged—src/repetition.rscase_and_whitespace_differences_still_count_as_the_same_sentence—src/repetition.rsdetects_the_exact_reproduced_failure_shape—src/repetition.rsempty_text_is_not_flagged—src/repetition.rsnormal_varied_text_is_not_flagged—src/repetition.rs
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 9 | 10 |
Public modules with a //! block | 0 | 0 |
pie showData
title Public items with rustdoc
"Documented" : 9
"No rustdoc detected" : 1
Metrics
| Metric | Value |
|---|---|
| Rust source files | 6 |
| Source lines | 1206 |
| Code lines | 867 |
| Public API items | 10 |
| Public modules | 0 |
| Tests | 20 |
| Examples | 0 |
| Cargo features | 4 |
| Direct runtime dependencies | 8 |
| Workspace reverse dependencies | 1 |
pie showData
title Public API by kind
"enum" : 1
"method" : 4
"struct" : 4
"trait" : 1
pie showData
title Rust source composition
"Code" : 867
"Blank or comment" : 339
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.