insight into research

This commit is contained in:
itsrubberduck
2025-10-04 16:49:44 +02:00
parent 13e4164d47
commit fb4cf53a89
4 changed files with 220 additions and 26 deletions

View File

@@ -7,7 +7,7 @@
<article v-if="post" class="card space-y-6">
<header class="space-y-2">
<span class="chip text-[10px] uppercase tracking-[0.3em]">{{ formatNewsDate(post.publishedAt) }}</span>
<span class="chip text-[10px] mb-8 uppercase tracking-[0.3em]">{{ formatNewsDate(post.publishedAt) }}</span>
<h1 class="text-3xl md:text-4xl font-semibold">{{ post.title }}</h1>
<p class="text-sm text-white/60">{{ post.readingTime }}</p>
</header>
@@ -67,6 +67,11 @@ const formatNewsDate = (iso: string) => new Date(iso).toLocaleDateString('en-US'
.news-body :deep(p) { @apply text-white/80 leading-relaxed mb-4; }
.news-body :deep(ul) { @apply list-disc list-inside text-white/75 mb-4 space-y-2; }
.news-body :deep(code) { @apply bg-white/10 px-1 py-0.5 rounded text-xs; }
.news-body :deep(a) { @apply text-cyan-300 underline; }
.news-body :deep(a) { @apply text-cyan-300; }
.glass { background: rgba(255,255,255,.06); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,.08); }
</style>
<style>
.news-body p a::before { content: '↗ '; }
.news-body p a:hover { background: rgba(34,211,238,.3); }
.news-body hr { border-color: rgba(255,255,255,.1); margin: 2rem 0; }
</style>

125
content/news/state.md Normal file
View File

