mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-04 16:22:48 +08:00
webseite sieht gut aus
This commit is contained in:
Binary file not shown.
@@ -1,22 +1,22 @@
|
||||
<template>
|
||||
<div class="bg-[#0b1020] text-white antialiased selection:bg-cyan-400/30">
|
||||
<!-- NAV -->
|
||||
<header class="sticky top-0 z-50 bg-[#0b1020]/70 backdrop-blur border-b border-white/10">
|
||||
<nav class="mx-auto max-w-[1200px] px-4 py-3 flex items-center justify-between">
|
||||
<a href="#" class="flex items-center gap-2 font-semibold tracking-tight">
|
||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" class="text-cyan-400"><path d="M12 3l8 4v10l-8 4-8-4V7l8-4z" stroke="currentColor" stroke-width="1.5"/><path d="M12 7l4 2v6l-4 2-4-2V9l4-2z" fill="currentColor" class="opacity-60"/></svg>
|
||||
<header class="sticky top-0 z-50 bg-[#0b1020]/70 backdrop-blur border-b border-white/10" data-aos="fade-down">
|
||||
<nav class="container-outer py-3 flex items-center justify-between">
|
||||
<NuxtLink to="#" class="flex items-center gap-2 font-semibold tracking-tight">
|
||||
<v-icon icon="mdi-radar" size="28" class="text-cyan-400" />
|
||||
<span class="text-white">OpenSquawk</span>
|
||||
</a>
|
||||
</NuxtLink>
|
||||
<div class="hidden md:flex gap-6 text-sm">
|
||||
<a href="#features" class="hover:text-cyan-300">Features</a>
|
||||
<a href="#learn" class="hover:text-cyan-300">Lernpfad</a>
|
||||
<a href="#pricing" class="hover:text-cyan-300">Preise</a>
|
||||
<a href="#opensource" class="hover:text-cyan-300">Open‑Source</a>
|
||||
<a href="#faq" class="hover:text-cyan-300">FAQ</a>
|
||||
<NuxtLink to="#features" class="hover:text-cyan-300">Features</NuxtLink>
|
||||
<NuxtLink to="#learn" class="hover:text-cyan-300">Lernpfad</NuxtLink>
|
||||
<NuxtLink to="#pricing" class="hover:text-cyan-300">Preise</NuxtLink>
|
||||
<NuxtLink to="#opensource" class="hover:text-cyan-300">Open‑Source</NuxtLink>
|
||||
<NuxtLink to="#faq" class="hover:text-cyan-300">FAQ</NuxtLink>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="#demo" class="btn btn-ghost text-sm">Live‑Demo</a>
|
||||
<a href="#cta" class="btn btn-primary text-sm">Frühzugang</a>
|
||||
<NuxtLink to="#demo" class="btn btn-ghost text-sm">Live‑Demo</NuxtLink>
|
||||
<NuxtLink to="#cta" class="btn btn-primary text-sm">Frühzugang</NuxtLink>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
@@ -27,27 +27,27 @@
|
||||
<div class="absolute -top-24 right-0 w-[600px] h-[600px] bg-cyan-500/10 rounded-full blur-3xl" />
|
||||
</div>
|
||||
|
||||
<div class="mx-auto max-w-[1200px] px-4 pt-16 pb-12 md:pt-24 md:pb-20">
|
||||
<div class="max-w-2xl">
|
||||
<div class="container-outer pt-16 pb-12 md:pt-24 md:pb-20">
|
||||
<div class="max-w-2xl" data-aos="fade-up">
|
||||
<span class="chip mb-4">Open‑Source · AI‑ATC · Simulator</span>
|
||||
<h1 class="text-4xl md:text-6xl font-semibold leading-tight">OpenSquawk<br><span class="text-cyan-400">AI‑ATC, offen & bezahlbar</span></h1>
|
||||
<h1 class="text-4xl md:text-6xl font-semibold leading-tight">OpenSquawk<br/><span class="text-cyan-400">AI‑ATC, offen & bezahlbar</span></h1>
|
||||
<p class="mt-4 md:mt-6 text-white/80 text-base md:text-lg">Offene Alternative für AI‑ATC im Flugsimulator. Lerne echte Phraseologie, übe sichere Abläufe und steige Schritt für Schritt Richtung VATSIM ein. Optional als gehosteter Plan – so günstig wie möglich.</p>
|
||||
<div class="flex flex-col sm:flex-row gap-3 mt-6">
|
||||
<a href="#cta" class="btn btn-primary text-base">Frühzugang sichern</a>
|
||||
<a href="#video" class="btn btn-ghost text-base">1‑Min‑Überblick ansehen</a>
|
||||
<NuxtLink to="#cta" class="btn btn-primary text-base">Frühzugang sichern</NuxtLink>
|
||||
<NuxtLink to="#video" class="btn btn-ghost text-base">1‑Min‑Überblick ansehen</NuxtLink>
|
||||
</div>
|
||||
<div class="mt-6 flex items-center gap-4 text-white/70 text-sm">
|
||||
<div class="flex -space-x-3">
|
||||
<img alt="avatar" src="https://i.pravatar.cc/40?img=1" class="w-8 h-8 rounded-full border border-white/10" />
|
||||
<img alt="avatar" src="https://i.pravatar.cc/40?img=2" class="w-8 h-8 rounded-full border border-white/10" />
|
||||
<img alt="avatar" src="https://i.pravatar.cc/40?img=3" class="w-8 h-8 rounded-full border border-white/10" />
|
||||
<img alt="avatar" src="https://i.pravatar.cc/40?img=1" class="w-8 h-8 rounded-full border border-white/10"/>
|
||||
<img alt="avatar" src="https://i.pravatar.cc/40?img=2" class="w-8 h-8 rounded-full border border-white/10"/>
|
||||
<img alt="avatar" src="https://i.pravatar.cc/40?img=3" class="w-8 h-8 rounded-full border border-white/10"/>
|
||||
</div>
|
||||
<p><b>1500+</b> Pilot:innen im Early‑Access</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-10 md:mt-16">
|
||||
<div class="mt-10 md:mt-16" data-aos="zoom-in" data-aos-delay="100">
|
||||
<div class="card relative overflow-hidden">
|
||||
<div class="absolute inset-0 bg-gradient-to-r from-cyan-500/10 via-blue-500/5 to-transparent" />
|
||||
<div class="absolute inset-0 bg-gradient-to-r from-cyan-500/10 via-blue-500/5 to-transparent"></div>
|
||||
<img src="https://images.unsplash.com/photo-1509749837427-392dfae2dbd1?q=80&w=1600&auto=format&fit=crop" alt="Cockpit" class="rounded-xl w-full object-cover" />
|
||||
<div class="absolute bottom-3 right-3 text-xs text-white/70 bg-black/40 px-2 py-1 rounded">Symbolbild</div>
|
||||
</div>
|
||||
@@ -56,43 +56,43 @@
|
||||
</section>
|
||||
|
||||
<!-- SOCIAL PROOF / LOGOS -->
|
||||
<section class="py-10 border-t border-white/10 bg-[#0a0f1c]">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<section class="py-10 border-t border-white/10 bg-[#0a0f1c]" data-aos="fade-up">
|
||||
<div class="container-outer">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-6 items-center opacity-80">
|
||||
<div class="text-center text-white/60">MSFS</div>
|
||||
<div class="text-center text-white/60">X‑Plane</div>
|
||||
<div class="text-center text-white/60">VATSIM* (Lernpfad)</div>
|
||||
<div class="text-center text-white/60">IVAO* (Lernpfad)</div>
|
||||
<div class="flex items-center justify-center gap-2 text-white/60"><v-icon icon="mdi-microsoft-xbox" class="opacity-70"/>MSFS</div>
|
||||
<div class="flex items-center justify-center gap-2 text-white/60"><v-icon icon="mdi-airplane" class="opacity-70"/>X‑Plane</div>
|
||||
<div class="flex items-center justify-center gap-2 text-white/60"><v-icon icon="mdi-headset" class="opacity-70"/>VATSIM* (Lernpfad)</div>
|
||||
<div class="flex items-center justify-center gap-2 text-white/60"><v-icon icon="mdi-radar" class="opacity-70"/>IVAO* (Lernpfad)</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FEATURES -->
|
||||
<section id="features" class="py-16 md:py-24 bg-gradient-to-b from-[#0a0f1c] to-[#0b1020]">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<div class="max-w-2xl mb-10">
|
||||
<div class="container-outer">
|
||||
<div class="max-w-2xl mb-10" data-aos="fade-up">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold">Warum OpenSquawk?</h2>
|
||||
<p class="mt-3 text-white/80">Echtzeit‑Funk mit KI, lernfreundliche Erklärungen und offene Architektur – damit du souverän taxi, departure, approach & landing beherrschst.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-6">
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="0">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M12 3l8 4v10l-8 4-8-4V7l8-4z" stroke="#22d3ee"/></svg></div>
|
||||
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><v-icon icon="mdi-tower-fire" class="text-cyan-300"/></div>
|
||||
<h3 class="font-semibold text-lg">AI‑ATC in Echtzeit</h3>
|
||||
</div>
|
||||
<p class="mt-3 text-white/80">Streaming‑ASR, LLM‑Verständnis & TTS Stimmen. Klar, schnell, latenzarm – optimiert für Phraseologie.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="100">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke="#22d3ee"/></svg></div>
|
||||
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><v-icon icon="mdi-school" class="text-cyan-300"/></div>
|
||||
<h3 class="font-semibold text-lg">Lernpfad → VATSIM</h3>
|
||||
</div>
|
||||
<p class="mt-3 text-white/80">Geführte Übungen, Checks & Erklärungen – vom Readback bis zu komplexen Clearances. Schrittweise Richtung Online‑Netzwerke.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="200">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><svg width="22" height="22" viewBox="0 0 24 24" fill="none"><path d="M5 12h14M12 5v14" stroke="#22d3ee"/></svg></div>
|
||||
<div class="p-2 rounded-lg bg-cyan-500/20 border border-cyan-400/20"><v-icon icon="mdi-source-repository" class="text-cyan-300"/></div>
|
||||
<h3 class="font-semibold text-lg">Open‑Source + Hosted</h3>
|
||||
</div>
|
||||
<p class="mt-3 text-white/80">Selbst hosten oder unseren günstigen Plan nutzen. Transparente Architektur, Community‑Plugins & APIs.</p>
|
||||
@@ -100,7 +100,7 @@
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-2 gap-6 mt-6">
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="0">
|
||||
<h3 class="font-semibold text-lg">Taxi‑Routen & Ground Awareness</h3>
|
||||
<p class="mt-3 text-white/80">OSM/apt.dat‑basierte Taxiway‑Graphen, A*‑Routing zu Holding Points, progressive Anweisungen mit Visual‑Overlay.</p>
|
||||
<ul class="mt-3 space-y-2 text-white/70 text-sm list-disc list-inside">
|
||||
@@ -109,14 +109,14 @@
|
||||
<li>Optional: NOTAM/ATIS Einbindung</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="100">
|
||||
<h3 class="font-semibold text-lg">Tech‑Stack</h3>
|
||||
<p class="mt-3 text-white/80">Streaming‑ASR, LLM‑Dialog, TTS – orchestriert mit WebRTC/WS. Offline‑Fallbacks möglich.</p>
|
||||
<div class="mt-4 grid grid-cols-2 gap-3 text-sm">
|
||||
<div class="glass rounded-xl p-3">ASR: Whisper/Alternativen (API)</div>
|
||||
<div class="glass rounded-xl p-3">LLM: GPT‑5‑Nano/4o‑Mini etc.</div>
|
||||
<div class="glass rounded-xl p-3">TTS: neural voices</div>
|
||||
<div class="glass rounded-xl p-3">Routing: A* / Dijkstra</div>
|
||||
<div class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-waveform"/>ASR: Whisper/Alternativen</div>
|
||||
<div class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-robot"/>LLM: GPT‑5‑Nano/4o‑Mini</div>
|
||||
<div class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-microphone"/>TTS: neural voices</div>
|
||||
<div class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-routes"/>Routing: A* / Dijkstra</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -125,9 +125,9 @@
|
||||
|
||||
<!-- LEARN PATH -->
|
||||
<section id="learn" class="py-16 md:py-24 bg-[#0b1020]">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<div class="container-outer">
|
||||
<div class="grid md:grid-cols-2 gap-8 items-center">
|
||||
<div>
|
||||
<div data-aos="fade-right">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold">ATC verstehen – Schritt für Schritt</h2>
|
||||
<p class="mt-3 text-white/80">Geführter Lernmodus: Hören, Nachsprechen, Feedback. Vom ersten „Ready to taxi“ bis zur komplexen STAR/Approach‑Freigabe.</p>
|
||||
<ol class="mt-5 space-y-3 text-white/80">
|
||||
@@ -138,11 +138,11 @@
|
||||
<li class="flex gap-3"><span class="chip">5</span><span><b>VATSIM</b>: Checklisten, Etiquette, Live‑Übungen.</span></li>
|
||||
</ol>
|
||||
<div class="mt-6 flex gap-3">
|
||||
<a href="#cta" class="btn btn-primary">Jetzt loslegen</a>
|
||||
<a href="#faq" class="btn btn-ghost">FAQ</a>
|
||||
<NuxtLink to="#cta" class="btn btn-primary">Jetzt loslegen</NuxtLink>
|
||||
<NuxtLink to="#faq" class="btn btn-ghost">FAQ</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-left">
|
||||
<ClientOnly>
|
||||
<video id="video" class="w-full rounded-xl" autoplay muted loop playsinline poster="https://images.unsplash.com/photo-1518306724291-1f5c9b4d2452?q=80&w=1600&auto=format&fit=crop">
|
||||
<source src="https://cdn.coverr.co/videos/coverr-airplane-taking-off-8255/1080p.mp4" type="video/mp4" />
|
||||
@@ -156,8 +156,8 @@
|
||||
|
||||
<!-- PRICING -->
|
||||
<section id="pricing" class="py-16 md:py-24 bg-gradient-to-b from-[#0b1020] to-[#0a0f1c]">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<div class="flex flex-col md:flex-row md:items-end md:justify-between gap-4">
|
||||
<div class="container-outer">
|
||||
<div class="flex flex-col md:flex-row md:items-end md:justify-between gap-4" data-aos="fade-up">
|
||||
<div class="max-w-2xl">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold">Preise</h2>
|
||||
<p class="mt-3 text-white/80">Open‑Source bleibt frei. Der gehostete Plan ist so günstig wie möglich kalkuliert. Umschalten:
|
||||
@@ -168,7 +168,7 @@
|
||||
|
||||
<div class="mt-8 grid md:grid-cols-3 gap-6">
|
||||
<!-- OSS -->
|
||||
<div class="card relative">
|
||||
<div class="card relative" data-aos="fade-up" data-aos-delay="0">
|
||||
<div class="absolute -top-3 right-4 chip">Community</div>
|
||||
<h3 class="text-xl font-semibold">Open‑Source (Self‑host)</h3>
|
||||
<p class="mt-2 text-white/80">Volle Kontrolle. Eigene Infrastruktur. API‑Keys selbst verwalten.</p>
|
||||
@@ -178,10 +178,10 @@
|
||||
<li>✔ Plugins & SDK</li>
|
||||
<li>✔ Community‑Support</li>
|
||||
</ul>
|
||||
<a href="#opensource" class="btn btn-ghost w-full mt-6">Repository ansehen</a>
|
||||
<NuxtLink to="#opensource" class="btn btn-ghost w-full mt-6">Repository ansehen</NuxtLink>
|
||||
</div>
|
||||
<!-- Hosted Basic -->
|
||||
<div class="card border-2 border-cyan-400/40 relative shadow-glow">
|
||||
<div class="card border-2 border-cyan-400/40 relative shadow-[0_0_40px_rgba(34,211,238,.25)]" data-aos="fade-up" data-aos-delay="100">
|
||||
<div class="absolute -top-3 right-4 chip bg-cyan-500/30 border-cyan-400/50">Empfohlen</div>
|
||||
<h3 class="text-xl font-semibold">Hosted – Basic</h3>
|
||||
<p class="mt-2 text-white/80">Alles fertig eingerichtet. Ideal zum Lernen & Üben.</p>
|
||||
@@ -191,11 +191,11 @@
|
||||
<li>✔ Lernpfad & Fortschritt</li>
|
||||
<li>✔ Updates & Cloud‑Scaling</li>
|
||||
</ul>
|
||||
<a href="#cta" class="btn btn-primary w-full mt-6">Kostenlos testen</a>
|
||||
<NuxtLink to="#cta" class="btn btn-primary w-full mt-6">Kostenlos testen</NuxtLink>
|
||||
<p class="mt-3 text-xs text-white/60">Preisziel: minimal + Betriebskosten. Änderungen möglich.</p>
|
||||
</div>
|
||||
<!-- Hosted Pro -->
|
||||
<div class="card relative">
|
||||
<div class="card relative" data-aos="fade-up" data-aos-delay="200">
|
||||
<div class="absolute -top-3 right-4 chip">Power‑User</div>
|
||||
<h3 class="text-xl font-semibold">Hosted – Pro</h3>
|
||||
<p class="mt-2 text-white/80">Mehr Kontingente, eigene Stimmen, API‑Zugriff.</p>
|
||||
@@ -205,7 +205,7 @@
|
||||
<li>✔ Team‑Seats</li>
|
||||
<li>✔ Priorisierter Support</li>
|
||||
</ul>
|
||||
<a href="#cta" class="btn btn-ghost w-full mt-6">Kontakt aufnehmen</a>
|
||||
<NuxtLink to="#cta" class="btn btn-ghost w-full mt-6">Kontakt aufnehmen</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -213,23 +213,23 @@
|
||||
|
||||
<!-- OPEN SOURCE -->
|
||||
<section id="opensource" class="py-16 md:py-24 bg-[#0a0f1c]">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<div class="container-outer">
|
||||
<div class="grid md:grid-cols-2 gap-8 items-center">
|
||||
<div>
|
||||
<div data-aos="fade-right">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold">Open‑Source, Community‑getrieben</h2>
|
||||
<p class="mt-3 text-white/80">Transparente Architektur, klare Roadmap, offene Issues. Baue eigene Voices, Integrationen und Workflows.</p>
|
||||
<ul class="mt-4 grid grid-cols-1 sm:grid-cols-2 gap-3 text-sm">
|
||||
<li class="glass rounded-xl p-3">MIT/Apache‑Lizenz (tbd)</li>
|
||||
<li class="glass rounded-xl p-3">Docker‑Compose / Helm</li>
|
||||
<li class="glass rounded-xl p-3">Plugin‑SDK (TS/JS)</li>
|
||||
<li class="glass rounded-xl p-3">CLI & REST API</li>
|
||||
<li class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-license"/>MIT/Apache‑Lizenz (tbd)</li>
|
||||
<li class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-docker"/>Docker‑Compose / Helm</li>
|
||||
<li class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-puzzle"/>Plugin‑SDK (TS/JS)</li>
|
||||
<li class="glass rounded-xl p-3 flex items-center gap-2"><v-icon icon="mdi-console"/>CLI & REST API</li>
|
||||
</ul>
|
||||
<div class="mt-6 flex gap-3">
|
||||
<a href="#cta" class="btn btn-primary">Mitmachen</a>
|
||||
<a href="#demo" class="btn btn-ghost">Demo</a>
|
||||
<NuxtLink to="#cta" class="btn btn-primary">Mitmachen</NuxtLink>
|
||||
<NuxtLink to="#demo" class="btn btn-ghost">Demo</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-left">
|
||||
<pre class="text-xs md:text-sm overflow-x-auto"><code>// Beispiel: REST‑Route für Taxi‑Routen
|
||||
POST /api/route/taxi
|
||||
{
|
||||
@@ -245,24 +245,24 @@ POST /api/route/taxi
|
||||
|
||||
<!-- HOW IT WORKS -->
|
||||
<section class="py-16 md:py-24 bg-[#0b1020]">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<div class="max-w-2xl mb-10">
|
||||
<div class="container-outer">
|
||||
<div class="max-w-2xl mb-10" data-aos="fade-up">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold">So funktioniert’s</h2>
|
||||
<p class="mt-3 text-white/80">Audio rein → Verständnis → Antwort raus. Designed für niedrige Latenz & klare Funk‑Disziplin.</p>
|
||||
</div>
|
||||
<div class="grid md:grid-cols-4 gap-4 md:gap-6">
|
||||
<div class="card"><h3 class="font-semibold">1 · ASR</h3><p class="mt-2 text-white/80">Streaming‑Speech‑to‑Text mit Funk‑Tuning.</p></div>
|
||||
<div class="card"><h3 class="font-semibold">2 · NLU</h3><p class="mt-2 text-white/80">LLM versteht Intention, Kontext, State.</p></div>
|
||||
<div class="card"><h3 class="font-semibold">3 · Logic</h3><p class="mt-2 text-white/80">Regeln, Flugdaten, Taxi‑Routing, Validierung.</p></div>
|
||||
<div class="card"><h3 class="font-semibold">4 · TTS</h3><p class="mt-2 text-white/80">Natürliches Voice‑Out mit korrekten Zahlen.</p></div>
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="0"><h3 class="font-semibold flex items-center gap-2"><v-icon icon="mdi-waveform"/>1 · ASR</h3><p class="mt-2 text-white/80">Streaming‑Speech‑to‑Text mit Funk‑Tuning.</p></div>
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="100"><h3 class="font-semibold flex items-center gap-2"><v-icon icon="mdi-brain"/>2 · NLU</h3><p class="mt-2 text-white/80">LLM versteht Intention, Kontext, State.</p></div>
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="200"><h3 class="font-semibold flex items-center gap-2"><v-icon icon="mdi-logic-gate-and"/>3 · Logic</h3><p class="mt-2 text-white/80">Regeln, Flugdaten, Taxi‑Routing, Validierung.</p></div>
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="300"><h3 class="font-semibold flex items-center gap-2"><v-icon icon="mdi-microphone"/>4 · TTS</h3><p class="mt-2 text-white/80">Natürliches Voice‑Out mit korrekten Zahlen.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section id="cta" class="py-16 md:py-24 bg-gradient-to-tr from-cyan-500/20 via-blue-500/10 to-transparent border-y border-white/10">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<div class="card md:flex md:items-center md:justify-between">
|
||||
<div class="container-outer">
|
||||
<div class="card md:flex md:items-center md:justify-between" data-aos="zoom-in">
|
||||
<div>
|
||||
<h3 class="text-2xl md:text-3xl font-semibold">Jetzt OpenSquawk ausprobieren</h3>
|
||||
<p class="mt-2 text-white/80">Starte kostenlos. Upgrade jederzeit. Keine Bindung.</p>
|
||||
@@ -272,31 +272,31 @@ POST /api/route/taxi
|
||||
<button class="btn btn-primary">Einladung anfordern</button>
|
||||
</form>
|
||||
</div>
|
||||
<p v-if="thanks" class="mt-3 text-sm text-green-300">Danke! Wir melden uns in Kürze mit deinem Zugang.</p>
|
||||
<p v-if="thanks" class="mt-3 text-sm text-green-300" data-aos="fade-in">Danke! Wir melden uns in Kürze mit deinem Zugang.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ -->
|
||||
<section id="faq" class="py-16 md:py-24 bg-[#0a0f1c]">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<div class="max-w-2xl mb-10">
|
||||
<div class="container-outer">
|
||||
<div class="max-w-2xl mb-10" data-aos="fade-up">
|
||||
<h2 class="text-3xl md:text-4xl font-semibold">FAQ</h2>
|
||||
<p class="mt-3 text-white/80">Kurz beantwortet.</p>
|
||||
</div>
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="0">
|
||||
<h3 class="font-semibold">Ist das für reale Luftfahrt?</h3>
|
||||
<p class="mt-2 text-white/80">Nein, OpenSquawk ist für Flugsimulatoren und Training. Nicht für den realen Flugfunk.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="100">
|
||||
<h3 class="font-semibold">Welche Simulatoren werden unterstützt?</h3>
|
||||
<p class="mt-2 text-white/80">MSFS, X‑Plane (weitere geplant). Integrationen per Plugin‑SDK.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="200">
|
||||
<h3 class="font-semibold">Kann ich selbst hosten?</h3>
|
||||
<p class="mt-2 text-white/80">Ja. Docker‑Compose/Helm bereitgestellt. Hosted‑Plan als bequeme Alternative.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card" data-aos="fade-up" data-aos-delay="300">
|
||||
<h3 class="font-semibold">Wie günstig ist „Hosted – Basic“?</h3>
|
||||
<p class="mt-2 text-white/80">Ziel: knapp über Betriebskosten. Pilotphase mit 4–5€ mtl. (vorläufig).</p>
|
||||
</div>
|
||||
@@ -305,35 +305,35 @@ POST /api/route/taxi
|
||||
</section>
|
||||
|
||||
<!-- FOOTER -->
|
||||
<footer class="py-12 bg-[#0b1020] border-t border-white/10">
|
||||
<div class="mx-auto max-w-[1200px] px-4">
|
||||
<footer class="py-12 bg-[#0b1020] border-t border-white/10" data-aos="fade-up">
|
||||
<div class="container-outer">
|
||||
<div class="grid md:grid-cols-4 gap-6">
|
||||
<div>
|
||||
<div class="flex items-center gap-2 font-semibold"><svg width="22" height="22" viewBox="0 0 24 24" fill="none" class="text-cyan-400"><path d="M12 3l8 4v10l-8 4-8-4V7l8-4z" stroke="currentColor"/></svg>OpenSquawk</div>
|
||||
<div class="flex items-center gap-2 font-semibold"><v-icon icon="mdi-radar" class="text-cyan-400"/>OpenSquawk</div>
|
||||
<p class="mt-3 text-white/70 text-sm">Open‑Source AI‑ATC für Simulatorpiloten. Lernpfad & günstiger Hosted‑Plan.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold mb-3">Produkt</h4>
|
||||
<ul class="space-y-2 text-white/70 text-sm">
|
||||
<li><a href="#features" class="hover:text-cyan-300">Features</a></li>
|
||||
<li><a href="#learn" class="hover:text-cyan-300">Lernpfad</a></li>
|
||||
<li><a href="#pricing" class="hover:text-cyan-300">Preise</a></li>
|
||||
<li><NuxtLink to="#features" class="hover:text-cyan-300">Features</NuxtLink></li>
|
||||
<li><NuxtLink to="#learn" class="hover:text-cyan-300">Lernpfad</NuxtLink></li>
|
||||
<li><NuxtLink to="#pricing" class="hover:text-cyan-300">Preise</NuxtLink></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold mb-3">Ressourcen</h4>
|
||||
<ul class="space-y-2 text-white/70 text-sm">
|
||||
<li><a href="#opensource" class="hover:text-cyan-300">Open‑Source</a></li>
|
||||
<li><a href="#demo" class="hover:text-cyan-300">Demo</a></li>
|
||||
<li><a href="#faq" class="hover:text-cyan-300">FAQ</a></li>
|
||||
<li><NuxtLink to="#opensource" class="hover:text-cyan-300">Open‑Source</NuxtLink></li>
|
||||
<li><NuxtLink to="#demo" class="hover:text-cyan-300">Demo</NuxtLink></li>
|
||||
<li><NuxtLink to="#faq" class="hover:text-cyan-300">FAQ</NuxtLink></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h4 class="font-semibold mb-3">Rechtliches</h4>
|
||||
<ul class="space-y-2 text-white/70 text-sm">
|
||||
<li><a href="#" class="hover:text-cyan-300">Impressum</a></li>
|
||||
<li><a href="#" class="hover:text-cyan-300">Datenschutz</a></li>
|
||||
<li><a href="#" class="hover:text-cyan-300">Nutzungshinweise</a></li>
|
||||
<li><NuxtLink to="#" class="hover:text-cyan-300">Impressum</NuxtLink></li>
|
||||
<li><NuxtLink to="#" class="hover:text-cyan-300">Datenschutz</NuxtLink></li>
|
||||
<li><NuxtLink to="#" class="hover:text-cyan-300">Nutzungshinweise</NuxtLink></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -344,7 +344,7 @@ POST /api/route/taxi
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useHead } from '#imports'
|
||||
|
||||
const yearly = ref(true)
|
||||
@@ -371,43 +371,33 @@ useHead({
|
||||
{ name: 'twitter:title', content: 'OpenSquawk – Open‑Source AI‑ATC' },
|
||||
{ name: 'twitter:description', content: 'Open, günstig, lernfreundlich. AI‑ATC mit Lernpfad & gehostetem Plan.' },
|
||||
{ name: 'twitter:image', content: 'https://opensquawk.example.com/cover.png' }
|
||||
],
|
||||
script: [
|
||||
{ src: 'https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js', defer: true },
|
||||
{ src: 'https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js', defer: true },
|
||||
{ type: 'application/ld+json', children: JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SoftwareApplication',
|
||||
name: 'OpenSquawk',
|
||||
applicationCategory: 'Simulation',
|
||||
offers: { '@type': 'AggregateOffer', lowPrice: '0', priceCurrency: 'EUR' },
|
||||
description: 'Open‑Source AI‑ATC für Flugsimulatoren mit Lernpfad & Hosted‑Plan.',
|
||||
operatingSystem: 'Windows, macOS'
|
||||
}) }
|
||||
]
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
const w: any = window as any
|
||||
const gsap = w.gsap
|
||||
const ScrollTrigger = w.ScrollTrigger
|
||||
if (!gsap || !ScrollTrigger) return
|
||||
gsap.registerPlugin(ScrollTrigger)
|
||||
gsap.from('header nav', { y: -30, opacity: 0, duration: .6, ease: 'power2'})
|
||||
gsap.from('.card', { opacity: 0, y: 20, duration: .6, stagger: .08, ease: 'power2', scrollTrigger: { trigger: '#features', start: 'top 80%' }})
|
||||
gsap.from('#pricing .card', { opacity: 0, y: 24, duration: .6, stagger: .08, ease: 'power2', scrollTrigger: { trigger: '#pricing', start: 'top 80%' }})
|
||||
gsap.from('#learn .card, #learn h2, #learn ol li', { opacity: 0, y: 18, duration: .6, stagger: .06, ease: 'power2', scrollTrigger: { trigger: '#learn', start: 'top 80%' }})
|
||||
gsap.from('#opensource .card', { opacity: 0, y: 18, duration: .6, stagger: .06, ease: 'power2', scrollTrigger: { trigger: '#opensource', start: 'top 80%' }})
|
||||
gsap.from('#cta .card', { opacity: 0, scale: .98, duration: .6, ease: 'power2', scrollTrigger: { trigger: '#cta', start: 'top 90%' }})
|
||||
// AOS: falls du kein Nuxt‑AOS Modul nutzt, hier Fallback
|
||||
onMounted(async () => {
|
||||
// @ts-ignore – optionaler Fallback
|
||||
if (!('AOS' in window)) {
|
||||
const [{ default: AOS }] = await Promise.all([
|
||||
import('aos'),
|
||||
import('aos/dist/aos.css')
|
||||
])
|
||||
AOS.init({ once: true, duration: 600, easing: 'ease-out' })
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container-outer { @apply mx-auto max-w-screen-xl px-4; }
|
||||
.gradient-hero {
|
||||
background: radial-gradient(1200px 600px at 10% -10%, rgba(6,182,212,.35), transparent),
|
||||
radial-gradient(900px 480px at 100% 10%, rgba(59,130,246,.25), transparent),
|
||||
linear-gradient(180deg, #0b1020 0%, #0b1020 60%, #0a0f1c 100%);
|
||||
}
|
||||
.glass { background: rgba(255,255,255,.06); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,.08); }
|
||||
.card { @apply glass rounded-2xl p-5 md:p-6; }
|
||||
.btn { @apply inline-flex items-center justify-center gap-2 rounded-xl px-5 py-3 font-medium transition; }
|
||||
.btn-primary { @apply bg-cyan-500 text-white hover:bg-cyan-400 shadow-[0_0_40px_rgba(34,211,238,.25)]; }
|
||||
.btn-ghost { @apply bg-white/5 text-white hover:bg-white/10; }
|
||||
.card { @apply glass rounded-2xl p-5 md:p-6; }
|
||||
.chip { @apply inline-flex items-center gap-2 rounded-full bg-white/10 border border-white/15 text-white px-3 py-1 text-xs; }
|
||||
.gradient-hero { background: radial-gradient(1200px 600px at 10% -10%, rgba(6,182,212,.35), transparent), radial-gradient(900px 480px at 100% 10%, rgba(59,130,246,.25), transparent), linear-gradient(180deg, #0b1020 0%, #0b1020 60%, #0a0f1c 100%); }
|
||||
</style>
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
devtools: { enabled: true },
|
||||
modules: ['vuetify-nuxt-module', '@nuxtjs/tailwindcss', 'nuxt-aos']
|
||||
})
|
||||
modules: ['vuetify-nuxt-module', '@nuxtjs/tailwindcss', 'nuxt-aos'],
|
||||
aos: { once: true, duration: 600, easing: 'ease-out' }
|
||||
})
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"dotenv": "^17.2.2",
|
||||
"nuxt": "^4.1.1",
|
||||
"nuxt-aos": "1.2.5",
|
||||
"openai": "^5.20.2",
|
||||
"openai": "^4.66.0",
|
||||
"vue": "^3.5.21",
|
||||
"vue-router": "^4.5.1",
|
||||
"vuetify": "3.9.0-beta.1",
|
||||
|
||||
@@ -1,35 +1,62 @@
|
||||
import { readMultipartFormData, createError } from "h3";
|
||||
import { openai, LLM_MODEL, TTS_MODEL, atcReplyPrompt } from "../../utils/openai";
|
||||
import { LLM_MODEL, TTS_MODEL, atcReplyPrompt, openai } from "../../utils/openai";
|
||||
import { applyRadioEffect } from "../../utils/radio";
|
||||
import { writeFile, rm } from "node:fs/promises";
|
||||
import { writeFile, rm, readFile } from "node:fs/promises";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { toFile } from "openai/uploads"; // ⟵ NEU
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const parts = await readMultipartFormData(event);
|
||||
const mode = parts?.find(p=>p.name==="mode")?.data?.toString("utf8") || "text";
|
||||
const audio = parts?.find(p=>p.type && p.data);
|
||||
if (!audio) throw createError({ statusCode:400, statusMessage:"No audio" });
|
||||
if (!parts) throw createError({ statusCode: 400, statusMessage: "No form-data" });
|
||||
|
||||
const file = new File([audio.data], audio.filename || "audio.webm", { type: audio.type || "audio/webm" });
|
||||
const mode = (parts.find(p => p.name === "mode")?.data?.toString("utf8") || "text").toLowerCase();
|
||||
const audio = parts.find(p => p.type && p.data);
|
||||
if (!audio) throw createError({ statusCode: 400, statusMessage: "No audio file" });
|
||||
|
||||
// ✅ saubere Datei-Erzeugung
|
||||
const file = await toFile(
|
||||
audio.data,
|
||||
audio.filename || "ptt.webm",
|
||||
{ type: audio.type || "audio/webm" }
|
||||
);
|
||||
|
||||
// 1) Transkribieren
|
||||
const tr = await openai.audio.transcriptions.create({ model: "whisper-1", file });
|
||||
const pilotText = tr.text.trim();
|
||||
const pilotText = tr.text?.trim() || "";
|
||||
if (!pilotText) throw createError({ statusCode: 400, statusMessage: "Empty transcription" });
|
||||
|
||||
const resp = await openai.responses.create({ model: LLM_MODEL, input: atcReplyPrompt(pilotText) });
|
||||
// 2) ATC-Antwort
|
||||
const resp = await openai.responses.create({
|
||||
model: LLM_MODEL,
|
||||
input: atcReplyPrompt(pilotText),
|
||||
});
|
||||
const replyText = resp.output_text?.trim() || "";
|
||||
if (!replyText) throw createError({ statusCode: 500, statusMessage: "LLM empty" });
|
||||
|
||||
// 3) Optional TTS + Funk
|
||||
if (mode === "tts") {
|
||||
const clean = join(tmpdir(), `tts-${randomUUID()}.wav`);
|
||||
const radio = join(tmpdir(), `radio-${randomUUID()}.wav`);
|
||||
const tts = await openai.audio.speech.create({ model: TTS_MODEL, voice: "alloy", format: "wav", input: replyText });
|
||||
|
||||
const tts = await openai.audio.speech.create({
|
||||
model: TTS_MODEL,
|
||||
voice: "alloy",
|
||||
format: "wav",
|
||||
input: replyText,
|
||||
});
|
||||
|
||||
await writeFile(clean, Buffer.from(await tts.arrayBuffer()));
|
||||
await applyRadioEffect(clean, radio);
|
||||
const data = await import("node:fs/promises").then(fs => fs.readFile(radio));
|
||||
await rm(clean).catch(()=>{});
|
||||
|
||||
const data = await readFile(radio);
|
||||
const b64 = Buffer.from(data).toString("base64");
|
||||
await rm(radio).catch(()=>{});
|
||||
return { pilotText, replyText, audio:{ mime:"audio/wav", base64:b64 } };
|
||||
rm(clean).catch(() => {});
|
||||
rm(radio).catch(() => {});
|
||||
|
||||
return { pilotText, replyText, audio: { mime: "audio/wav", base64: b64 } };
|
||||
}
|
||||
|
||||
return { pilotText, replyText };
|
||||
});
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
import { readMultipartFormData, createError } from "h3";
|
||||
import { openai } from "../../utils/openai";
|
||||
import { toFile } from "openai/uploads"; // ⟵ NEU
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const parts = await readMultipartFormData(event);
|
||||
const audio = parts?.find(p=>p.type && p.data);
|
||||
if (!audio) throw createError({ statusCode:400, statusMessage:"No audio" });
|
||||
const file = new File([audio.data], audio.filename || "audio.webm", { type: audio.type || "audio/webm" });
|
||||
const tr = await openai.audio.transcriptions.create({ model: "whisper-1", file });
|
||||
if (!parts) throw createError({ statusCode: 400, statusMessage: "No form-data" });
|
||||
|
||||
const audio = parts.find(p => p.type && p.data);
|
||||
if (!audio) throw createError({ statusCode: 400, statusMessage: "No audio file" });
|
||||
|
||||
const file = await toFile(
|
||||
audio.data, // Buffer
|
||||
audio.filename || "ptt.webm", // ⟵ mit Endung
|
||||
{ type: audio.type || "audio/webm" } // ⟵ korrekter MIME
|
||||
);
|
||||
|
||||
const tr = await openai.audio.transcriptions.create({
|
||||
model: "whisper-1",
|
||||
file
|
||||
});
|
||||
|
||||
return { text: tr.text };
|
||||
});
|
||||
|
||||
163
yarn.lock
163
yarn.lock
@@ -2059,6 +2059,34 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node-fetch@npm:^2.6.4":
|
||||
version: 2.6.13
|
||||
resolution: "@types/node-fetch@npm:2.6.13"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
form-data: "npm:^4.0.4"
|
||||
checksum: 10c0/6313c89f62c50bd0513a6839cdff0a06727ac5495ccbb2eeda51bb2bbbc4f3c0a76c0393a491b7610af703d3d2deb6cf60e37e59c81ceeca803ffde745dbf309
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:*":
|
||||
version: 24.4.0
|
||||
resolution: "@types/node@npm:24.4.0"
|
||||
dependencies:
|
||||
undici-types: "npm:~7.11.0"
|
||||
checksum: 10c0/3aefa4c6b006b3478f2d28a48d830ab7350ce24efdaf352011418e3ee17ed7683ca9c0a1840e770685ce78f413344badafa91e034be02488efe2eb6b612bd542
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^18.11.18":
|
||||
version: 18.19.124
|
||||
resolution: "@types/node@npm:18.19.124"
|
||||
dependencies:
|
||||
undici-types: "npm:~5.26.4"
|
||||
checksum: 10c0/a1b1aa2d21a0b0dec473b9b15e048a25f86cd26f7fc1b9036b43b838ee50b33534518c503f12c9a86be4cebb0f957fd3583fee9c78372ece973a1081c9fc7966
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/parse-path@npm:^7.0.0":
|
||||
version: 7.0.3
|
||||
resolution: "@types/parse-path@npm:7.0.3"
|
||||
@@ -2454,6 +2482,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"agentkeepalive@npm:^4.2.1":
|
||||
version: 4.6.0
|
||||
resolution: "agentkeepalive@npm:4.6.0"
|
||||
dependencies:
|
||||
humanize-ms: "npm:^1.2.1"
|
||||
checksum: 10c0/235c182432f75046835b05f239708107138a40103deee23b6a08caee5136873709155753b394ec212e49e60e94a378189562cb01347765515cff61b692c69187
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"alien-signals@npm:^2.0.5":
|
||||
version: 2.0.7
|
||||
resolution: "alien-signals@npm:2.0.7"
|
||||
@@ -2597,6 +2634,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"asynckit@npm:^0.4.0":
|
||||
version: 0.4.0
|
||||
resolution: "asynckit@npm:0.4.0"
|
||||
checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"at-least-node@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "at-least-node@npm:1.0.0"
|
||||
@@ -3009,6 +3053,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"combined-stream@npm:^1.0.8":
|
||||
version: 1.0.8
|
||||
resolution: "combined-stream@npm:1.0.8"
|
||||
dependencies:
|
||||
delayed-stream: "npm:~1.0.0"
|
||||
checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"commander@npm:^11.1.0":
|
||||
version: 11.1.0
|
||||
resolution: "commander@npm:11.1.0"
|
||||
@@ -3450,6 +3503,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"delayed-stream@npm:~1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "delayed-stream@npm:1.0.0"
|
||||
checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"delegates@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "delegates@npm:1.0.0"
|
||||
@@ -3738,6 +3798,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"es-set-tostringtag@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "es-set-tostringtag@npm:2.1.0"
|
||||
dependencies:
|
||||
es-errors: "npm:^1.3.0"
|
||||
get-intrinsic: "npm:^1.2.6"
|
||||
has-tostringtag: "npm:^1.0.2"
|
||||
hasown: "npm:^2.0.2"
|
||||
checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"esbuild@npm:^0.20.2 || ^0.21.0 || ^0.22.0 || ^0.23.0":
|
||||
version: 0.23.1
|
||||
resolution: "esbuild@npm:0.23.1"
|
||||
@@ -4090,6 +4162,36 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"form-data-encoder@npm:1.7.2":
|
||||
version: 1.7.2
|
||||
resolution: "form-data-encoder@npm:1.7.2"
|
||||
checksum: 10c0/56553768037b6d55d9de524f97fe70555f0e415e781cb56fc457a68263de3d40fadea2304d4beef2d40b1a851269bd7854e42c362107071892cb5238debe9464
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"form-data@npm:^4.0.4":
|
||||
version: 4.0.4
|
||||
resolution: "form-data@npm:4.0.4"
|
||||
dependencies:
|
||||
asynckit: "npm:^0.4.0"
|
||||
combined-stream: "npm:^1.0.8"
|
||||
es-set-tostringtag: "npm:^2.1.0"
|
||||
hasown: "npm:^2.0.2"
|
||||
mime-types: "npm:^2.1.12"
|
||||
checksum: 10c0/373525a9a034b9d57073e55eab79e501a714ffac02e7a9b01be1c820780652b16e4101819785e1e18f8d98f0aee866cc654d660a435c378e16a72f2e7cac9695
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"formdata-node@npm:^4.3.2":
|
||||
version: 4.4.1
|
||||
resolution: "formdata-node@npm:4.4.1"
|
||||
dependencies:
|
||||
node-domexception: "npm:1.0.0"
|
||||
web-streams-polyfill: "npm:4.0.0-beta.3"
|
||||
checksum: 10c0/74151e7b228ffb33b565cec69182694ad07cc3fdd9126a8240468bb70a8ba66e97e097072b60bcb08729b24c7ce3fd3e0bd7f1f80df6f9f662b9656786e76f6a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fraction.js@npm:^4.3.7":
|
||||
version: 4.3.7
|
||||
resolution: "fraction.js@npm:4.3.7"
|
||||
@@ -4186,7 +4288,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-intrinsic@npm:^1.3.0":
|
||||
"get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "get-intrinsic@npm:1.3.0"
|
||||
dependencies:
|
||||
@@ -4541,6 +4643,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"humanize-ms@npm:^1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "humanize-ms@npm:1.2.1"
|
||||
dependencies:
|
||||
ms: "npm:^2.0.0"
|
||||
checksum: 10c0/f34a2c20161d02303c2807badec2f3b49cbfbbb409abd4f95a07377ae01cfe6b59e3d15ac609cffcd8f2521f0eb37b7e1091acf65da99aa2a4f1ad63c21e7e7a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"iconv-lite@npm:^0.6.2":
|
||||
version: 0.6.3
|
||||
resolution: "iconv-lite@npm:0.6.3"
|
||||
@@ -5362,7 +5473,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mime-types@npm:^2.1.18, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34":
|
||||
"mime-types@npm:^2.1.12, mime-types@npm:^2.1.18, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34":
|
||||
version: 2.1.35
|
||||
resolution: "mime-types@npm:2.1.35"
|
||||
dependencies:
|
||||
@@ -5550,7 +5661,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ms@npm:^2.1.1, ms@npm:^2.1.3":
|
||||
"ms@npm:^2.0.0, ms@npm:^2.1.1, ms@npm:^2.1.3":
|
||||
version: 2.1.3
|
||||
resolution: "ms@npm:2.1.3"
|
||||
checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48
|
||||
@@ -5716,6 +5827,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-domexception@npm:1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "node-domexception@npm:1.0.0"
|
||||
checksum: 10c0/5e5d63cda29856402df9472335af4bb13875e1927ad3be861dc5ebde38917aecbf9ae337923777af52a48c426b70148815e890a5d72760f1b4d758cc671b1a2b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"node-fetch-native@npm:^1.6.4, node-fetch-native@npm:^1.6.6, node-fetch-native@npm:^1.6.7":
|
||||
version: 1.6.7
|
||||
resolution: "node-fetch-native@npm:1.6.7"
|
||||
@@ -6056,9 +6174,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"openai@npm:^5.20.2":
|
||||
version: 5.20.2
|
||||
resolution: "openai@npm:5.20.2"
|
||||
"openai@npm:^4.66.0":
|
||||
version: 4.104.0
|
||||
resolution: "openai@npm:4.104.0"
|
||||
dependencies:
|
||||
"@types/node": "npm:^18.11.18"
|
||||
"@types/node-fetch": "npm:^2.6.4"
|
||||
abort-controller: "npm:^3.0.0"
|
||||
agentkeepalive: "npm:^4.2.1"
|
||||
form-data-encoder: "npm:1.7.2"
|
||||
formdata-node: "npm:^4.3.2"
|
||||
node-fetch: "npm:^2.6.7"
|
||||
peerDependencies:
|
||||
ws: ^8.18.0
|
||||
zod: ^3.23.8
|
||||
@@ -6069,7 +6195,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
openai: bin/cli
|
||||
checksum: 10c0/9a8004d64feadfeba0cc15ccfdce6d1863be06dbaef7c1137aea606a4825657e77803cb106ccaf2913303ee1c1b55bc599fde08afb5158726e69011dfb38f6e3
|
||||
checksum: 10c0/c4f2e837684ed96b8cec58c65a584646d667c69918f29052775e2e8c05ff5c860d8b58214a7770bc6895ca8602480420c1db6a5392dd250179eb0b91c2b19a2f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6081,7 +6207,7 @@ __metadata:
|
||||
dotenv: "npm:^17.2.2"
|
||||
nuxt: "npm:^4.1.1"
|
||||
nuxt-aos: "npm:1.2.5"
|
||||
openai: "npm:^5.20.2"
|
||||
openai: "npm:^4.66.0"
|
||||
vue: "npm:^3.5.21"
|
||||
vue-router: "npm:^4.5.1"
|
||||
vuetify: "npm:3.9.0-beta.1"
|
||||
@@ -8048,6 +8174,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici-types@npm:~5.26.4":
|
||||
version: 5.26.5
|
||||
resolution: "undici-types@npm:5.26.5"
|
||||
checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"undici-types@npm:~7.11.0":
|
||||
version: 7.11.0
|
||||
resolution: "undici-types@npm:7.11.0"
|
||||
checksum: 10c0/24ff69baeaebc7d09f4dae68564df850b4ff561810148ff6c37d3fc64dd1460c55e59e604420495e73b1fb48594a1c98e69f6732086a24e01b88f2d926378af1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"unenv@npm:^2.0.0-rc.21":
|
||||
version: 2.0.0-rc.21
|
||||
resolution: "unenv@npm:2.0.0-rc.21"
|
||||
@@ -8645,6 +8785,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"web-streams-polyfill@npm:4.0.0-beta.3":
|
||||
version: 4.0.0-beta.3
|
||||
resolution: "web-streams-polyfill@npm:4.0.0-beta.3"
|
||||
checksum: 10c0/a9596779db2766990117ed3a158e0b0e9f69b887a6d6ba0779940259e95f99dc3922e534acc3e5a117b5f5905300f527d6fbf8a9f0957faf1d8e585ce3452e8e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"webidl-conversions@npm:^3.0.0":
|
||||
version: 3.0.1
|
||||
resolution: "webidl-conversions@npm:3.0.1"
|
||||
|
||||
Reference in New Issue
Block a user