Skip to content

Commit 1ac3dd4

Browse files
authored
Merge pull request open-webui#21773 from open-webui/dev
0.8.5
2 parents 2ed3055 + 55c4891 commit 1ac3dd4

9 files changed

Lines changed: 60 additions & 10 deletions

File tree

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.8.5] - 2026-02-23
9+
10+
### Added
11+
12+
- ⌨️ **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.
13+
14+
### Fixed
15+
16+
- 🚫 **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).
17+
- 🔄 **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.
18+
- 🛡️ **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.
19+
820
## [0.8.4] - 2026-02-23
921

1022
### Added

backend/open_webui/utils/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ def get_filtered_models(models, user, db=None):
459459
if model_info:
460460
if (
461461
(user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL)
462-
or user.id == model_info["user_id"]
462+
or user.id == model_info.get("user_id")
463463
or model["id"] in accessible_model_ids
464464
):
465465
filtered_models.append(model)

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "open-webui",
3-
"version": "0.8.4",
3+
"version": "0.8.5",
44
"private": true,
55
"scripts": {
66
"dev": "npm run pyodide:fetch && vite dev --host",

src/lib/components/chat/MessageInput.svelte

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,19 @@
824824
shiftKey = true;
825825
}
826826
827+
// Cmd/Ctrl+Shift+L to toggle dictation
828+
if (e.key.toLowerCase() === 'l' && (e.metaKey || e.ctrlKey) && e.shiftKey) {
829+
e.preventDefault();
830+
if (recording) {
831+
// Confirm and stop recording
832+
document.getElementById('confirm-recording-button')?.click();
833+
} else {
834+
// Start recording (same logic as voice-input-button click)
835+
document.getElementById('voice-input-button')?.click();
836+
}
837+
return;
838+
}
839+
827840
if (e.key === 'Escape') {
828841
console.log('Escape');
829842
dragged = false;

src/lib/components/chat/MessageInput/VoiceRecording.svelte

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,17 @@
368368
let maxVisibleItems = 300;
369369
$: maxVisibleItems = Math.floor(containerWidth / 5); // 2px width + 0.5px gap
370370
371+
const handleKeyDown = (e) => {
372+
if (e.key === 'Escape') {
373+
e.preventDefault();
374+
stopRecording();
375+
onCancel();
376+
}
377+
};
378+
371379
onMount(() => {
380+
window.addEventListener('keydown', handleKeyDown);
381+
372382
// listen to width changes
373383
resizeObserver = new ResizeObserver(() => {
374384
VISUALIZER_BUFFER_LENGTH = Math.floor(window.innerWidth / 4);
@@ -385,6 +395,7 @@
385395
});
386396
387397
onDestroy(() => {
398+
window.removeEventListener('keydown', handleKeyDown);
388399
// remove resize observer
389400
resizeObserver.disconnect();
390401
});
@@ -547,6 +558,7 @@
547558
</div>
548559
{:else}
549560
<button
561+
id="confirm-recording-button"
550562
type="button"
551563
class="p-1.5 bg-indigo-500 text-white dark:bg-indigo-500 dark:text-blue-950 rounded-full"
552564
on:click={async () => {

src/lib/shortcuts.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export enum Shortcut {
1717
NEW_TEMPORARY_CHAT = 'newTemporaryChat',
1818
DELETE_CHAT = 'deleteChat',
1919
OPEN_MODEL_SELECTOR = 'openModelSelector',
20+
TOGGLE_DICTATION = 'toggleDictation',
2021

2122
//Global
2223
SEARCH = 'search',
@@ -64,6 +65,11 @@ export const shortcuts: ShortcutRegistry = {
6465
keys: ['mod', 'shift', 'M'],
6566
category: 'Chat'
6667
},
68+
[Shortcut.TOGGLE_DICTATION]: {
69+
name: 'Toggle Dictation',
70+
keys: ['mod', 'shift', 'L'],
71+
category: 'Chat'
72+
},
6773

6874
//Global
6975
[Shortcut.SEARCH]: {

src/routes/(app)/+layout.svelte

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,14 @@
152152
clearChatInputStorage();
153153
await Promise.all([
154154
checkLocalDBChats(),
155-
setBanners(),
156-
setTools(),
155+
setBanners().catch((e) => console.error('Failed to load banners:', e)),
156+
setTools().catch((e) => console.error('Failed to load tools:', e)),
157157
setUserSettings(async () => {
158-
await Promise.all([setModels(), setToolServers()]);
159-
})
158+
await Promise.all([
159+
setModels().catch((e) => console.error('Failed to load models:', e)),
160+
setToolServers().catch((e) => console.error('Failed to load tool servers:', e))
161+
]);
162+
}).catch((e) => console.error('Failed to load user settings:', e))
160163
]);
161164
162165
// Helper function to check if the pressed keys match the shortcut definition

src/routes/+layout.svelte

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@
770770
const browserLanguages = navigator.languages
771771
? navigator.languages
772772
: [navigator.language || navigator.userLanguage];
773-
const lang = backendConfig.default_locale
773+
const lang = backendConfig?.default_locale
774774
? backendConfig.default_locale
775775
: bestMatchingLanguage(languages, browserLanguages, 'en-US');
776776
changeLanguage(lang);
@@ -797,7 +797,11 @@
797797
798798
if (sessionUser) {
799799
await user.set(sessionUser);
800-
await config.set(await getBackendConfig());
800+
try {
801+
await config.set(await getBackendConfig());
802+
} catch (error) {
803+
console.error('Error refreshing backend config:', error);
804+
}
801805
} else {
802806
// Redirect Invalid Session User to /auth Page
803807
localStorage.removeItem('token');

0 commit comments

Comments
 (0)