mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-01 06:06:05 +08:00
Whisper prompt seeding (per request):
- ptt.post.ts builds the prompt as generic ICAO bias + this state's expected
readback appended LAST (survives the 224-token truncation), in both raw token
form and spoken ICAO form via new radioSpeech.speakToken().
- pm.vue passes the expected phrase + active variable values; classroom.vue
passes the lesson's expected field values.
Per-field readback debug:
- sttMatch.matchTranscriptionToFields returns fields[] (matched/missing + which
view matched) plus normalized/denormalized transcription views.
- useRadioBackend types readback_report on the transmit response.
- pm.vue renders a "Readback check" panel in the right log rail; classroom.vue
renders per-field rows under the STT panel.
Radio-pronunciation fixes (radioSpeech.ts):
- callsign expander handles multi-letter suffixes (DLH6RK -> Lufthansa six Romeo
Kilo).
- toRadioSpeech now expands airports (EDDC -> Echo Delta Delta Charlie).
- bare altitudes >=1000 in a clearance context are spoken ("climb initially
5000" -> "climb initially five thousand feet"); speeds/headings untouched.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
78 lines
2.5 KiB
TypeScript
78 lines
2.5 KiB
TypeScript
export interface RadioSessionResponse {
|
|
session_id: string
|
|
flow_slug: string
|
|
current_state: string
|
|
variables: Record<string, any>
|
|
flags: Record<string, boolean>
|
|
expected_pilot_template: string | null
|
|
}
|
|
|
|
export interface RadioTransmitResponse {
|
|
session_id: string
|
|
next_state_id: string
|
|
active_flow: string
|
|
controller_say_template: string | null
|
|
controller_say_rendered: string | null
|
|
expected_pilot_template: string | null
|
|
variables: Record<string, any>
|
|
flags: Record<string, boolean>
|
|
trace: Array<{ type: string; message: string }>
|
|
fallback_used: boolean
|
|
fallback_reason: string | null
|
|
auto_advanced_states?: string[]
|
|
/** True when the full chain is done — show the completion screen. */
|
|
session_complete?: boolean
|
|
/** Per-field readback diagnostic for the pilot state just evaluated. */
|
|
readback_report?: ReadbackFieldDetail[]
|
|
}
|
|
|
|
export interface ReadbackFieldDetail {
|
|
field: string
|
|
expected: string
|
|
matched: boolean
|
|
/** Which accepted spoken form matched ("two five right", "icao_phonetic"), or null. */
|
|
matched_via: string | null
|
|
/** All spoken forms that would have matched this field. */
|
|
accepted_forms: string[]
|
|
note?: string | null
|
|
}
|
|
|
|
export function useRadioBackend() {
|
|
const config = useRuntimeConfig()
|
|
|
|
function baseUrl(): string {
|
|
return (config.public.radioBackendUrl as string) || 'http://127.0.0.1:8000'
|
|
}
|
|
|
|
async function createSession(
|
|
flowSlug: string,
|
|
variables?: Record<string, any>,
|
|
noChain: boolean = false,
|
|
): Promise<RadioSessionResponse> {
|
|
return await $fetch<RadioSessionResponse>(`${baseUrl()}/api/radio/session`, {
|
|
method: 'POST',
|
|
body: { flow_slug: flowSlug, variables: variables ?? null, no_chain: noChain },
|
|
})
|
|
}
|
|
|
|
async function transmit(sessionId: string, pilotUtterance: string): Promise<RadioTransmitResponse> {
|
|
return await $fetch<RadioTransmitResponse>(
|
|
`${baseUrl()}/api/radio/session/${sessionId}/transmissions`,
|
|
{
|
|
method: 'POST',
|
|
body: { pilot_utterance: pilotUtterance },
|
|
},
|
|
)
|
|
}
|
|
|
|
async function deleteSession(sessionId: string): Promise<void> {
|
|
await $fetch(`${baseUrl()}/api/radio/session/${sessionId}`, { method: 'DELETE' })
|
|
}
|
|
|
|
async function fetchFlows(): Promise<any> {
|
|
return await $fetch(`${baseUrl()}/api/decision-flows/runtime`)
|
|
}
|
|
|
|
return { createSession, transmit, deleteSession, fetchFlows }
|
|
}
|