Commit Graph

74 Commits

Author SHA1 Message Date
leubeem
0b7345ced7 feat(server): per-user AI usage tracking, cost alerting, and endpoint hardening
Usage tracking:
- new UsageEvent collection records every STT/TTS/LLM call per user with
  provider, model, volume (audio seconds, characters, tokens) and an
  estimated USD cost; self-hosted providers (Speaches/Piper) and cache
  hits record at $0
- pricing table for whisper-1, tts-1, gpt-5-nano & co. in server/utils/usage.ts
- weekly KPI mail gains an "AI-Nutzung & Kosten" section: weekly and
  rolling 30-day cost, per-kind breakdown, top 5 users by cost
- quota alert mail when rolling 30-day cost exceeds USAGE_ALERT_USD
  (default $5), at most once per calendar month (UsageAlertDelivery)

Hardening:
- /api/atc/say now requires an authenticated session (middleware
  exemption removed); useFlightLabAudio sends the bearer token
- /api/service/tools/latency requires auth (was a public LLM endpoint)
- per-user rate limits: PTT 20/min, say 60/min, latency 5/min
- cron endpoints (waitlist-drip, weekly-kpi-report) require a shared
  secret via ?secret= or x-cron-secret (CRON_SECRET, falls back to
  KPI_CRON_SECRET); allowed with a warning while unset so existing
  deployments keep working
- PTT records the actual transcribed audio duration for billing accuracy

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:17:03 +02:00
leubeem
0907e011fd feat(atc): accept preNormalized flag on /api/atc/say
Clients that already ran the full radiotelephony normalizer (see
normalizeATCText) pass preNormalized: true so the server skips
normalizeATC — double-normalizing corrupts the text, e.g. expandAirports
spells the city name "MAIN" letter-by-letter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 23:12:53 +02:00
itsrubberduck
d6cae201ed feat(atis): inline METAR expansion, airport name lookup, acronym fix
ATIS text often arrives in raw METAR form (e.g.
"METAR EDDF 281050Z AUTO 02008KT 320V070 CAVOK 24/02 Q1025 NOSIG"),
which TTS reads as letter-by-letter spelling. The normalizer now expands
the full WMO Code Form FM 15-XV vocabulary inline: DDHHMMZ date stamps,
compressed wind (with gusts, VRB, calm), wind variability ranges, RVR
(R25L/1500N), wind shear, slash-form temp/dewpoint, Q/A pressure,
NSC/SKC/CLR/NCD/VV cloud codes, weather phenomena (with intensity and
descriptors), recent-weather RE prefix, BECMG/TEMPO/FM/TL/AT trend
codes, and strips RMK remarks. Plus ATIS/METAR/SPECI get lowercased
so TTS pronounces them as words (pilots SPELL ILS/QNH/VOR so those
stay uppercase).

Airport ICAO codes are substituted with their OpenAIP name when the
frequencies endpoint returns one. New `airportName` field added to
the FrequencyResponse for that. Adds 7 test cases covering the user-
reported EDDF sample plus calm/VRB/gust winds, RVR, weather codes,
cloud specials, trend codes, and RMK stripping.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 13:45:15 +02:00
itsrubberduck
22f50aa403 feat(atis): clock-locked ATIS loop tied to tuned frequency
Real ATIS broadcasts run continuously; tuning in mid-broadcast should
drop the pilot into the current spoken position, then loop. The frontend
now generates the full announcement once via TTS, plays it as a looping
HTMLAudioElement, and seeks to ((Date.now() - lastUpdated) / duration)
on metadata-load so all clients tuned to the same ATIS hear it phase-
synced. The loop starts/stops automatically with frequency tuning and
restarts on info-letter change. say.post.ts now caches tag=atis like
tag=flightlab to avoid re-synthesizing identical announcements.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 14:43:48 +02:00
leubeem
d50e0e67b3 fix: correct OpenAIP v2 airport frequency parsing (3 bugs)
The frequency panel was always empty when using OpenAIP because of three
compounding bugs in frequencies.get.ts:

1. Wrong query parameter — ?icao=EDDF performs an unfiltered full-text
   search and returns all 46 000+ airports paginated; EDDF wasn't even
   on the first page.  The correct parameter is ?search=EDDF, which
   returns exactly the one matching airport.

