diff --git a/CHANGELOG.md b/CHANGELOG.md index bc2dfc15c0..b6a6674982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.8.5] - 2026-02-23 + +### Added + +- ⌨️ **Voice dictation shortcut.** Users can now toggle voice dictation using Cmd+Shift+L (or Ctrl+Shift+L on Windows/Linux), making it faster to start and stop dictation without clicking the microphone button. + +### Fixed + +- 🚫 **Model access KeyError fix.** The /api/models endpoint no longer crashes with a 500 error when models have incomplete info metadata missing the user_id field (e.g. models using global default metadata). +- 🔄 **Frontend initialization resilience.** The app layout now gracefully handles individual API failures during initialization (getModels, getBanners, getTools, getUserSettings, setToolServers) instead of blocking the entire page load when any single call fails. +- 🛡️ **Backend config null safety.** Language detection during app initialization no longer crashes when the backend config fetch fails, preventing a secondary cause of infinite loading. + ## [0.8.4] - 2026-02-23 ### Added diff --git a/backend/open_webui/utils/models.py b/backend/open_webui/utils/models.py index 285de54fc9..6040c0645d 100644 --- a/backend/open_webui/utils/models.py +++ b/backend/open_webui/utils/models.py @@ -459,7 +459,7 @@ def get_filtered_models(models, user, db=None): if model_info: if ( (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) - or user.id == model_info["user_id"] + or user.id == model_info.get("user_id") or model["id"] in accessible_model_ids ): filtered_models.append(model) diff --git a/package-lock.json b/package-lock.json index 467452cac3..b77dca902a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.8.4", + "version": "0.8.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.8.4", + "version": "0.8.5", "dependencies": { "@azure/msal-browser": "^4.5.0", "@codemirror/lang-javascript": "^6.2.2", diff --git a/package.json b/package.json index e4f677ee7f..8c024b76e2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.8.4", + "version": "0.8.5", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index a0cc2dd010..696c682018 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -824,6 +824,19 @@ shiftKey = true; } + // Cmd/Ctrl+Shift+L to toggle dictation + if (e.key.toLowerCase() === 'l' && (e.metaKey || e.ctrlKey) && e.shiftKey) { + e.preventDefault(); + if (recording) { + // Confirm and stop recording + document.getElementById('confirm-recording-button')?.click(); + } else { + // Start recording (same logic as voice-input-button click) + document.getElementById('voice-input-button')?.click(); + } + return; + } + if (e.key === 'Escape') { console.log('Escape'); dragged = false; diff --git a/src/lib/components/chat/MessageInput/VoiceRecording.svelte b/src/lib/components/chat/MessageInput/VoiceRecording.svelte index 526421daa7..d3dc4cba37 100644 --- a/src/lib/components/chat/MessageInput/VoiceRecording.svelte +++ b/src/lib/components/chat/MessageInput/VoiceRecording.svelte @@ -368,7 +368,17 @@ let maxVisibleItems = 300; $: maxVisibleItems = Math.floor(containerWidth / 5); // 2px width + 0.5px gap + const handleKeyDown = (e) => { + if (e.key === 'Escape') { + e.preventDefault(); + stopRecording(); + onCancel(); + } + }; + onMount(() => { + window.addEventListener('keydown', handleKeyDown); + // listen to width changes resizeObserver = new ResizeObserver(() => { VISUALIZER_BUFFER_LENGTH = Math.floor(window.innerWidth / 4); @@ -385,6 +395,7 @@ }); onDestroy(() => { + window.removeEventListener('keydown', handleKeyDown); // remove resize observer resizeObserver.disconnect(); }); @@ -547,6 +558,7 @@ {:else}