diff --git a/.env.development b/.env.development index 8c20778dd..b603dbc2b 100644 --- a/.env.development +++ b/.env.development @@ -222,6 +222,11 @@ CONTACTS_GOOGLE_REDIRECT_URI=http://localhost:5184/import?tab=google CALENDAR_BACKEND_PORT=3014 CALENDAR_DATABASE_URL=postgresql://manacore:devpassword@localhost:5432/calendar +# Speech-to-Text Service (mana-stt) +# Production: https://stt-api.mana.how +# Local dev: http://localhost:3020 +STT_URL=https://stt-api.mana.how + # ============================================ # STORAGE PROJECT (Cloud Drive) # ============================================ diff --git a/apps/calendar/apps/web/src/hooks.server.ts b/apps/calendar/apps/web/src/hooks.server.ts index 6d7a5089d..5215d05b8 100644 --- a/apps/calendar/apps/web/src/hooks.server.ts +++ b/apps/calendar/apps/web/src/hooks.server.ts @@ -11,6 +11,7 @@ const PUBLIC_MANA_CORE_AUTH_URL_CLIENT = process.env.PUBLIC_MANA_CORE_AUTH_URL_CLIENT || process.env.PUBLIC_MANA_CORE_AUTH_URL || ''; const PUBLIC_BACKEND_URL_CLIENT = process.env.PUBLIC_BACKEND_URL_CLIENT || process.env.PUBLIC_BACKEND_URL || ''; +const PUBLIC_STT_URL = process.env.PUBLIC_STT_URL || 'https://stt-api.mana.how'; export const handle: Handle = async ({ event, resolve }) => { return resolve(event, { @@ -20,6 +21,7 @@ export const handle: Handle = async ({ event, resolve }) => { const envScript = ``; return html.replace('', `${envScript}`); }, diff --git a/apps/calendar/apps/web/src/lib/components/settings/SettingsModal.svelte b/apps/calendar/apps/web/src/lib/components/settings/SettingsModal.svelte index 00f234422..4bd9dd614 100644 --- a/apps/calendar/apps/web/src/lib/components/settings/SettingsModal.svelte +++ b/apps/calendar/apps/web/src/lib/components/settings/SettingsModal.svelte @@ -4,7 +4,7 @@ import { authStore } from '$lib/stores/auth.svelte'; import { userSettings } from '$lib/stores/user-settings.svelte'; import { settingsStore } from '$lib/stores/settings.svelte'; - import type { TimeFormat, AllDayDisplayMode } from '$lib/stores/settings.svelte'; + import type { TimeFormat, AllDayDisplayMode, SttLanguage } from '$lib/stores/settings.svelte'; import { calendarsStore } from '$lib/stores/calendars.svelte'; import { toast } from '$lib/stores/toast.svelte'; import { @@ -620,6 +620,48 @@ + + + {#snippet icon()} + + + + {/snippet} + +
+
+
+ Sprache der Spracherkennung + Sprache für die Transkription von Sprachaufnahmen +
+
+ + +
+
+
+
+
+ {#snippet icon()} diff --git a/apps/calendar/apps/web/src/lib/services/stt.ts b/apps/calendar/apps/web/src/lib/services/stt.ts index 1ed2c509d..037865503 100644 --- a/apps/calendar/apps/web/src/lib/services/stt.ts +++ b/apps/calendar/apps/web/src/lib/services/stt.ts @@ -7,11 +7,18 @@ import { browser } from '$app/environment'; /** - * STT service URL - defaults to localhost for development + * STT service URL - uses runtime injection for production, env var for dev */ -const STT_URL = browser - ? import.meta.env.PUBLIC_STT_URL || 'http://localhost:3020' - : 'http://localhost:3020'; +function getSttUrl(): string { + if (!browser) return 'http://localhost:3020'; + // Check runtime-injected variable first (production Docker) + const runtimeUrl = (window as any).__PUBLIC_STT_URL__; + if (runtimeUrl) return runtimeUrl; + // Fall back to build-time env var or default + return import.meta.env.PUBLIC_STT_URL || 'https://stt-api.mana.how'; +} + +const STT_URL = getSttUrl(); export interface TranscriptionResult { /** The transcribed text */ diff --git a/apps/calendar/apps/web/src/lib/stores/settings.svelte.ts b/apps/calendar/apps/web/src/lib/stores/settings.svelte.ts index 32de61472..b82b4b1d3 100644 --- a/apps/calendar/apps/web/src/lib/stores/settings.svelte.ts +++ b/apps/calendar/apps/web/src/lib/stores/settings.svelte.ts @@ -14,6 +14,7 @@ export type WeekStartDay = 0 | 1; // 0 = Sunday, 1 = Monday export type TimeFormat = '24h' | '12h'; export type AllDayDisplayMode = 'header' | 'block'; // header = separate row, block = full day block in grid export type WeekdayFormat = 'full' | 'short' | 'hidden'; +export type SttLanguage = 'de' | 'auto'; // Speech-to-text language setting export interface CalendarAppSettings { // View settings @@ -64,6 +65,9 @@ export interface CalendarAppSettings { // Event defaults defaultEventDuration: number; // in minutes defaultReminder: number; // in minutes before event + + // Voice input settings + sttLanguage: SttLanguage; // Speech-to-text language ('de' or 'auto') } const DEFAULT_SETTINGS: CalendarAppSettings = { @@ -106,6 +110,8 @@ const DEFAULT_SETTINGS: CalendarAppSettings = { // Event defaults defaultEventDuration: 60, defaultReminder: 15, + // Voice input defaults + sttLanguage: 'de', }; const STORAGE_KEY = 'calendar-settings'; @@ -275,6 +281,9 @@ export const settingsStore = { get customDayCount() { return settings.customDayCount; }, + get sttLanguage() { + return settings.sttLanguage; + }, get cloudSyncEnabled() { return cloudSyncEnabled; }, diff --git a/apps/calendar/apps/web/src/lib/utils/audio-recorder.ts b/apps/calendar/apps/web/src/lib/utils/audio-recorder.ts index afd99c86c..9554bebe6 100644 --- a/apps/calendar/apps/web/src/lib/utils/audio-recorder.ts +++ b/apps/calendar/apps/web/src/lib/utils/audio-recorder.ts @@ -35,7 +35,12 @@ export interface AudioRecorder { * Check if the browser supports audio recording */ export function isAudioRecordingSupported(): boolean { - return !!(navigator.mediaDevices && navigator.mediaDevices.getUserMedia && window.MediaRecorder); + return !!( + typeof navigator !== 'undefined' && + navigator.mediaDevices && + typeof navigator.mediaDevices.getUserMedia === 'function' && + typeof MediaRecorder !== 'undefined' + ); } /** diff --git a/scripts/generate-env.mjs b/scripts/generate-env.mjs index b0c8935d5..ba8fac561 100644 --- a/scripts/generate-env.mjs +++ b/scripts/generate-env.mjs @@ -391,6 +391,8 @@ const APP_CONFIGS = [ // Cross-app integration: Contacts service for birthdays PUBLIC_CONTACTS_API_URL: (env) => `http://localhost:${env.CONTACTS_BACKEND_PORT || '3015'}`, PUBLIC_CONTACTS_WEB_URL: () => 'http://localhost:5184', + // Speech-to-Text Service + PUBLIC_STT_URL: (env) => env.STT_URL || 'http://localhost:3020', }, },