1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//! Runner — sync compute primitives + (transitionally) the
//! built-in thread-pool orchestration.
//!
//! ## Migration in progress
//!
//! Asry is moving to a Sans-I/O posture (per its
//! `Cargo.toml` charter, matching whisperX's function-style
//! API): threading and lifecycle become the caller's
//! responsibility. The new public primitives are:
//!
//! - [`AsrSource`] / `WhisperAsrSource` (the latter needs
//! `feature = "runner"`; not linked here because it doesn't
//! exist under a bare `emissions` build) — sync ASR compute,
//! no internal threads, caller-driven cancellation via a
//! shared `Arc<AtomicBool>`.
//! - [`crate::core::Transcriber`] — the existing Sans-I/O
//! state machine; pull commands via `poll_command()`,
//! dispatch them inline, push results back via
//! `handle_asr` / `handle_alignment` /
//! `handle_failure`.
//!
//! Sync users (CLI tools, batch indexers) drive the pump on
//! one thread. The full ASR + alignment loop, using
//! `run_one_alignment` (needs `feature = "alignment"`; not
//! linked here because it doesn't exist under a bare `emissions`
//! build) so per-language script-dispatch `runs` are honoured:
//!
//! ```ignore
//! use core::num::NonZeroU32;
//! use std::sync::{Arc, atomic::AtomicBool};
//! use mediatime::{TimeRange, Timebase};
//! use asry::{AlignWorkItem, run_one_alignment};
//! use asry::core::Command;
//! use asry::ort::session::RunOptions;
//!
//! let abort_flag = Arc::new(AtomicBool::new(false));
//! // Allocate a FRESH `RunOptions` per alignment chunk
//! // ([high]). ORT termination is
//! // sticky — reusing a single handle means the first
//! // `terminate()` poisons every subsequent
//! // `Session::run`. Per-chunk allocation keeps each
//! // watchdog deadline independent: hand the new handle to
//! // the watchdog at chunk start, drop both at chunk end.
//! // Cancellation between chunks lives on `abort_flag`.
//!
//! while let Some(cmd) = transcriber.poll_command() {
//! match cmd {
//! Command::Asr { chunk_id, samples, params, .. } => {
//! let result = asr_source.run_chunk(AsrChunkContext::new(
//! &samples,
//! ¶ms,
//! &abort_flag,
//! chunk_id,
//! ))?;
//! transcriber.handle_asr(chunk_id, result)?;
//! }
//! Command::Alignment { chunk_id, samples, sub_segments: _,
//! text, language, runs } => {
//! // Sans-I/O OOV resolution: per-run detect + decide.
//! // Each run gets its own decisions vec sized + ordered
//! // by the events `detect_oov` produces for that run's
//! // text + language. Whole-chunk fallback (when `runs`
//! // is empty) gets one inner vec.
//! let oov_decisions: Vec<Vec<asry::core::ResolvedOov>> =
//! if runs.is_empty() {
//! let events = alignment_set.detect_oov(&text, &language)?;
//! vec![asry::core::default_oov_decisions(&events)]
//! } else {
//! alignment_set.detect_oov_per_run(&runs)?
//! .iter()
//! .map(|ev| asry::core::default_oov_decisions(ev))
//! .collect()
//! };
//! // `AlignWorkItem::from_run_alignment` flips the
//! // command's output-timebase `sub_segments` into
//! // chunk-local 1/16000 (the form `Aligner::align`
//! // requires) and pulls the chunk anchor + bridge from
//! // `Transcriber`. Returns `None` only if the chunk
//! // already drained — recoverable.
//! let job = AlignWorkItem::from_run_alignment(
//! &transcriber, chunk_id, samples, text, language,
//! runs, abort_flag.clone(), oov_decisions,
//! ).expect("chunk in flight");
//! // Fresh `RunOptions` per chunk so a watchdog's
//! // `terminate()` for chunk N does not poison chunk N+1.
//! let run_options = RunOptions::new().unwrap();
//! let aligned = run_one_alignment(&alignment_set, &job, &run_options)?;
//! transcriber.handle_alignment(chunk_id, aligned)?;
//! }
//! }
//! }
//! while let Some(event) = transcriber.poll_event() { /* ... */ }
//! ```
//!
//! `run_one_alignment` honours `job.runs` for per-language
//! dispatch (Ja+Zh in one chunk, En+Ko, etc.), falling back to
//! whole-chunk alignment keyed on `job.language` when `runs`
//! is empty. Without it, code-switched chunks regress to
//! single-language alignment.
//!
//! Async users (tokio, smol) call `WhisperAsrSource::run_chunk`
//! from `spawn_blocking` and wire shutdown via their own
//! cancellation tokens flipping the supplied `abort_flag`.
// `asr_source` and `errors` compile with zero features, so their
// `mod` statements stay ungated even though `runner` (below) is now
// reachable without the `runner` feature — see the `pub mod runner;`
// doc comment in `lib.rs`. In `asr_source`, the whisper.cpp-specific
// items (`WhisperAsrSource` and its impls) are individually
// `#[cfg(feature = "runner")]`. In `errors`, `RunnerError`'s variants
// are plain data (message strings, `Duration`, `io::Error`,
// `TranscriberError`) that never name a whisper.cpp type, so the enum
// builds featureless; its only cfg-gated variant, `AlignerLoad`, is
// gated on `alignment` (the ort aligner loader), not `runner`.
// Both need `whispercpp` unconditionally (no internal cfg-splitting),
// so they stay behind `runner` specifically even though the parent
// module is reachable under `emissions` too.
pub
// `pub(crate)` (rather than `mod`) so the crate-root
// `#[cfg(feature = "bench-internals")] pub mod __bench` (and the
// `#[cfg(feature = "emissions")] pub mod emissions`) re-export this
// module's `pub(crate)`-then-`pub` algorithm items. Reachable under
// `emissions` OR `alignment`: `algorithm`, `normalizer`, and
// `normalizers` (the ort-free trellis/beam/tokenize/normalize/
// compose pipeline) need only `emissions`; `aligner`, `builder`,
// `key`, and `set` (the `Aligner`/`AlignmentSet` ort orchestration)
// stay behind `alignment` specifically via their own `#[cfg]` inside
// `runner/aligner/mod.rs`. Outside these gates the module's items
// are only visible through the curated `pub use` re-exports below.
pub
pub use WhisperAsrSource;
pub use ;
pub use RunnerError;
pub use ;
pub use ;