# `orchestrator.pkg.media_asr`
<!-- generated by `orchestrator understand`; the PKG is source of truth, edits here are advisory -->

[← Episteme](../README.md) · [Architecture](../architecture.md)

**Source:** [`src/orchestrator/pkg/media_asr.py`](../../src/orchestrator/pkg/media_asr.py)

5 types · 7 functions · python

## Changing this safely

**Tested by** (1): `tests.pkg.test_media_asr`

**Most depended-upon here** — a change to these reaches the most code (call graph, ≤4 hops):

- [`Segment`](../../src/orchestrator/pkg/media_asr.py#L55) — reaches **3** symbols
- [`_bounded`](../../src/orchestrator/pkg/media_asr.py#L177) — reaches **3** symbols
- [`_media_kind`](../../src/orchestrator/pkg/media_asr.py#L173) — reaches **3** symbols
- [`_to_ms`](../../src/orchestrator/pkg/media_asr.py#L166) — reaches **3** symbols
- [`RemoteConsentRequiredError`](../../src/orchestrator/pkg/media_asr.py#L46) — reaches **2** symbols
- [`_load_whisper`](../../src/orchestrator/pkg/media_asr.py#L140) — reaches **2** symbols · **no test path visible**
- [`_segments_from_whisper`](../../src/orchestrator/pkg/media_asr.py#L151) — reaches **2** symbols
- [`build_media_artifact`](../../src/orchestrator/pkg/media_asr.py#L192) — reaches **2** symbols

_3 of the symbols other code depends on here have no test path the graph can see — worth a second look before changing them. Absence of a path is not proof of absence of a test: calls through an attribute chain (`obj.method()`) are skipped rather than guessed at, so indirect coverage is invisible._

## Types

### `ApiAsrBackend`

[`src/orchestrator/pkg/media_asr.py:96`](../../src/orchestrator/pkg/media_asr.py#L96)

- **Called by** (1): [`media_extract`](../../src/orchestrator/cli.py#L3652)
- **Fields**: `api_key_env`, `endpoint`, `model`, `name`, `off_machine`

### `AsrBackend`

[`src/orchestrator/pkg/media_asr.py:63`](../../src/orchestrator/pkg/media_asr.py#L63)

- **Extends** (1): `typing.Protocol`
- **Fields**: `name`, `off_machine`

### `LocalWhisperBackend`

[`src/orchestrator/pkg/media_asr.py:73`](../../src/orchestrator/pkg/media_asr.py#L73)

- **Called by** (1): [`media_extract`](../../src/orchestrator/cli.py#L3652)
- **Fields**: `model`, `name`, `off_machine`

### `RemoteConsentRequiredError`

[`src/orchestrator/pkg/media_asr.py:46`](../../src/orchestrator/pkg/media_asr.py#L46)

- **Extends** (1): `RuntimeError`
- **Called by** (1): [`extract_media`](../../src/orchestrator/pkg/media_asr.py#L227)

### `Segment`

[`src/orchestrator/pkg/media_asr.py:55`](../../src/orchestrator/pkg/media_asr.py#L55)

- **Called by** (1 production · 3 test): [`_segments_from_whisper`](../../src/orchestrator/pkg/media_asr.py#L151), [`test_duration_cap_truncates_and_records`](../../tests/pkg/test_media_asr.py#L127), [`test_segment_count_cap_truncates`](../../tests/pkg/test_media_asr.py#L137), [`test_video_suffix_is_kind_video`](../../tests/pkg/test_media_asr.py#L85)
- **Fields**: `end_ms`, `start_ms`, `text`

## Functions

### `_bounded`

[`src/orchestrator/pkg/media_asr.py:177`](../../src/orchestrator/pkg/media_asr.py#L177)

- **Called by** (1): [`build_media_artifact`](../../src/orchestrator/pkg/media_asr.py#L192)

### `_load_whisper`

[`src/orchestrator/pkg/media_asr.py:140`](../../src/orchestrator/pkg/media_asr.py#L140)

- **Called by** (2): [`transcribe`](../../src/orchestrator/pkg/media_asr.py#L86), [`version`](../../src/orchestrator/pkg/media_asr.py#L82)
- **Calls** (1): [`MediaExtractorUnavailableError`](../../src/orchestrator/pkg/media_extract.py#L55)

### `_media_kind`

[`src/orchestrator/pkg/media_asr.py:173`](../../src/orchestrator/pkg/media_asr.py#L173)

- **Called by** (1): [`build_media_artifact`](../../src/orchestrator/pkg/media_asr.py#L192)

### `_segments_from_whisper`

[`src/orchestrator/pkg/media_asr.py:151`](../../src/orchestrator/pkg/media_asr.py#L151)

- **Called by** (2 production · 1 test): [`transcribe`](../../src/orchestrator/pkg/media_asr.py#L116), [`transcribe`](../../src/orchestrator/pkg/media_asr.py#L86), [`test_segments_from_whisper_normalises_and_drops_blanks`](../../tests/pkg/test_media_asr.py#L99)
- **Calls** (2): [`Segment`](../../src/orchestrator/pkg/media_asr.py#L55), [`_to_ms`](../../src/orchestrator/pkg/media_asr.py#L166)

### `_to_ms`

[`src/orchestrator/pkg/media_asr.py:166`](../../src/orchestrator/pkg/media_asr.py#L166)

- **Called by** (1 production · 1 test): [`_segments_from_whisper`](../../src/orchestrator/pkg/media_asr.py#L151), [`test_seconds_convert_to_milliseconds`](../../tests/pkg/test_media_asr.py#L92)

### `build_media_artifact`

[`src/orchestrator/pkg/media_asr.py:192`](../../src/orchestrator/pkg/media_asr.py#L192)

- **Called by** (1 production · 4 test): [`extract_media`](../../src/orchestrator/pkg/media_asr.py#L227), [`test_build_media_artifact_preserves_timestamps_and_kind`](../../tests/pkg/test_media_asr.py#L75), [`test_duration_cap_truncates_and_records`](../../tests/pkg/test_media_asr.py#L127), [`test_segment_count_cap_truncates`](../../tests/pkg/test_media_asr.py#L137), [`test_video_suffix_is_kind_video`](../../tests/pkg/test_media_asr.py#L85)
- **Calls** (4): [`MediaExtractorUnavailableError`](../../src/orchestrator/pkg/media_extract.py#L55), [`_bounded`](../../src/orchestrator/pkg/media_asr.py#L177), [`_file_sha256`](../../src/orchestrator/pkg/media.py#L52), [`_media_kind`](../../src/orchestrator/pkg/media_asr.py#L173)

### `extract_media`

[`src/orchestrator/pkg/media_asr.py:227`](../../src/orchestrator/pkg/media_asr.py#L227)

- **Called by** (1 production · 7 test): [`media_extract`](../../src/orchestrator/cli.py#L3652), [`test_extract_media_is_deterministic_for_a_pinned_version`](../../tests/pkg/test_media_asr.py#L115), [`test_extract_media_writes_and_reader_round_trips`](../../tests/pkg/test_media_asr.py#L108), [`test_local_backend_needs_no_consent`](../../tests/pkg/test_media_asr.py#L168), [`test_oversized_media_is_skipped`](../../tests/pkg/test_media_asr.py#L146), [`test_recorded_review_becomes_searchable_doc`](../../tests/pkg/test_media_asr.py#L177), [`test_remote_backend_refuses_without_consent`](../../tests/pkg/test_media_asr.py#L155), [`test_remote_backend_runs_with_consent`](../../tests/pkg/test_media_asr.py#L162)
- **Calls** (7): [`ExtractResult`](../../src/orchestrator/pkg/media_extract.py#L64), [`MediaExtractorUnavailableError`](../../src/orchestrator/pkg/media_extract.py#L55), [`RemoteConsentRequiredError`](../../src/orchestrator/pkg/media_asr.py#L46), [`_file_sha256`](../../src/orchestrator/pkg/media.py#L52), [`artifact_path`](../../src/orchestrator/pkg/media.py#L64), [`build_media_artifact`](../../src/orchestrator/pkg/media_asr.py#L192), [`write_artifact`](../../src/orchestrator/pkg/media_extract.py#L174)

## Imports

`__future__.annotations`, `dataclasses.dataclass`, `httpx`, [`orchestrator.pkg.media`](../../src/orchestrator/pkg/media.py#L1), [`orchestrator.pkg.media_extract`](orchestrator.pkg.media_extract.md), `os`, `pathlib.Path`, `typing.Protocol`, `whisper`

## Imported by

[`orchestrator.cli`](orchestrator.cli.md), [`tests.pkg.test_media_asr`](../../tests/pkg/test_media_asr.py#L1)