@@ -0,0 +1,125 @@
---
title: "The State of Open-Source AI-ATC and Why Were Building OpenSquawk"
date: "2025-06-20"
summary: "We analyzed the current market, research, and existing AI ATC systems to define how realistic, affordable, and open AI air traffic control can actually work — and where current solutions fall short."
readingTime: "14 min read"
---
While commercial AI-ATC tools have rapidly gained popularity, the open-source landscape is still almost empty. Thats exactly where **OpenSquawk** comes in.
Over the past few months, weve studied how systems like *SayIntentions.AI*, *BeyondATC*, and *FSHud* operate, which simulators dominate the market, and what current research says about AI in air traffic communication.
Our goal: to understand **what a realistic, open, and cost-efficient AI ATC should look like** — and how to actually make it viable.
---
## Why We Started This
The built-in ATC in most simulators — especially Microsoft Flight Simulator — is far from realistic radio comms.
Anyone whos flown on VATSIM or PilotEdge knows how much richer and more dynamic real-human ATC can be.
But not everyone wants (or can) go online all the time. A smart offline ATC that actually talks like a controller would be a game changer — if it could sound natural, handle real procedures, and adapt flexibly to pilots speech.
The current generation of AI systems gets close — but each hits its own ceiling.
---
## What Others Are Doing (and Where They Fall Short)
**SayIntentions.AI** proved that *unscripted ATC* can work: free-form voice input, dynamic replies, global coverage
(<a href="https://www.sayintentions.ai/pricing" target="_blank">SayIntentions AI, 2025</a>).
Technically brilliant — but expensive. Their subscription model (~€30/month) collapsed under cloud costs for STT, LLM, and TTS inference
(<a href="https://www.sayintentions.ai/opensky" target="_blank">OpenSky Closure Statement, 2025</a>).
Even the free *OpenSky* beta was shut down because it simply wasnt financially sustainable.
That taught us an important lesson: **pure cloud AI doesnt scale**.
**BeyondATC** chose a smarter path. Their AI runs **locally**, not in the cloud. The conversational layer is powered by a compact offline LLM, while the actual ATC logic (clearances, sequencing, vectoring) stays rule-based
(<a href="https://www.beyondatc.net/" target="_blank">BeyondATC.net</a>).
That hybrid approach convinced us: **LLM for language, rules for logic**. It keeps realism and reliability while avoiding the “hallucination” problem of free-running AI.
**FSHud** shows the opposite: stable AI traffic control and structured IFR flow matter even more than fancy dialogue.
It manages AI aircraft, avoids conflicts, and feels professional — but speech is rigid, tied to scripted phrases
(<a href="https://www.fshud.com/" target="_blank">FSHud.com</a>,
<a href="https://www.avsim.com/forums/topic/655442-fshud-atc-now-compatible-with-msfs2024/" target="_blank">AVSIM, 2024</a>).
Its realistic but sterile. Without semantic understanding (LLM), ATC stays mechanical.
And in the **open-source world?** Almost nothing. Apart from *Red Griffin ATC* for FlightGear (GPL, 2020) and a few legacy scripts, there is **no active project** that implements a true STT → LLM → TTS pipeline for flight simulators.
That gap is exactly what were addressing with **OpenSquawk**.
---
## Which Simulators Matter Most
Our market research shows:
- **MSFS 2020/2024** dominates, with **15+ million players**
(<a href="https://news.xbox.com/en-us/2024/03/05/microsoft-flight-simulator-15-million-players/" target="_blank">Microsoft Flight Simulator Blog, 2024</a>).
- **X-Plane 12** is smaller but technically strong, favored among serious hobbyists and training users.
- **Prepar3D** and **FlightGear** are now niche in the leisure sector.
So our roadmap is clear: **MSFS first, X-Plane second.**
Both provide APIs (SimConnect and DataRefs) that make integration of flight plans, frequencies, and AI traffic feasible.
---
## What the Research Says
We reviewed current papers and industry reports on AI in ATC:
<a href="https://arxiv.org/abs/2304.07842" target="_blank">Zuluaga-Gomez et al., 2023</a>;
<a href="https://arxiv.org/abs/2212.07164" target="_blank">Prasad et al., 2022</a>;
<a href="https://arxiv.org/abs/2508.02269" target="_blank">Gould et al., 2025</a>.
The consensus: **hybrid systems win.**
Pure LLMs hallucinate; pure rule engines are too rigid.
The best results come from combining speech transcription, LLM interpretation, and deterministic ATC logic.
Fine-tuning open models like **Llama 2** or **Mistral 7B** on real ATC dialogues is feasible — especially using open audio data (e.g., LiveATC).
Several studies also warn against letting AI make operational decisions autonomously, confirming our design direction: **the LLM speaks, but doesnt decide.**
---
## Our Technical Approach
Our architecture follows one simple principle:
**Speech-to-Text → LLM → Text-to-Speech — all local.**
- **STT:** Whisper (Tiny or Small models for real-time)
- **LLM:** locally run, ATC-tuned model (e.g., Mistral 7B, fine-tuned)
- **TTS:** Speaches (using Piper)
Everything is containerized and runs on **Windows, macOS, or Linux via Docker** — no dependency hell, no login, no cloud bill.
Thats how we keep it open, private, and sustainable.
---
## Funding and Sustainability
OpenSquawk will remain **free to use**, but we plan optional paid services for those who want more:
- local mode: 100 % free and offline,
- optional cloud add-ons: high-quality voices or hosted inference,
- community donations or institutional sponsorships for development and data hosting.
This mirrors what the most successful AI-ATC products have proven viable: **an offline core, optional cloud extras.**
---
## Takeaways
Our research made a few things clear:
- AI-ATC is not futuristic — its here.
- Open-source solutions are still missing.
- The pain points of current tools — cost, hallucination, speech tolerance — can be solved with a local hybrid design.
So thats what were building.
**OpenSquawk** aims to become a free, intelligent, locally running virtual controller that brings believable, dynamic ATC to flight simulators — not to replace real humans, but to make every offline flight feel alive again.
---
### Sources
- <a href="https://www.sayintentions.ai/" target="_blank">SayIntentions.AI (2025) — Official site and pricing</a>
- <a href="https://www.beyondatc.net/" target="_blank">BeyondATC (2025) — Official product page</a>
- <a href="https://www.fshud.com/" target="_blank">FSHud (2025) — Official site and features</a>
- <a href="https://www.avsim.com/forums/topic/655442-fshud-atc-now-compatible-with-msfs2024/" target="_blank">AVSIM (2024) — FSHud now compatible with MSFS 2024</a>
- <a href="https://news.xbox.com/en-us/2024/03/05/microsoft-flight-simulator-15-million-players/" target="_blank">Microsoft (2024) — Flight Simulator reaches 15 M players</a>
- <a href="https://arxiv.org/abs/2304.07842" target="_blank">Zuluaga-Gomez J. et al. (2023) — A Virtual Simulation-Pilot Agent for ATC Training</a>
- <a href="https://arxiv.org/abs/2212.07164" target="_blank">Prasad R., Zuluaga-Gomez J., Motlicek P. (2022) — Speech & NLP for Pseudo-Pilot Simulator</a>
- <a href="https://arxiv.org/abs/2508.02269" target="_blank">Gould S., De Ath G., Carvell R., Pepper A. (2025) — AirTrafficGen: ATC Scenario Generation with LLMs</a>

View File

@@ -66,4 +66,5 @@ export default defineNuxtConfig({
'~/assets/css/opensquawk-glass.css',
'~/assets/css/learn-theme.css'
],
})

View File

