diff --git a/app/pages/classroom.vue b/app/pages/classroom.vue
index 8e5800d..645be1a 100644
--- a/app/pages/classroom.vue
+++ b/app/pages/classroom.vue
@@ -1328,11 +1328,11 @@
mdi-alert-circle-outline
-
Sprachserver aktuell nicht erreichbar
-
Server-TTS ist gerade überlastet
+
Voice service is temporarily unavailable
+
Online voice is busy right now
- Unser Sprachserver ist aktuell wegen zu hoher Auslastung nicht erreichbar. Es kann ein bisschen dauern,
- bis dieses Feature wieder verfügbar ist. Du kannst solange Browser TTS nutzen.
+ Our online voice server is currently under heavy load and cannot be reached. It may take a little while
+ until this feature is available again. You can use the voice built into your browser in the meantime.
@@ -1343,14 +1343,42 @@
@click="enableBrowserTtsFromWarning"
>
mdi-volume-high
- Browser TTS nutzen
+ Use browser voice
- Verstanden
+ Got it
- Dein Browser meldet aktuell keine Web-Speech-Unterstützung.
+ Your browser does not report built-in voice support right now.
+
+
+
+
+
+
+
+ mdi-cloud-check-outline
+
+
+
Better voice available
+
Use the online voice?
+
+ You are currently using the voice built into your browser. The online voice service is available and usually
+ sounds clearer and more natural for ATC practice.
+
+
+
+
+ mdi-cloud-outline
+ Use online voice
+
+
+ Keep browser voice
+
+
+
+ You can change this later in Settings under Browser TTS.
@@ -2744,6 +2772,7 @@ const referenceOpen = ref(false)
const toast = ref({show: false, text: ''})
const showSettings = ref(false)
const showSpeechServerWarning = ref(false)
+const showOnlineTtsSuggestion = ref(false)
const api = useApi()
const isClient = typeof window !== 'undefined'
const auth = useAuthStore()
@@ -2812,7 +2841,9 @@ function persistLocalAtcSettings(config: LearnConfig) {
async function checkSpeechServerAvailability() {
try {
const health = await api.get('/api/classroom/speech-server-health')
+ const hasOnlineTts = Boolean(health.configured && health.reachable)
showSpeechServerWarning.value = Boolean(health.configured && !health.reachable)
+ showOnlineTtsSuggestion.value = Boolean(hasOnlineTts && cfg.value.tts)
} catch (error) {
console.error('Failed to check speech server availability', error)
}
@@ -2823,6 +2854,11 @@ function enableBrowserTtsFromWarning() {
showSpeechServerWarning.value = false
}
+function enableOnlineTtsFromSuggestion() {
+ cfg.value.tts = false
+ showOnlineTtsSuggestion.value = false
+}
+
function loadLocalAtcSettings(): LearnConfigPatch | null {
if (!isClient) return null
const key = getAtcSettingsStorageKey()
@@ -6780,6 +6816,13 @@ onMounted(() => {
box-shadow: 0 18px 36px rgba(245, 158, 11, .16);
}
+.speech-server-icon.is-online {
+ color: var(--accent);
+ background: color-mix(in srgb, var(--accent) 18%, transparent);
+ border-color: color-mix(in srgb, var(--accent) 36%, transparent);
+ box-shadow: 0 18px 36px rgba(34, 211, 238, .16);
+}
+
.speech-server-copy {
margin-top: 10px;
line-height: 1.6;
@@ -6796,6 +6839,18 @@ onMounted(() => {
justify-content: center;
}
+.speech-server-actions .btn.primary:not([disabled]):hover {
+ color: #051217;
+ background: linear-gradient(
+ 180deg,
+ color-mix(in srgb, var(--accent) 98%, white 10%),
+ color-mix(in srgb, var(--accent2) 78%, transparent)
+ );
+ border-color: color-mix(in srgb, var(--accent) 70%, transparent);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .22),
+ 0 16px 30px color-mix(in srgb, var(--accent) 40%, transparent);
+}
+
.sr-only {
position: absolute;
width: 1px;