2. Wrong ICAO field name — the code checked airport.icao but the real
   field in the v2 API response is icaoCode.  Even on a correctly
   filtered response the match would always fail.

3. Wrong frequency field names and numeric types — each frequency item
   exposes the MHz value in a value field (not frequency / frequencyMHz),
   and the service type is a numeric code (5=Delivery, 9=Ground,
   14=Tower, 15=ATIS) rather than a string.  Added OPENAIP_TYPE_MAP to
   translate these numeric codes to the internal DEL/GND/TWR/ATIS codes
   the rest of the pipeline expects.

With these fixes EDDF now returns all 8 frequencies (Delivery 122.035,
Ground 121.805, three Tower variants, two ATIS) which are then stored in
delivery_freq / ground_freq / tower_freq / atis_freq and used for both
the frequency overview panel and the per-state frequency validation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 18:16:32 +02:00
leubeem
c9f51f757f feat: wire Python backend session to PTT, add pm.vue debug logger
- Pass  as top-level field in PTT requests so Whisper STT
  results are linked to the correct Python backend session
- Add namespaced  helper in pm.vue (info/warn/error/debug/group)
  controlled by localStorage PM_DEBUG flag; logs transmit/response
  cycles, TTS calls, flag/variable syncs, and fallback warnings
- Log backend session creation context (flow, start state, vars, flags)
  in startMonitoring
- Fix typo in text input hint: STT fails not PTT fails

and

fix: sync backend variables to frontend after each transmission

The ATC say template was rendered using the frontend engine's local
variable defaults (squawk '1234', hardcoded SID, etc.) instead of
the authoritative values from the Python backend session. This caused
the spoken clearance and the readback prompt to show different squawk
codes.

- After each backend transmission response, sync all response.variables
  into vars.value (same pattern already used for flags)
- Prefer controller_say_rendered (pre-rendered by backend) over the raw
  template for TTS scheduling, eliminating any remaining dependency on
  local variable state for the ATC speech text
2026-05-20 16:44:01 +02:00
leubeem
76ab765069 Cleanup old unused code and add id sessionId to /api/atc/ptt 2026-05-20 14:13:26 +02:00
itsrubberduck
971fff388c simbrief gefixt 2026-05-06 15:43:05 +02:00
itsrubberduck
d3e6787836 first version looks ok 2026-04-25 20:29:09 +02:00
itsrubberduck
5a09f3820e feat: warn when classroom speech server is unavailable 2026-04-23 09:21:23 +02:00
itsrubberduck
7862f1ffd4 Bridge dome light mode mapping and flightlab seat belt flow 2026-02-18 22:43:56 +01:00
itsrubberduck
36ad4677dc add the lidl dome light temporarily 2026-02-18 21:49:03 +01:00
itsrubberduck
6b96b295e1 change default settings 2026-02-18 18:05:12 +01:00
itsrubberduck
ea9cc476bb besser error message 2026-02-17 19:10:50 +01:00
itsrubberduck
bf4ce3abdf typescript 2026-02-17 18:19:55 +01:00
itsrubberduck
4a01593612 fix typescript errors and update dependencies 2026-02-17 18:13:04 +01:00
itsrubberduck
25e4f77ca3 add server log 2026-02-17 15:31:32 +01:00
itsrubberduck
8bf2638a9a feat(bridge): add unlink flow for linked tokens 2026-02-16 16:39:18 +01:00
itsrubberduck
562ad236a2 use 6 digit codes for bridge 2026-02-16 15:47:12 +01:00
itsrubberduck
f271943684 Fix bridge telemetry boolean coercion for auto-advance conditions
SimConnect sends boolean fields (on_ground, parking_brake, etc.) as 0/1
numbers. The condition evaluator uses strict equality (===), so
0 === false was returning false even when the condition was semantically
met. Cast boolean telemetry fields with !! to ensure proper type matching.
Also reduce solo-mode telemetry polling from 500ms to 2000ms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:26:50 +01:00
itsrubberduck
d09221d8e3 Connect bridge telemetry to FlightLab with auto-advance triggers
Map raw bridge fields (ias_kt, on_ground, etc.) to FlightLabTelemetryState
format, add direct telemetry polling endpoint for solo mode, and show
sim condition panel in sidebar regardless of auto-advance toggle state.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 16:16:42 +01:00
itsrubberduck
ae0f0b0f86 Unify bridge auth header and add live telemetry panel 2026-02-15 16:04:07 +01:00
itsrubberduck
46f95baf9e fix(classroom): audio speed slider now actually changes playback speed with pitch correction
- Fix client: playbackRate was set to 1 for non-native-speed providers (Speaches/Piper),
  making the speed slider ineffective in the main Pizzicato audio path
