mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-06 01:06:28 +08:00
Fix remaining German comment
This commit is contained in:
@@ -16,10 +16,10 @@ export const LLM_MODEL = llmModel;
|
||||
export const TTS_MODEL = ttsModel;
|
||||
|
||||
/* =========================
|
||||
LLM PROMPTS (überarbeitet)
|
||||
LLM PROMPTS (refined)
|
||||
=========================
|
||||
Ziel: LLM liefert kompakte, maschinenfreundliche ICAO-Zeile, die unser Normalizer→TTS perfekt erweitert.
|
||||
WICHTIG: Zahlen/Marker exakt im unten definierten Output-Format, keine ausgeschriebenen Wörter.
|
||||
Goal: the LLM returns a compact, machine-friendly ICAO line that our normalizer → TTS can expand perfectly.
|
||||
IMPORTANT: Use the exact output format defined below; do not spell out numbers.
|
||||
*/
|
||||
|
||||
export const ATC_OUTPUT_SPEC = `
|
||||
@@ -43,9 +43,9 @@ OUTPUT RULES (STRICT):
|
||||
- Use standard order for the phase (e.g., taxi: destination RWY first, then route, then hold short).
|
||||
`.trim();
|
||||
|
||||
/** System-Prompt: legt Rolle/Regeln fest */
|
||||
/** System prompt: defines the role and rules */
|
||||
export function atcSystemPrompt(opts?: {
|
||||
regionHint?: "EUR" | "US" | "INTL"; // nur als Soft-Hinweis, default INTL
|
||||
regionHint?: "EUR" | "US" | "INTL"; // soft hint only, defaults to INTL
|
||||
}) {
|
||||
const region = opts?.regionHint ?? "INTL";
|
||||
return [
|
||||
@@ -56,7 +56,7 @@ export function atcSystemPrompt(opts?: {
|
||||
].join("\n\n");
|
||||
}
|
||||
|
||||
/** Seed-ATC ohne Pilot-Input (rückwärtskompatible Signatur, aber reicherer Prompt) */
|
||||
/** Seed ATC without pilot input (backward-compatible signature, but richer prompt) */
|
||||
export function atcSeedPrompt(s: {
|
||||
airport: string; // e.g., "EDDF"
|
||||
aircraft: string; // e.g., "A320"
|
||||
@@ -66,11 +66,11 @@ export function atcSeedPrompt(s: {
|
||||
sid?: string; // e.g., "MARUN 7F"
|
||||
squawk?: string; // "4723"
|
||||
freq?: string; // "121.800"
|
||||
runway?: string; // "25R" (optional: falls bekannt)
|
||||
runway?: string; // "25R" (optional if known)
|
||||
phase?: "clearance" | "taxi" | "lineup" | "departure" | "handoff" | "approach" | "landing";
|
||||
notes?: string; // z.B. "TWY N closed between N2–N4"
|
||||
notes?: string; // e.g. "TWY N closed between N2–N4"
|
||||
}) {
|
||||
// Default-Phase: clearance
|
||||
// Default phase: clearance
|
||||
const phase = s.phase || "clearance";
|
||||
const ctx = [
|
||||
`Airport ${s.airport}`,
|
||||
@@ -106,12 +106,12 @@ export function atcSeedPrompt(s: {
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
/** Pilot→ATC (rückwärtskompatibler Name, aber mit robustem Rahmen) */
|
||||
/** Pilot → ATC (same legacy name, but with a sturdier framework) */
|
||||
export function atcReplyPrompt(userText: string, state?: {
|
||||
airport?: string; runway?: string; sid?: string; dep?: string;
|
||||
lastSquawk?: string; lastFreq?: string; lastQNH?: string;
|
||||
phase?: "clearance" | "taxi" | "lineup" | "departure" | "handoff" | "approach" | "landing";
|
||||
constraints?: string; // z.B. "TWY N closed", "no intersection deps on 25C"
|
||||
constraints?: string; // e.g. "TWY N closed", "no intersection deps on 25C"
|
||||
}) {
|
||||
const ctx = [
|
||||
state?.airport ? `Airport ${state.airport}` : null,
|
||||
@@ -137,10 +137,10 @@ export function atcReplyPrompt(userText: string, state?: {
|
||||
}
|
||||
|
||||
/* =========================
|
||||
Normalizer → TTS (wie zuvor)
|
||||
Normalizer → TTS (unchanged)
|
||||
========================= */
|
||||
|
||||
// Airline-Telephony (erweiterbar)
|
||||
// Airline telephony (extensible)
|
||||
export const CALLSIGN_MAP: Record<string,string> = {
|
||||
DLH: "Lufthansa",
|
||||
EWG: "Eurowings",
|
||||
@@ -185,16 +185,16 @@ export async function speakATC(text: string, filePath = "atc.mp3") {
|
||||
}
|
||||
|
||||
/* =========================
|
||||
Beispiele
|
||||
Examples
|
||||
=========================
|
||||
|
||||
— Seed (Clearance):
|
||||
— Seed (clearance):
|
||||
const sys = atcSystemPrompt();
|
||||
const usr = atcSeedPrompt({
|
||||
airport: "EDDF", aircraft: "A320", type: "IFR", stand: "V155",
|
||||
dep: "EHAM", sid: "MARUN 7F", runway: "25R", freq: "121.800"
|
||||
});
|
||||
// → LLM antwortet z.B.:
|
||||
// → The LLM might respond:
|
||||
// "DLH359, cleared to EHAM via MARUN 7F, initial 5000 ft, squawk 4723. QNH 1013."
|
||||
|
||||
— Taxi:
|
||||
@@ -205,12 +205,12 @@ const usrTaxi = atcSeedPrompt({
|
||||
});
|
||||
// → "DLH359, taxi to RWY 25R via A3 A N2, hold short."
|
||||
|
||||
— Pilot→ATC:
|
||||
— Pilot → ATC:
|
||||
const usrReply = atcReplyPrompt(
|
||||
"DLH359 ready for departure RWY 25R",
|
||||
{ airport: "EDDF", runway: "25R", phase: "lineup", lastFreq: "121.800" }
|
||||
);
|
||||
// → "DLH359, line up and wait RWY 25R."
|
||||
|
||||
Nach dem LLM-Output: `speakATC(llmText)` ruft Normalizer→TTS.
|
||||
After receiving the LLM output, call `speakATC(llmText)` to trigger normalizer → TTS.
|
||||
*/
|
||||
|
||||
@@ -97,7 +97,7 @@ export async function sendMail(options: MailOptions) {
|
||||
|
||||
const success = await sendViaSmtp(payload)
|
||||
if (!success) {
|
||||
console.info(`[mail:fallback] ${options.subject}\nEmpfänger: ${options.to}\n${options.text}`)
|
||||
console.info(`[mail:fallback] ${options.subject}\nRecipient: ${options.to}\n${options.text}`)
|
||||
}
|
||||
return success
|
||||
}
|
||||
@@ -169,7 +169,7 @@ export async function sendAdminNotification(notification: string | AdminNotifica
|
||||
|
||||
const success = await sendMail(mailOptions)
|
||||
if (!success) {
|
||||
console.info(`[notify:fallback] ${mailOptions.subject}\nEmpfänger: ${to}\n${mailOptions.text}`)
|
||||
console.info(`[notify:fallback] ${mailOptions.subject}\nRecipient: ${to}\n${mailOptions.text}`)
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ function ensureOpenAI(): OpenAI {
|
||||
if (!openaiClient) {
|
||||
const { openaiKey, openaiProject, llmModel } = getServerRuntimeConfig()
|
||||
if (!openaiKey) {
|
||||
throw new Error('OPENAI_API_KEY fehlt. Bitte den Schlüssel setzen, bevor KI-Funktionen genutzt werden.')
|
||||
throw new Error('OPENAI_API_KEY is missing. Please set the key before using AI features.')
|
||||
}
|
||||
const clientOptions: ConstructorParameters<typeof OpenAI>[0] = { apiKey: openaiKey }
|
||||
if (openaiProject) {
|
||||
@@ -246,9 +246,9 @@ function extractTemplateVariables(text?: string): string[] {
|
||||
return matches.map(match => match.slice(1, -1)) // Remove { }
|
||||
}
|
||||
|
||||
// Optimierte aber ausreichende Eingabe für gute Entscheidungen
|
||||
// Optimized yet sufficient input for reliable decisions
|
||||
function optimizeInputForLLM(input: LLMDecisionInput) {
|
||||
// Sammle alle verfügbaren Variablen aus dem Decision Tree
|
||||
// Collect all available variables from the decision tree
|
||||
const availableVariables = [
|
||||
'callsign', 'dest', 'dep', 'runway', 'squawk', 'sid', 'transition',
|
||||
'initial_altitude_ft', 'climb_altitude_ft', 'cruise_flight_level',
|
||||
@@ -308,7 +308,7 @@ function optimizeInputForLLM(input: LLMDecisionInput) {
|
||||
current_role: input.state.role,
|
||||
state_summary: stateSummary,
|
||||
candidates: candidates,
|
||||
available_variables: availableVariables, // Alle verfügbaren Variablen
|
||||
available_variables: availableVariables, // All available variables
|
||||
candidate_variables: Array.from(candidateVars), // Variablen die Candidates verwenden
|
||||
pilot_utterance: input.pilot_utterance,
|
||||
decision_hints: {
|
||||
@@ -318,7 +318,7 @@ function optimizeInputForLLM(input: LLMDecisionInput) {
|
||||
has_interrupt_candidate: input.candidates.some(c => c.id.startsWith('INT_')),
|
||||
readback_check_state: Boolean(readbackKeys.length)
|
||||
},
|
||||
// Nur aktueller Context ohne Werte (für Token-Sparen)
|
||||
// Current context only without values (to save tokens)
|
||||
context: {
|
||||
callsign: input.variables.callsign,
|
||||
current_unit: input.flags.current_unit,
|
||||
@@ -459,7 +459,7 @@ export async function routeDecision(input: LLMDecisionInput): Promise<LLMDecisio
|
||||
}
|
||||
}
|
||||
|
||||
// Sofortige Erkennung ohne LLM für häufige Cases
|
||||
// Instant detection without the LLM for common cases
|
||||
if (pilotText.includes('radio check') || pilotText.includes('signal test') ||
|
||||
(pilotText.includes('read') && (pilotText.includes('check') || pilotText.includes('you')))) {
|
||||
return finalize({
|
||||
@@ -479,17 +479,17 @@ export async function routeDecision(input: LLMDecisionInput): Promise<LLMDecisio
|
||||
|
||||
const optimizedInput = optimizeInputForLLM(input)
|
||||
|
||||
// Prüfe ob nächste States ATC-Responses brauchen
|
||||
// Check whether the next states require ATC responses
|
||||
const atcCandidates = input.candidates.filter(c =>
|
||||
c.state.role === 'atc' || c.state.say_tpl || c.id.startsWith('INT_')
|
||||
)
|
||||
|
||||
// Wenn keine ATC-States verfügbar, einfache Transition ohne Response
|
||||
// If no ATC states are available, perform a simple transition without a response
|
||||
if (atcCandidates.length === 0 && input.candidates.length > 0) {
|
||||
return finalize({ next_state: input.candidates[0].id })
|
||||
}
|
||||
|
||||
// Kompakter aber informativer Prompt - mit Variable-Info für intelligente Responses
|
||||
// Compact yet informative prompt — includes variable info for intelligent responses
|
||||
const system = [
|
||||
'You are an ATC state router. Return strict JSON.',
|
||||
'Keys: next_state, controller_say_tpl (optional), off_schema (optional), intent (optional).',
|
||||
@@ -593,7 +593,7 @@ export async function routeDecision(input: LLMDecisionInput): Promise<LLMDecisio
|
||||
})
|
||||
}
|
||||
|
||||
// Pilot readback oder acknowledgment → keine ATC response nötig
|
||||
// Pilot readback or acknowledgment → no ATC response required
|
||||
if (pilotText.includes('wilco') || pilotText.includes('roger') ||
|
||||
pilotText.includes('cleared') || pilotText.includes('copied')) {
|
||||
fallbackInfo.selected = 'acknowledge'
|
||||
|
||||
@@ -58,7 +58,7 @@ export function getServerRuntimeConfig(): ServerRuntimeConfig {
|
||||
|
||||
const openaiKey = String(runtimeConfig.openaiKey || '').trim()
|
||||
if (!openaiKey && !warnedMissingOpenAIKey) {
|
||||
console.warn('[OpenSquawk] OPENAI_API_KEY fehlt. Einige KI-Funktionen stehen ohne Schlüssel nicht zur Verfügung.')
|
||||
console.warn('[OpenSquawk] OPENAI_API_KEY is missing. Some AI features are unavailable without a key.')
|
||||
warnedMissingOpenAIKey = true
|
||||
}
|
||||
|
||||
|
||||
@@ -12,16 +12,16 @@ export interface PasswordValidationResult {
|
||||
export function validatePasswordStrength(password: string): PasswordValidationResult {
|
||||
const trimmed = password.trim()
|
||||
if (trimmed.length < 10) {
|
||||
return { valid: false, message: 'Passwort muss mindestens 10 Zeichen lang sein.' }
|
||||
return { valid: false, message: 'Password must be at least 10 characters long.' }
|
||||
}
|
||||
if (/\s/.test(trimmed)) {
|
||||
return { valid: false, message: 'Passwort darf keine Leerzeichen enthalten.' }
|
||||
return { valid: false, message: 'Password cannot contain spaces.' }
|
||||
}
|
||||
if (!/[A-Za-zÄÖÜäöüß]/.test(trimmed) || !/[0-9]/.test(trimmed)) {
|
||||
return { valid: false, message: 'Bitte Buchstaben und Zahlen kombinieren.' }
|
||||
return { valid: false, message: 'Please use both letters and numbers.' }
|
||||
}
|
||||
if (!/[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(trimmed)) {
|
||||
return { valid: false, message: 'Mindestens ein Sonderzeichen erhöht die Sicherheit.' }
|
||||
return { valid: false, message: 'Include at least one special character for better security.' }
|
||||
}
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user