Expand description
Dictation - the [dictate] section in forge.toml, and the
preflight pass that makes the models usable before forge starts.
The costs are what shape this. A first run fetches 3.07 GB; every later one re-hashes what is on disk, about 0.8 s for the pair now the two models are prepared concurrently, then loads the weights, another second warm. The hash is skipped for a model whose size and modification time still match the digest recorded for it, which is every boot but the one after a file changed. None of that can happen while somebody is dictating, so all of it happens once, at boot, on the preflight screen.
Re-exports§
use std::collections::HashMap;🔒use std::path::PathBuf;🔒use std::sync::Arc;🔒use std::sync::atomic::AtomicBool;🔒use std::sync::atomic::Ordering;🔒use std::time::Duration;🔒use std::time::Instant;🔒use parking_lot::Mutex;🔒use serde::Deserialize;🔒use serde::Deserialize;🔒use tokio::time::MissedTickBehavior;🔒use crate::SessionSlot;🔒use crate::protocol::DictateOutcome;🔒use crate::protocol::SessionUpdate;🔒
Structs§
- Dictate
Axes - The three axes decided, as a client that captures sends them: the values it read from the greeting with its own edits applied, so every axis is a value rather than a maybe. The crate defaults stand in where nothing was configured, which is what the client’s own panel draws as the unset state.
- Dictate
Model - One model’s row in preflight.
- Dictate
Overrides - What a session has overridden on the normalizer’s prompt axes.
Noneon an axis means “the crate default”; the/dictatedialog derives each row’s in-force marker from this plus the defaults. - Dictate
Runtime 🔒 - Dictation state across every session. Every take is fed by a client’s own frames and holds no device, so several seats can dictate at once; several takes can also be finishing, because a new recording never waits for the previous transcript.
- Dictate
Settings - The
[dictate]section. Every field has a default, so an absent section is exactlyenabled = false. - Dictate
Snapshot - Everything preflight knows about dictation right now.
- Dictate
State 🔒 - Preflight’s own handle on the work: the snapshot a view renders, the cancellation flag, and the active models the resolution landed.
- Finishing
Take 🔒 - A submitted take still awaiting its transcript. The recording is already stopped; the entry stays only so a stop can still abandon it.
- Live
Recording 🔒 - The live side of one dictation: the channel its task polls for the
stop decision (
trueon the channel means submit,falsemeans abandon), and - for a take the client captures - the sink the socket pushes frames into. The seat is the map key, so the entry does not carry it again. - Registered
Take 🔒 - A take the client will feed with frames, registered and ready to run: what the socket pushes into, what the runner finishes, and what the take normalizes by.
- SetRecording 🔒
- The read-aloud set being recorded, when one is: the audio a client’s own frames have fed so far, held until the stop that keeps or drops it. It belongs to no session - the words are known, so nothing is transcribed and nothing is routed - but it is a live capture like any other, and the guards that wait on captures count it.
- Transfer
Progress 🔒 - Per-file transfer bookkeeping, kept across the progress events of one
preparecall.
Enums§
- Dictate
Bind - The push-to-talk key. Right Cmd is the default; on Linux and Windows there is no Cmd key, so the cmd equivalent is the right Control key.
- Dictate
Failure - Why preflight stopped.
- Dictate
Mode - How a press/release pair maps onto starting and stopping a take.
Autoinfers from timing; the forced modes bypass the tap window entirely. - Dictate
Model State - How far one model has got.
- Dictate
Override Update - One edit the
/dictatedialog asks for: set a single axis, or clear them all. Enter on an already-set row re-sets the same value; there is no per-axis clear, so the reset row is the only way back. - Dictate
Role - What a model is for. Preflight labels the row by role and prints the file underneath, because the role is what a reader is scanning for and the file is the detail they want only when something is wrong.
- Take
Resolution 🔒 - How waiting on a submitted take ended.
Constants§
- DEFAULT_
MAX_ 🔒CAPTURE_ MINUTES - Cap on one recording when
[dictate] max_capture_minutesis absent. Matches the crate’s own default; a capture reserves 4 bytes a sample eagerly, so this is about 110 MiB held for the run. - METER_
INTERVAL 🔒 - How often the live recording is polled for its level. A deliberate fourth clock: coarser than the repaint gate, so every level event lands on a repaint without driving it.
- PROGRESS_
POLL 🔒 - How often a submitted take’s per-window progress stream is polled. A window takes seconds to decode; this cannot be felt.
- STOP_
PARK_ 🔒WINDOW - How long after parking a stop is still treated as racing its start’s registration. The gap it covers is the scheduler’s delay between two spawned tasks, so anything older is a stop whose take is already gone.
Functions§
- clear_
recording_ 🔒if_ ours - Clear the seat’s live entry when the take that owns it has resolved - a teardown may already have removed it, which this tolerates.
- default_
max_ 🔒capture_ minutes - enabled_
by_ 🔒default - failing_
file 🔒 - The file an error is about, so the row that failed is the one that goes red.
- failure_
for 🔒 - forward_
take_ 🔒progress - Forward a take’s progress steps as updates while it runs. Steps arrive while the recording is still open (segments settling, no total) and again after the stop (total known); the task ends when the take’s segmenter closes the stream.
- handle_
dictate_ 🔒stop Command::DictateStop: submit (true) or abandon the take thatkeystarted. A stop that arrives before its start has registered is parked instop_pendingfor the registration to honour, rather than dropped: dropping it would orphan a take until the take’s own cap ended it. A stop whose take already resolved parks too - the park cannot tell the two apart on arrival - but it is only honoured while fresh, and every take-resolution path clears it, so it never poisons the session’s next attempt.- map_
outcome 🔒 - Map the crate’s answer onto the wire outcome. A normalisation that produced nothing is a valid answer, not a failure.
- move_
to_ 🔒finishing - Move this take’s stop channel from the live map to the finishing list, so a stop during transcription still routes to it.
- preflight_
config 🔒 - The config preflight builds the engine from: the
[dictate]settings, the resolved active models, and the always-on stores under forge’s app-support dir - per-take diagnostics and the verified-digest record - machine-local and never synced. - prepare 🔒
- The fetch-and-verify leg.
Err(())meansstatealready carries the reason. - record_
until_ 🔒stopped - Stream level events until a stop decision or the capture cap stops itself. Returns whether the take should be submitted.
- register_
stream_ 🔒take Command::DictateStream: register a take the client will feed with frames.- remove_
finishing 🔒 - Drop this take’s finishing entry, whatever took it out of routing.
- run_
dictate_ 🔒preflight - Fetch, verify and load the active models, reporting progress into
stateas it goes. The caller resolves the models and builds the config; a dictation-off run never gets here. - run_
recording 🔒 - Own one take from first sample to delivered transcript: stream level events while recording, then submit and wait, honouring the stop channel at every phase. Segments of a long take transcribe while the recording is still running; the transcript lands once the take’s join has been normalized.
- run_
stream_ 🔒take - Own a stream-fed take from its registration to its delivered transcript: the recording lifecycle, with the axes the client sent.
- spec_
size 🔒 - Byte length the config records for the model at
path, or zero when the error is about a file no spec names. - teardown_
all 🔒 - Release every session’s dictation at once, for workspace shutdown.
- teardown_
for_ 🔒closed_ session - Abandon everything
keyhas in flight: a live take goes back (dropping the entry closes the stop channel, which is what makes its runner abandon it) and a submitted take loses its cancel route. Called when the session closes. - wait_
for_ 🔒take - Wait for a submitted take’s answer or a stop decision, whichever
comes first. A submit decision is a no-op (the take is already in),
and ANY other stop -
Some(false)from Esc, or the channel closing at teardown - fires this take’s own cancel token and abandons the wait. The abandon must end the wait rather than re-select: a closed channel answers immediately and forever, and a loop that keeps polling it busy-spins a core until the inference runs out on its own.