@@ -123,6 +123,7 @@ function firstParagraph(body: string): string {
if (collected.length) break
continue
}
if (line.startsWith('#') || line.startsWith('- ')) {
if (collected.length) break
continue
@@ -150,55 +151,117 @@ function markdownToHtml(markdown: string): string {
const lines = markdown.split(/\r?\n/)
let html = ''
let inList = false
let paraParts: string[] = [] // <-- sammelt Zeilen eines Absatzes
const closeList = () => {
if (inList) {
html += '</ul>'
inList = false
const closeList = () => { if (inList) { html += '</ul>'; inList = false } }
const flushPara = () => {
if (paraParts.length) {
// Soft line breaks: Zeilen mit zwei Leerzeichen am Ende -> <br>
const joined = paraParts
.map(s => s.replace(/ {2}$/, '<br>'))
.join(' ')
html += `<p>${formatInline(joined)}</p>`
paraParts = []
}
}
for (const rawLine of lines) {
const line = rawLine.trim()
if (!line) {
closeList()
const line = rawLine.replace(/\s+$/,'') // trailing spaces relevant (2 = <br>), rest säubern
const trimmed = line.trim()
// Leere Zeile: Absatz beenden
if (!trimmed) { flushPara(); closeList(); continue }
// Horizontal rule
if (/^ {0,3}(?:-{3,}|\*{3,}|_{3,})$/.test(trimmed)) {
flushPara(); closeList()
html += '<hr>'
continue
}
if (line.startsWith('#')) {
closeList()
const level = Math.min(line.match(/^#+/)?.[0].length ?? 1, 6)
const content = line.replace(/^#+/, '').trim()
// Überschriften
if (trimmed.startsWith('#')) {
flushPara(); closeList()
const level = Math.min(trimmed.match(/^#+/)?.[0].length ?? 1, 6)
const content = trimmed.replace(/^#+/, '').trim()
html += `<h${level}>${formatInline(content)}</h${level}>`
continue
}
if (line.startsWith('- ')) {
if (!inList) {
html += '<ul>'
inList = true
}
html += `<li>${formatInline(line.slice(2).trim())}</li>`
// Listen
if (trimmed.startsWith('- ')) {
flushPara()
if (!inList) { html += '<ul>'; inList = true }
html += `<li>${formatInline(trimmed.slice(2).trim())}</li>`
continue
}
closeList()
html += `<p>${formatInline(line)}</p>`
// Standard-Text: NICHT sofort <p> erzeugen, sondern sammeln
paraParts.push(trimmed)
}
flushPara()
closeList()
return html
}
function formatInline(value: string): string {
let text = escapeHtml(value)
text = text.replace(/\[([^\]]+)]\(([^)]+)\)/g, (_match, label, href) => {
const url = escapeAttribute(String(href))
return `<a href="${url}" class="text-cyan-300 underline">${String(label)}</a>`
let text = value
// 2.1 Markdown-Links [label](url) zuerst in echte <a> umwandeln
text = text.replace(/\[([^\]]+)]\(([^)]+)\)/g, (_m, label, href) => {
const url = sanitizeUrl(String(href))
const inner = escapeHtml(String(label))
return `<a href="${url}" target="_blank" rel="noopener noreferrer">${inner}</a>`
})
text = text.replace(/`([^`]+)`/g, (_match, code) => `<code>${String(code)}</code>`)
// 2.2 Bereits im Markdown vorhandene <a ...>...</a> erlauben (whitelist & sanitize)
const placeholders: string[] = []
text = text.replace(/<a\b[^>]*>.*?<\/a>/gis, (raw) => {
const safe = sanitizeAnchor(raw)
placeholders.push(safe)
return `@@A${placeholders.length - 1}@@`
})
// 2.3 Rest escapen
text = escapeHtml(text)
// 2.4 Platzhalter zurücksetzen (echte erlaubte <a> bleiben unescaped)
text = text.replace(/@@A(\d+)@@/g, (_m, i) => placeholders[Number(i)])
// 2.5 Inline-Code/Bold/Italic nach dem Escaping anwenden
text = text.replace(/`([^`]+)`/g, (_m, code) => `<code>${String(code)}</code>`)
text = text.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
text = text.replace(/\*([^*]+)\*/g, '<em>$1</em>')
return text
}
// ---- Helpers ----
function sanitizeUrl(url: string): string {
try {
const u = new URL(url, 'https://dummy.local') // Basis nötig für relative
const proto = u.protocol.toLowerCase()
if (proto === 'http:' || proto === 'https:' || proto === 'mailto:' || proto === 'tel:') {
return escapeAttribute(url)
}
} catch {}
return '#'
}
function sanitizeAnchor(raw: string): string {
// href extrahieren
const hrefMatch = raw.match(/href\s*=\s*"(.*?)"/i) || raw.match(/href\s*=\s*'(.*?)'/i)
const innerMatch = raw.match(/>([\s\S]*?)<\/a>/i)
const href = hrefMatch ? sanitizeUrl(hrefMatch[1]) : '#'
const inner = innerMatch ? escapeHtml(innerMatch[1]) : ''
return `<a href="${href}" target="_blank" rel="noopener noreferrer" class="text-cyan-300 underline">${inner}</a>`
}
function escapeHtml(value: string): string {
return value.replace(/[&<>"']/g, (char) => {
switch (char) {