- Fix server: pass speed parameter to Speaches TTS API
- Add pitch-preserving playback via MediaElementSourceNode when rate != 1,
  routing through the same Web Audio effects chain (radio filters, distortion, etc.)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:01:02 +01:00
itsrubberduck
52734e8d8b feat(flightlab): sidebar, progress bars, skip speech, SimBridge telemetry & auth
- Add collapsible sidebar with phase stepper (jump between phases)
- Add SimBridge conditions panel in sidebar (live values, progress bars, targets)
- Add global progress bar (top edge, glowing) + phase-local TTS progress bar
- Add skip button to skip TTS speech while ATC is speaking
- Add skipSpeech() to audio composable (stops current Pizzicato sound)
- Wire up bridge data.post.ts with user auth (JWT) + example payload
- Add server-side telemetry store with pub/sub for Bridge→WS relay
- Extend WS handler with subscribe-telemetry message + userId tracking
- Extend sync composable with subscribeTelemetry() + onTelemetry() callback
- Add require-auth middleware to all flightlab pages
- Fix instructor station ECONNREFUSED via import.meta.client guard
- Add animations: phase transitions, button lists, fade-scale, check-pop, pulse

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 10:14:33 +01:00
itsrubberduck
d4190c9d95 dont log users id on transmission 2026-02-13 18:44:34 +01:00
itsrubberduck
76a9e05563 add todo for najan 2025-10-19 21:03:52 +02:00
Remi
c3d6a116ac Add bidirectional airport geocode and name-aware taxi routing 2025-10-19 19:17:18 +02:00
Remi
c821ef34b3 Remove explicit type hints from airport geocode lookup 2025-10-19 19:07:23 +02:00
Remi
4d44b96665 Infer airport geocode types from query text 2025-10-19 19:00:32 +02:00
Remi
ba39b4357a Add airport geocode endpoint 2025-10-19 18:56:48 +02:00
Remi
363faa6149 Refine taxiway collapse and radius default 2025-10-18 21:47:54 +02:00
Remi
1e7748a60e Adjust taxi route collapse rules 2025-10-18 21:47:54 +02:00
Remi
143ffbf527 Preserve raw taxi route names 2025-10-18 21:47:53 +02:00
itsrubberduck
651a41106f merge 2025-10-12 15:42:18 +02:00
itsrubberduck
8c5edf2361 move data post endpoint 2025-09-24 15:54:40 +02:00
Remi
b756bf2ea6 Point bridge download to GitHub 2025-09-24 00:01:00 +02:00
Remi
7f2585c211 Improve flow activation handling and expose active nodes 2025-09-23 23:12:02 +02:00
Remi
3c12f6d836 feat: allow manual unlocks in learn missions 2025-09-22 07:40:15 +02:00
Remi
fbec5c4830 Add session timeline logging and admin sessions view 2025-09-21 23:08:10 +02:00
Remi
6c9f467b94 Enable flow-aware decision routing 2025-09-21 21:16:33 +02:00
itsrubberduck
9148607bfc test 2025-09-21 17:32:56 +02:00
itsrubberduck
966ed6340f improve latency time 2025-09-20 16:21:59 +02:00
najajan
f43230ee30 get route 2025-09-20 15:55:25 +02:00
najajan
0b50e003d5 first try with graph 2025-09-20 15:47:22 +02:00
najajan
6fe19c0ccb fix taxiroute nearest taxiway 2025-09-20 15:41:03 +02:00
Remi
d6c87d3378 Enhance admin transmissions with detailed LLM and TTS context 2025-09-20 12:42:21 +02:00
itsrubberduck
c39cbc2f3c document call example for taxiroute 2025-09-20 12:41:33 +02:00
itsrubberduck
2eae4e3aa6 add taxi route endpoint 2025-09-20 11:56:17 +02:00
Remi
440aef2f62 Fix remaining German comment 2025-09-20 09:46:34 +02:00
Remi
103fdd6bbc feat: improve learn experience 2025-09-19 23:01:39 +02:00