Documentation
¶
Overview ¶
Package stt provides a local algorithmic speech-to-command parser for ATC transcripts, replacing the LLM-based approach with fast fuzzy matching.
Index ¶
- func CleanWord(w string) string
- func CommandCategory(cmd string) string
- func CommandsEquivalent(expected, actual string, aircraft map[string]Aircraft) bool
- func ConvertNATOLetter(word string) (string, bool)
- func DoubleMetaphone(word string) (primary, alternate string)
- func EntryHash(e TestFile) string
- func ExtractNATOSpelling(words []string) (string, int)
- func FuzzyMatch(word, target string, threshold float64) bool
- func Init()
- func IsCommandKeyword(w string) bool
- func IsDigit(s string) bool
- func IsFillerWord(w string) bool
- func IsNumber(s string) bool
- func IsSingleDigit19(s string) bool
- func IsSpellingTrigger(word string) bool
- func JaroWinkler(s1, s2 string) float64
- func Levenshtein(a, b string) int
- func MatchCallsign(tokens []Token, aircraft map[string]Aircraft) (CallsignMatch, []Token)
- func NormalizeTranscript(transcript string) []string
- func ParseCommands(tokens []Token, ac Aircraft) ([]string, float64)
- func ParseDigit(s string) int
- func ParseNumber(s string) int
- func PhoneticMatch(w1, w2 string) bool
- func RegisterCallsignPattern(template string, opts ...CallsignPatternOption)
- func SanitizeTestFilename(transcript string) string
- func StopCapture() []string
- func WordScore(word, target string) float64
- type Aircraft
- type CallsignMatch
- type CallsignPattern
- type CallsignPatternOption
- func WithCallsignConfidence(conf float64) CallsignPatternOption
- func WithCallsignMinScore(score float64) CallsignPatternOption
- func WithCallsignName(name string) CallsignPatternOption
- func WithCallsignPriority(priority int) CallsignPatternOption
- func WithCallsignRequire(fn func(Aircraft) bool) CallsignPatternOption
- func WithCallsignScoring(fn func(*callsignMatchResult) float64) CallsignPatternOption
- type CandidateApproach
- type CommandMatch
- type CommandOption
- type LogBuffer
- type NumberCandidate
- type NumberContext
- type NumberKind
- type ParseResult
- type ReviewState
- type TestFile
- type Token
- type TokenType
- type Transcriber
- func (p *Transcriber) BuildAircraftContext(state *sim.UserState, userTCW sim.TCW) map[string]Aircraft
- func (p *Transcriber) DecodeCommandsForCallsign(aircraft map[string]Aircraft, transcript string, callsign string) (string, error)
- func (p *Transcriber) DecodeFromState(state *sim.UserState, userTCW sim.TCW, transcript string) (string, error)
- func (p *Transcriber) DecodeTranscript(aircraft map[string]Aircraft, transcript string, controllerRadioName string) (string, error)
- func (p *Transcriber) GetUsageStats() string
- func (p *Transcriber) ParseTranscriptDetailed(aircraft map[string]Aircraft, transcript string) ParseResult
- type ValidationResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CommandCategory ¶ added in v0.15.0
CommandCategory returns the category of an output command ("heading", "altitude", "speed", ...), or "" if it has none. Exported for analysis tooling (cmd/stteval).
func CommandsEquivalent ¶
CommandsEquivalent checks if two command strings are equivalent, considering altitude-aware flexibility for A/D/C commands. For example, "A40" and "D40" are equivalent if the aircraft is above 4000 ft.
func ConvertNATOLetter ¶
ConvertNATOLetter converts a NATO phonetic word to its letter. Returns the letter and true if found, empty string and false otherwise.
func DoubleMetaphone ¶
DoubleMetaphone generates phonetic encodings for a word. Returns primary and alternate encodings. The alternate may be empty. This is a simplified implementation covering common ATC vocabulary.
func EntryHash ¶ added in v0.15.0
EntryHash computes the identity hash of a record: transcripts plus the stored output. This must remain stable — it is the key of the persisted Seen set.
func ExtractNATOSpelling ¶
ExtractNATOSpelling extracts consecutive NATO phonetic letters from words. Returns the spelled-out string (uppercase) and number of words consumed. Stops at the first non-NATO word.
func FuzzyMatch ¶
FuzzyMatch reports whether word matches target at the given threshold.
func IsCommandKeyword ¶
IsCommandKeyword returns true if the word is a command keyword that indicates the start of a new command context. Used by the slack mechanism to avoid searching past command boundaries.
func IsFillerWord ¶
IsFillerWord returns true if the word should be ignored during parsing.
func IsSingleDigit19 ¶
IsSingleDigit19 returns true if the string is a single digit 1-9.
func IsSpellingTrigger ¶
IsSpellingTrigger returns true if the word introduces a spelling correction.
func JaroWinkler ¶
JaroWinkler computes the Jaro-Winkler similarity between two strings. Returns a value between 0.0 (no similarity) and 1.0 (identical). Jaro-Winkler gives higher weight to strings that match from the beginning.
func Levenshtein ¶ added in v0.15.0
Levenshtein returns the edit distance (insertions, deletions, substitutions) between two strings.
func MatchCallsign ¶
func MatchCallsign(tokens []Token, aircraft map[string]Aircraft) (CallsignMatch, []Token)
MatchCallsign attempts to match tokens to an aircraft callsign. Tries starting at different positions to handle garbage words at the beginning. Returns the best match and remaining tokens after the callsign.
func NormalizeTranscript ¶
func ParseCommands ¶
ParseCommands parses tokens into a sequence of commands using the registered command templates.
func ParseDigit ¶
ParseDigit converts a digit string to int. Returns -1 on error.
func ParseNumber ¶
ParseNumber converts a digit sequence to int. Returns -1 on error.
func PhoneticMatch ¶
PhoneticMatch reports whether two words are phonetically similar enough to treat as the same word in isolation.
func RegisterCallsignPattern ¶
func RegisterCallsignPattern(template string, opts ...CallsignPatternOption)
RegisterCallsignPattern registers a callsign matching pattern.
func SanitizeTestFilename ¶ added in v0.15.0
SanitizeTestFilename derives a test-file basename (without extension) from a transcript: lowercased, spaces to underscores, other punctuation dropped, truncated to 50 characters.
func StopCapture ¶
func StopCapture() []string
StopCapture stops capturing and returns the captured lines.
func WordScore ¶ added in v0.15.0
WordScore returns a graded similarity in [0,1] between a transcript word and a vocabulary target: 1.0 for an exact (case-insensitive) match, otherwise the best of letter similarity (Jaro-Winkler), phonetic similarity, and known whisper confusions, capped at scoreFuzzyCap.
Types ¶
type Aircraft ¶
type Aircraft struct {
Callsign string
AircraftType string `json:",omitempty"` // Aircraft type code (e.g., "C172", "BE36")
Fixes map[string]string `json:",omitempty"` // spoken name -> fix ID
CandidateApproaches map[string]string `json:",omitempty"` // canonical name ("RNAV Z Runway 28R") -> approach ID
CandidateVisualApproaches map[string]string `json:",omitempty"` // spoken name -> runway ID for active plain visual approaches
ApproachFixes map[string]map[string]string `json:",omitempty"` // approach ID -> (spoken name -> fix ID)
AssignedApproach string `json:",omitempty"`
ExpectedDirectFix string `json:",omitempty"` // Fix the controller said to "expect direct" (if any)
SID string `json:",omitempty"`
STAR string `json:",omitempty"`
Route []string `json:",omitempty"` // Ordered route waypoint fix names (full route, no truncation)
Altitude int `json:",omitempty"` // Current altitude in feet
Heading int `json:",omitempty"` // Current magnetic heading in degrees (0 if unknown)
Speed int `json:",omitempty"` // Current groundspeed in knots (0 if unknown)
AssignedAltitude int `json:",omitempty"` // Controller-assigned altitude in feet (0 if none)
AssignedHeading int `json:",omitempty"` // Controller-assigned heading in degrees (0 if none)
AssignedSpeed int `json:",omitempty"` // Controller-assigned speed in knots (0 if none, or if assigned in mach)
AssignedMach int `json:",omitempty"` // Controller-assigned mach in hundredths, e.g. 78 for M0.78 (0 if none, or if assigned in knots)
State string `json:",omitempty"` // "departure", "arrival", "cleared approach", "overflight", "vfr flight following"
ControllerFrequency string `json:",omitempty"` // Current controller position the aircraft is tuned to
TrackingController string `json:",omitempty"` // Controller tracking this aircraft (from flight plan)
AddressingForm sim.CallsignAddressingForm `json:",omitempty"` // How this aircraft was addressed (based on which key matched)
LAHSORunways []string `json:",omitempty"` // Runways that intersect the approach runway (for LAHSO matching)
}
Aircraft holds context for a single aircraft for STT processing. Zero means "unknown"/"none" throughout, so the JSON tags omit empty values: this struct is logged verbatim with every transmission and stored in the test corpus, where zeroes are pure noise.
type CallsignMatch ¶
type CallsignMatch struct {
Callsign string // The matched ICAO callsign (e.g., "AAL5936")
SpokenKey string // The key in the aircraft context map
Confidence float64 // Match confidence (0.0-1.0)
Consumed int // Number of tokens consumed for the callsign
AddressingForm sim.CallsignAddressingForm // How the callsign was addressed (full vs type+trailing3)
}
CallsignMatch represents a matched callsign with confidence score.
func MatchCallsignCandidates ¶ added in v0.15.0
func MatchCallsignCandidates(tokens []Token, aircraft map[string]Aircraft) []CallsignMatch
MatchCallsignCandidates returns the distinct callsign interpretations of the leading tokens, best first.
Matching proceeds using a declarative pattern-based approach:
- Weight class filtering - if "heavy"/"super" found, filter aircraft first
- Pattern-based matching - uses DSL patterns in priority order
type CallsignPattern ¶
type CallsignPattern struct {
Name string // Human-readable name for debugging
Template string // Original template string
Priority int // Higher priority patterns are tried first
Matchers []callsignMatcher // Parsed from template
MinScore float64 // Minimum score to accept a match
FixedConfidence float64 // If > 0, use this confidence instead of computed
ScoringFunc func(result *callsignMatchResult) float64 // Custom scoring function
Condition func(Aircraft) bool // Pre-filter aircraft (returns true to include)
RequireUnique bool // Only accept if exactly one aircraft matches
}
CallsignPattern represents a declarative callsign matching rule.
type CallsignPatternOption ¶
type CallsignPatternOption func(*CallsignPattern)
CallsignPatternOption configures a callsign pattern registration.
func WithCallsignConfidence ¶
func WithCallsignConfidence(conf float64) CallsignPatternOption
WithCallsignConfidence sets a fixed confidence value for matches from this pattern.
func WithCallsignMinScore ¶
func WithCallsignMinScore(score float64) CallsignPatternOption
WithCallsignMinScore sets the minimum score threshold for accepting a match.
func WithCallsignName ¶
func WithCallsignName(name string) CallsignPatternOption
WithCallsignName sets a human-readable name for the pattern.
func WithCallsignPriority ¶
func WithCallsignPriority(priority int) CallsignPatternOption
WithCallsignPriority sets the pattern priority (higher = tried first).
func WithCallsignRequire ¶
func WithCallsignRequire(fn func(Aircraft) bool) CallsignPatternOption
WithCallsignRequire sets a condition function to pre-filter aircraft.
func WithCallsignScoring ¶
func WithCallsignScoring(fn func(*callsignMatchResult) float64) CallsignPatternOption
WithCallsignScoring sets a custom scoring function.
type CandidateApproach ¶ added in v0.15.0
CandidateApproach is one approach an aircraft could be cleared for, expanded from the aircraft's canonical-name-to-code map. Id is the scenario's approach code and is what emitted commands carry; it is facility-authored and has no fixed layout ("RZ8R" at one field, "Z8R" or even "R4L" at another), so nothing may be read from its characters. The approach's type, variant letter, and runway all come from FullName, the canonical name ("RNAV Z Runway 28R"); Spoken is its telephony, and is what transcript spans are aligned against.
type CommandMatch ¶
type CommandMatch struct {
Command string // The output command string
Name string // Matched template's name, for logging
Confidence float64 // Per-token match score
Score float64 // Coverage-adjusted score used to rank competing matches
Kind commandKind // What kind of segment this template matched
Consumed int // Tokens consumed
IsThen bool // Whether this is a "then" sequenced command
IsSayAgain bool // True if this is a partial match that needs say-again
}
CommandMatch represents a matched command.
type CommandOption ¶
type CommandOption func(*sttCommand)
CommandOption configures a command registration.
func WithKind ¶ added in v0.15.0
func WithKind(k commandKind) CommandOption
WithKind marks a template as informational rather than command-issuing.
func WithName ¶
func WithName(name string) CommandOption
WithName sets a human-readable name for debugging.
func WithSayAgainMinTokens ¶ added in v0.14.2
func WithSayAgainMinTokens(n int) CommandOption
WithSayAgainMinTokens sets the minimum number of consumed tokens before SAYAGAIN triggers. Use this for commands starting with common words like "at" where a single keyword match is insufficient context. For example, "at {fix} cleared {approach}" should only trigger SAYAGAIN if the fix matched (2+ tokens consumed), not when just "at" matched.
func WithSayAgainOnFail ¶
func WithSayAgainOnFail() CommandOption
WithSayAgainOnFail enables emitting SAYAGAIN when a type parser fails. Use this for commands where the controller clearly requested something specific (like "expect approach") and we should ask for clarification.
func WithThenVariant ¶
func WithThenVariant(format string) CommandOption
WithThenVariant sets the format for "then" sequenced commands.
type LogBuffer ¶
type LogBuffer struct {
// contains filtered or unexported fields
}
LogBuffer captures STT processing logs for bug reports.
func StartCapture ¶
func StartCapture() *LogBuffer
StartCapture begins capturing log lines to a buffer. Returns the buffer that will collect the logs.
type NumberCandidate ¶ added in v0.15.0
type NumberCandidate struct {
Value int
Consumed int // tokens consumed starting at the decode position
Score float64
}
NumberCandidate is one scored interpretation of the tokens at a position.
func DecodeNumber ¶ added in v0.15.0
func DecodeNumber(tokens []Token, pos int, ctx NumberContext) []NumberCandidate
DecodeNumber decodes one number of the given kind at tokens[pos], returning all plausible interpretations ordered best-first. An empty result means no reading of the tokens at pos yields a valid value.
type NumberContext ¶ added in v0.15.0
type NumberContext struct {
Kind NumberKind
AC Aircraft
// AllowFlightLevel permits altitude values in 100-400 (which would
// otherwise be reserved for speeds) when decoding in explicit
// climb/descend context.
AllowFlightLevel bool
}
NumberContext carries the decoding kind and the aircraft context used for plausibility priors (current altitude, performance envelope).
type NumberKind ¶ added in v0.15.0
type NumberKind int
NumberKind identifies what kind of value is being decoded, which determines the valid range and the plausibility priors.
const ( NumAltitude NumberKind = iota // encoded hundreds of feet (50 = 5,000 ft) NumHeading // 001-360 degrees, normally a multiple of 5 NumSpeed // 100-400 knots, normally a multiple of 10 NumMach // hundredths (75 = Mach 0.75), 60-99 NumOClock // clock position 1-12 (traffic advisories) NumTrafficAltitude // encoded hundreds, as reported in traffic advisories )
type ParseResult ¶
type ParseResult struct {
Callsign string
Commands []string
Confidence float64
CallsignConf float64
CommandConf float64
ValidationConf float64
Errors []string
}
ParseResult holds detailed parsing results for debugging/testing.
type ReviewState ¶ added in v0.15.0
ReviewState is the persisted state of the transmission-review workflow (cmd/sttreview, cmd/stteval): a queue of records awaiting review and the set of already-processed record hashes.
func LoadReviewState ¶ added in v0.15.0
func LoadReviewState(path string) *ReviewState
LoadReviewState loads review state from path. A missing or unparseable file yields an empty state. Queue entries that are already Seen, and duplicates within the queue, are dropped.
func (*ReviewState) Ingest ¶ added in v0.15.0
func (s *ReviewState) Ingest(entries []TestFile) int
Ingest adds new entries to the queue, skipping already-seen ones and duplicates. Returns the number added.
func (*ReviewState) MarkDone ¶ added in v0.15.0
func (s *ReviewState) MarkDone(e TestFile)
MarkDone marks an entry as processed.
func (*ReviewState) Save ¶ added in v0.15.0
func (s *ReviewState) Save(path string) error
Save persists the state to path, creating parent directories as needed.
type TestFile ¶ added in v0.15.0
type TestFile struct {
Time string `json:"time,omitempty"`
Level string `json:"level,omitempty"`
Msg string `json:"msg"`
Callstack []string `json:"callstack,omitempty"`
Transcript string `json:"transcript"`
WhisperPrompt string `json:"whisper_prompt,omitempty"`
WhisperDurationMs float64 `json:"whisper_duration_ms,omitempty"`
Duration int64 `json:"duration,omitempty"`
AudioDurationMs float64 `json:"audio_duration_ms,omitempty"`
Processor string `json:"processor,omitempty"`
WhisperModel string `json:"whisper_model,omitempty"`
Callsign string `json:"callsign"`
Command string `json:"command"`
Suggested string `json:"suggested,omitempty"` // reviewer-prefill correction, if any
Reason string `json:"reason,omitempty"` // why the entry is a suspect / the suggestion (review note)
STTAircraft map[string]Aircraft `json:"stt_aircraft"`
Logs []string `json:"logs,omitempty"`
}
TestFile is the on-disk record for one STT transmission: the shape of the "STT command" entries in the vice slog, of the corpus files in stt/tests/ and stt/failing_tests/, and of the entries in cmd/sttreview's review queue. Callsign and Command hold the expected decoder output (both empty means the expected output is silence).
func LoadTestFile ¶ added in v0.15.0
LoadTestFile reads and parses one test-file JSON.
func (TestFile) BuildAircraftMap ¶ added in v0.15.0
BuildAircraftMap converts the stored per-aircraft context into the map DecodeTranscript expects, mirroring the production context initialization in provider.go: type-addressed callsigns get a /T suffix, and the assigned approach's fixes are merged into Fixes.
type Token ¶
type Token struct {
Original string // Original text from STT (before normalization)
Text string // Normalized text
Type TokenType // Token type
Value int // Numeric value if applicable (-1 if not)
}
Token represents a normalized piece of the transcript.
type Transcriber ¶
type Transcriber struct {
// contains filtered or unexported fields
}
Transcriber converts speech transcripts to aircraft control commands using local algorithmic parsing with fast fuzzy matching.
func NewTranscriber ¶
func NewTranscriber(lg *log.Logger) *Transcriber
NewTranscriber creates a new STT transcriber.
func (*Transcriber) BuildAircraftContext ¶
func (p *Transcriber) BuildAircraftContext( state *sim.UserState, userTCW sim.TCW, ) map[string]Aircraft
BuildAircraftContext creates the STT aircraft context from simulation state.
func (*Transcriber) DecodeCommandsForCallsign ¶
func (p *Transcriber) DecodeCommandsForCallsign( aircraft map[string]Aircraft, transcript string, callsign string, ) (string, error)
DecodeCommandsForCallsign parses commands from a transcript for a known callsign. This is used when the controller repeats a command without saying the callsign after an aircraft replied "AGAIN". It skips callsign matching and directly parses the entire transcript as commands for the specified aircraft. Returns one of:
- "{commands}" for successfully parsed commands
- "AGAIN" if no commands could be parsed
- "" if transcript is empty
func (*Transcriber) DecodeFromState ¶
func (p *Transcriber) DecodeFromState( state *sim.UserState, userTCW sim.TCW, transcript string, ) (string, error)
DecodeFromState decodes a transcript using the simulation state directly. It builds the aircraft context internally from the provided state. Only tracks on the user's frequency (ControllerFrequency) are included in the context.
func (*Transcriber) DecodeTranscript ¶
func (p *Transcriber) DecodeTranscript( aircraft map[string]Aircraft, transcript string, controllerRadioName string, ) (string, error)
DecodeTranscript converts a speech transcript to aircraft control commands. It returns one of:
- "{CALLSIGN} {CMD1} {CMD2} ..." for successful parsing
- "{CALLSIGN} AGAIN" if callsign identified but commands unclear
- "" if transcript is empty, only contains position identification, or no callsign could be matched
Commands may include SAYAGAIN/TYPE for partial parses where keywords were recognized but the associated value couldn't be extracted (e.g., "fly heading blark" would return "SAYAGAIN/HEADING"). Valid types are: HEADING, ALTITUDE, SPEED, APPROACH, TURN, SQUAWK, FIX. When combined with other commands, e.g., "{CALLSIGN} C50 SAYAGAIN/HEADING", the aircraft will execute the valid commands and ask for clarification on the missed part.
controllerRadioName is the user's controller radio name (e.g., "New York Departure") used to detect position identification phrases. Pass empty string if not available.
func (*Transcriber) GetUsageStats ¶
func (p *Transcriber) GetUsageStats() string
GetUsageStats returns usage statistics for this provider.
func (*Transcriber) ParseTranscriptDetailed ¶
func (p *Transcriber) ParseTranscriptDetailed( aircraft map[string]Aircraft, transcript string, ) ParseResult
ParseTranscriptDetailed provides detailed parsing results for testing.
type ValidationResult ¶
type ValidationResult struct {
ValidCommands []string // Commands that passed validation
Confidence float64 // Adjusted confidence based on validation
Errors []string // Validation error messages (for debugging)
}
ValidationResult holds the result of command validation.
func ValidateCommands ¶
func ValidateCommands(commands []string, ac Aircraft) ValidationResult
ValidateCommands validates a list of commands against aircraft state. Returns filtered commands and adjusted confidence.
Source Files
¶
- approach.go
- beam.go
- callsign.go
- callsign_engine.go
- callsign_parsers.go
- callsign_pattern.go
- callsign_patterns.go
- callsign_template.go
- commands.go
- compare.go
- fix.go
- handlers.go
- log.go
- match.go
- normalize.go
- number.go
- parse.go
- provider.go
- registry.go
- reviewstate.go
- score.go
- template.go
- template_element.go
- testfile.go
- tokenize.go
- traffic.go
- typeparsers.go
- validate.go