From 9d6b17ffbc9f533a9708e3e660bc2dccada957a2 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:18:23 +0200 Subject: [PATCH 01/70] fix: errors on Responses API connections are not shown or not kept after a reload (#31439) With a connection set to the Responses API, when the provider reported a reply as failed, the error showed while streaming but was gone after a reload, leaving an empty reply. Some other provider errors never showed up at all, not even while streaming. Both kinds of error now show up and are still there after a reload, the same as on Chat Completions connections. Fixes #31433 --- backend/open_webui/utils/middleware.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 754b90c0c0..5407085707 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -933,6 +933,9 @@ def handle_responses_streaming_event( error = data.get('response', {}).get('error', {}) return current_output, {'error': error} + elif event_type == 'error': + return current_output, {'error': data} + else: return current_output, None @@ -5113,8 +5116,8 @@ async def streaming_chat_response_handler(response, ctx): 'data': data, } ) - # Check for Responses API events (type field starts with "response.") - elif data.get('type', '').startswith('response.'): + # Check for Responses API events + elif data.get('type', '').startswith('response.') or data.get('type', '') == 'error': response_data_type = data.get('type', '') response_data_is_delta = response_data_type.endswith('.delta') output, response_metadata = handle_responses_streaming_event(data, output) @@ -5173,6 +5176,20 @@ async def streaming_chat_response_handler(response, ctx): response_metadata['usage'] = usage if response_metadata.get('error'): + log.error( + 'Provider returned error (streaming): %s', response_metadata['error'] + ) + if save_to_chat: + try: + await Chats.upsert_message_to_chat_by_id_and_message_id( + metadata['chat_id'], + metadata['message_id'], + { + 'error': {'content': response_metadata['error']}, + }, + ) + except Exception: + pass await event_emitter( { 'type': 'chat:completion', From 8081ac299fbd555ae64934ab5ae8252e938aff2b Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:18:35 +0200 Subject: [PATCH 02/70] fix: missing space in reasoning model answers right after the thinking block (#31438) With reasoning models, when the first part of the answer arrived together with the end of the thinking block and ended with a space, that space went missing, so "The answer is 4." was shown and saved as "The answeris 4.". That space is now kept. Fixes #31435 --- backend/open_webui/utils/middleware.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 5407085707..f629b73dd2 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -4682,14 +4682,14 @@ async def streaming_chat_response_handler(response, ctx): # Strip start and end tags from content start_tag_pattern = _start_tag_pattern(start_tag) - block_content = re.sub(start_tag_pattern, '', block_content).strip() + block_content = re.sub(start_tag_pattern, '', block_content) end_tag_pattern = rf'{re.escape(end_tag)}' end_tag_regex = re.compile(end_tag_pattern, re.DOTALL) split_content = end_tag_regex.split(block_content, maxsplit=1) block_content = split_content[0].strip() if split_content else '' - leftover_content = split_content[1].strip() if len(split_content) > 1 else '' + leftover_content = split_content[1].lstrip() if len(split_content) > 1 else '' if block_content: # Update the item with final content From 583f5a66d2ba3def4e47374654abbd22d051ef2a Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:18:43 +0200 Subject: [PATCH 03/70] fix: max_tokens sent through the API is ignored for Ollama models (#31437) When an API request to an Ollama model set max_tokens, Open WebUI passed it on in a place Ollama does not read, so Ollama ignored it and replies ran to full length. The limit now reaches Ollama as its own output length setting, so replies stop at the requested length. It also wins over a max_tokens value saved in the model's advanced parameters, as the API docs describe. Chats in the web UI were not affected, since their limit already reached Ollama correctly. Fixes #31432 --- backend/open_webui/utils/payload.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/utils/payload.py b/backend/open_webui/utils/payload.py index 7ee2f9d3b3..94a9bc4769 100644 --- a/backend/open_webui/utils/payload.py +++ b/backend/open_webui/utils/payload.py @@ -379,10 +379,6 @@ def convert_payload_openai_to_ollama(openai_payload: dict) -> dict: if 'tools' in openai_payload: ollama_payload['tools'] = openai_payload['tools'] - if 'max_tokens' in openai_payload: - ollama_payload['num_predict'] = openai_payload['max_tokens'] - del openai_payload['max_tokens'] - # If there are advanced parameters in the payload, format them in Ollama's options field if openai_payload.get('options'): # Copied before key deletions below so the caller's options stay intact @@ -430,6 +426,11 @@ def convert_payload_openai_to_ollama(openai_payload: dict) -> dict: ollama_options['stop'] = openai_payload.get('stop') ollama_payload['options'] = ollama_options + if 'max_tokens' in openai_payload: + ollama_options = ollama_payload.get('options', {}) + ollama_options['num_predict'] = openai_payload['max_tokens'] + ollama_payload['options'] = ollama_options + if 'metadata' in openai_payload: ollama_payload['metadata'] = openai_payload['metadata'] From 25604d7070d62e6109302babd1ae93cedeb31725 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:19:00 +0200 Subject: [PATCH 04/70] fix: chats keep failing on Anthropic and Bedrock after a tool call is saved incorrectly (#31431) Sometimes a reply where the model used tools gets saved with a tool result that no call in that reply asked for, or with a tool call that never got its result. The chat history was then sent to the provider unchanged, Anthropic and Bedrock rejected it, and every following message in that chat failed until the user deleted the broken reply. Now each tool call is only kept together with its own result from the same reply, and the unmatched calls and results are left out of what gets sent to the model. The chat itself is not changed, and correctly saved chats are sent exactly as before. Fixes #28937 --- backend/open_webui/utils/middleware.py | 22 +++----------- backend/open_webui/utils/misc.py | 42 ++++++++++++++++---------- 2 files changed, 31 insertions(+), 33 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index f629b73dd2..a4ddd71689 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -115,6 +115,7 @@ from open_webui.utils.misc import ( get_last_user_message_item, get_message_list, get_output_text, + get_paired_tool_call_ids, get_response_error_detail, get_reasoning_details, get_system_message, @@ -2306,25 +2307,12 @@ def process_messages_with_output( def sanitize_tool_pairs(messages: list[dict]) -> list[dict]: - tool_result_ids = { - message.get('tool_call_id') - for message in messages - if message.get('role') == 'tool' and message.get('tool_call_id') - } - - tool_call_ids = { - tool_call.get('id') - for message in messages - for tool_call in (message.get('tool_calls') or []) - if message.get('role') == 'assistant' and tool_call.get('id') - } + paired_ids_by_message = get_paired_tool_call_ids(messages) sanitized = [] - for message in messages: + for message, paired_ids in zip(messages, paired_ids_by_message): if message.get('role') == 'assistant' and message.get('tool_calls'): - kept = [ - tool_call for tool_call in message.get('tool_calls') or [] if tool_call.get('id') in tool_result_ids - ] + kept = [tool_call for tool_call in message.get('tool_calls') or [] if tool_call.get('id') in paired_ids] if kept: sanitized.append({**message, 'tool_calls': kept}) else: @@ -2333,7 +2321,7 @@ def sanitize_tool_pairs(messages: list[dict]) -> list[dict]: clean.pop('reasoning_items', None) if clean.get('content'): sanitized.append(clean) - elif message.get('role') != 'tool' or message.get('tool_call_id') in tool_call_ids: + elif message.get('role') != 'tool' or message.get('tool_call_id') in paired_ids: sanitized.append(message) return sanitized diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index ad959d3bc7..5c5dcce3a6 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -261,6 +261,26 @@ def get_output_text(output: list | None) -> str: return '\n'.join(texts) +def get_paired_tool_call_ids(messages: list[dict]) -> list[set[str]]: + """Tool call ids answered within each message's assistant-plus-tool-results block.""" + paired_ids_by_message = [set() for _ in messages] + for index, message in enumerate(messages): + if message.get('role') != 'assistant' or not message.get('tool_calls'): + continue + + block_end = index + 1 + while block_end < len(messages) and messages[block_end].get('role') == 'tool': + block_end += 1 + + requested_ids = {tool_call.get('id') for tool_call in message['tool_calls'] if tool_call.get('id')} + completed_ids = {tool_message.get('tool_call_id') for tool_message in messages[index + 1 : block_end]} + paired_ids = requested_ids & completed_ids + for block_index in range(index, block_end): + paired_ids_by_message[block_index] = paired_ids + + return paired_ids_by_message + + def reconcile_tool_pairs(messages: list[dict]) -> list[dict]: """Drop unpaired tool_use / tool_result from a reconstructed conversation. @@ -271,22 +291,14 @@ def reconcile_tool_pairs(messages: list[dict]) -> list[dict]: Well-formed output is unaffected: every id pairs, so nothing is stripped. """ - completed_tool_call_ids = { - message['tool_call_id'] for message in messages if message.get('role') == 'tool' and message.get('tool_call_id') - } - requested_tool_call_ids = { - tool_call['id'] - for message in messages - for tool_call in message.get('tool_calls') or () - if message.get('role') == 'assistant' and tool_call.get('id') - } + paired_ids_by_message = get_paired_tool_call_ids(messages) reconciled_messages = [] - for message in messages: + for message, paired_ids in zip(messages, paired_ids_by_message): role = message.get('role') - # Orphan tool result — no assistant ever claimed this call_id. - if role == 'tool' and message.get('tool_call_id') not in requested_tool_call_ids: + # Orphan tool result: not claimed by the assistant heading its tool block. + if role == 'tool' and message.get('tool_call_id') not in paired_ids: continue # Non-assistant or no tool_calls — pass through unchanged. @@ -294,10 +306,8 @@ def reconcile_tool_pairs(messages: list[dict]) -> list[dict]: reconciled_messages.append(message) continue - # Keep only tool_calls whose id received a tool-role response. - valid_tool_calls = [ - tool_call for tool_call in message['tool_calls'] if tool_call.get('id') in completed_tool_call_ids - ] + # Keep only tool_calls whose id received an adjacent tool-role response. + valid_tool_calls = [tool_call for tool_call in message['tool_calls'] if tool_call.get('id') in paired_ids] if valid_tool_calls: reconciled_messages.append({**message, 'tool_calls': valid_tool_calls}) From fe8b30438a1ddefcd9d1e446f56e8456c1b89561 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:19:09 +0200 Subject: [PATCH 05/70] fix: stray <|end_of_solution|> marker left in the reply (#31436) When a model wraps its answer in <|begin_of_solution|> and <|end_of_solution|>, only the opening marker was removed. The closing marker stayed visible in the reply and was saved with the message, and anything the model wrote after it was glued onto the answer. Now both markers are removed and text after the answer shows up as a normal part of the reply. Fixes #31434 --- backend/open_webui/utils/middleware.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index a4ddd71689..6378ad57b1 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -4540,7 +4540,7 @@ async def streaming_chat_response_handler(response, ctx): last_type = output[-1].get('type', '') if output else '' - if last_type == 'message': + if last_type == 'message' and output[-1].get('_tag_type') != content_type: # Use the output item's own text for tag detection item = output[-1] item_text = get_last_text(output) From c402acb40478611312616ebbe221eba7cbfea24b Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:19:56 +0200 Subject: [PATCH 06/70] fix: skills picked from the / menu are not applied to the reply (#31429) Picking a skill from the / menu in the chat input inserted it as an @ mention, so the skill was never loaded and its raw tag ended up in the message the model received. Picking the same skill from the $ menu worked. A skill chosen through / is now sent the same way as through $ and gets applied. Fixes #29978 --- src/lib/components/chat/MessageInput.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 8d5107286e..02859eb9f4 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1452,7 +1452,7 @@ .insertContentAt(range, [ { type: 'mention', - attrs: props + attrs: { ...props, mentionSuggestionChar: '/' } }, { type: 'text', text: ' ' } ]) From 42cd4f0ec0569797edef36b97229735b8d01d024 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:20:14 +0200 Subject: [PATCH 07/70] refactor: check shared chat access before loading the snapshot on clone (#30388) The clone endpoint now resolves and checks the share before reading its snapshot, matching the order used by the shared chat view endpoint. --- backend/open_webui/routers/chats.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 7138dc9f21..e46fed259c 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -1848,18 +1848,6 @@ async def clone_shared_chat_by_id( ): await require_chat_import_permission(request, user, db) - chat = await Chats.get_chat_by_share_id(id, db=db) - - # Fallback: admins can also access any chat directly by chat ID - if not chat and user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: - chat = await Chats.get_chat_by_id(id, db=db) - - if not chat: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.NOT_FOUND, - ) - # Enforce access grants (owner and admins bypass) shared = await SharedChats.get_by_id(id, db=db) if shared and user.role != 'admin' and shared.user_id != user.id: @@ -1876,6 +1864,18 @@ async def clone_shared_chat_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) + chat = await Chats.get_chat_by_share_id(id, db=db) if shared else None + + # Fallback: admins can also access any chat directly by chat ID + if not chat and user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: + chat = await Chats.get_chat_by_id(id, db=db) + + if not chat: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + updated_chat = { **chat.chat, 'originalChatId': chat.id, From ffa6bb17cd2f92cccd3059f95ed8e0ea2db982df Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:26:19 -0400 Subject: [PATCH 08/70] fix: refresh the skill list used in chat after turning a skill on or off (#30966) --- src/lib/components/workspace/Skills.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/components/workspace/Skills.svelte b/src/lib/components/workspace/Skills.svelte index 876e44b2cf..20dbb211a9 100644 --- a/src/lib/components/workspace/Skills.svelte +++ b/src/lib/components/workspace/Skills.svelte @@ -584,7 +584,8 @@ { - toggleSkillById(localStorage.token, skill.id); + await toggleSkillById(localStorage.token, skill.id); + _skills.set(await getSkills(localStorage.token)); }} /> From 693f666c69c1c10b76dc82e33cd2563f497119be Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:26:27 -0400 Subject: [PATCH 09/70] fix: start a reply saved as a copy without the original's rating (#30962) --- src/lib/components/chat/Messages.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index 30ac1a10a3..4a08eecc02 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -370,6 +370,8 @@ parentId: parentId, childrenIds: [], files: undefined, + annotation: undefined, + feedbackId: undefined, content: output !== undefined ? '' : content, ...(output !== undefined ? { output } : {}), timestamp: Math.floor(Date.now() / 1000) // Unix epoch From 301aa8c5bdb602c4c8b98912d4afff9be486b464 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:26:34 -0400 Subject: [PATCH 10/70] fix: clear the Add Connection form's advanced fields after a connection is added (#30958) --- src/lib/components/AddConnectionModal.svelte | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/components/AddConnectionModal.svelte b/src/lib/components/AddConnectionModal.svelte index a7edcf3913..1a5f117929 100644 --- a/src/lib/components/AddConnectionModal.svelte +++ b/src/lib/components/AddConnectionModal.svelte @@ -241,6 +241,12 @@ showAdvanced = false; tags = []; modelIds = []; + headers = ''; + enable = true; + connectionType = 'external'; + provider = ''; + apiVersion = ''; + apiType = ''; }; const init = () => { From f8e15f92d1f248d867e1f2513251c07d71ee39a6 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:26:43 -0400 Subject: [PATCH 11/70] fix: check the external loader headers whenever they are set, so Save reports the error (#30434) --- src/lib/components/admin/Settings/Documents.svelte | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index 4baf3a01a5..aa0c109769 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -169,10 +169,7 @@ toast.error($i18n.t('External Document Loader URL required.')); return; } - if ( - RAGConfig.CONTENT_EXTRACTION_ENGINE === 'external' && - RAGConfig.EXTERNAL_DOCUMENT_LOADER_HEADERS - ) { + if (RAGConfig.EXTERNAL_DOCUMENT_LOADER_HEADERS) { try { const headers = JSON.parse(RAGConfig.EXTERNAL_DOCUMENT_LOADER_HEADERS); if (headers === null || typeof headers !== 'object' || Array.isArray(headers)) { From 6fdbe3ab67bba7de26fcb047de5547e0ce9c6d3a Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:27:40 -0400 Subject: [PATCH 12/70] fix: move a calendar event's end with its date instead of keeping the old end date (#31303) --- .../components/calendar/CalendarEventModal.svelte | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/lib/components/calendar/CalendarEventModal.svelte b/src/lib/components/calendar/CalendarEventModal.svelte index 75237d9323..cf92306f79 100644 --- a/src/lib/components/calendar/CalendarEventModal.svelte +++ b/src/lib/components/calendar/CalendarEventModal.svelte @@ -28,6 +28,7 @@ let startDate = ''; let startTime = ''; let endDate = ''; + let endDayOffset = 0; let endTime = ''; let allDay = false; let location = ''; @@ -111,6 +112,12 @@ alertMinutes = 10; repeatFrequency = ''; } + endDayOffset = endDate + ? Math.round( + (dateTimeToNs(endDate, '12:00') - dateTimeToNs(startDate, '12:00')) / + (24 * 60 * 60 * 1000 * NS) + ) + : 0; } $: if (show) reset(); @@ -129,7 +136,12 @@ loading = true; try { const startNs = dateTimeToNs(startDate, allDay ? '00:00' : startTime); - let endNs = endDate ? dateTimeToNs(endDate, allDay ? '23:59' : endTime) : undefined; + const shiftedEndDate = endDate + ? nsToDateStr(dateTimeToNs(startDate, '12:00') + endDayOffset * 24 * 60 * 60 * 1000 * NS) + : ''; + let endNs = shiftedEndDate + ? dateTimeToNs(shiftedEndDate, allDay ? '23:59' : endTime) + : undefined; if (endNs !== undefined && endNs < startNs) { const duration = event?.end_at && event.end_at > event.start_at ? event.end_at - event.start_at : 0; From ffe21bef8dd8f1dbcd7aa0dd1805733e97bdb6d6 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:27:49 -0400 Subject: [PATCH 13/70] fix: remove the share links of chats deleted along with their folder (#31306) --- backend/open_webui/models/chats.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index d90f52e4c9..c5620f0cfe 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -2522,6 +2522,8 @@ class ChatTable: async def delete_chats_by_user_id_and_folder_id( self, user_id: str, folder_id: str, db: AsyncSession | None = None ) -> bool: + from open_webui.models.shared_chats import SharedChat as SharedChatTable + try: async with get_async_db_context(db) as session: chat_ids_stmt = select(Chat.id).filter_by(user_id=user_id, folder_id=folder_id) @@ -2529,6 +2531,7 @@ class ChatTable: update(AutomationRun).filter(AutomationRun.chat_id.in_(chat_ids_stmt)).values(chat_id=None) ) await session.execute(delete(ChatMessage).filter(ChatMessage.chat_id.in_(chat_ids_stmt))) + await session.execute(delete(SharedChatTable).filter(SharedChatTable.chat_id.in_(chat_ids_stmt))) await session.execute(delete(Chat).filter_by(user_id=user_id, folder_id=folder_id)) await session.commit() From b233d0d94bf8f464da648101d2655fc81f488557 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Fri, 25 Sep 2026 23:28:02 -0400 Subject: [PATCH 14/70] fix: paste the clipboard as is for {{CLIPBOARD}}, keeping dollar signs (#31364) --- src/lib/components/channel/MessageInput.svelte | 2 +- src/lib/components/chat/MessageInput.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/channel/MessageInput.svelte b/src/lib/components/channel/MessageInput.svelte index bc7cd1a8de..ff432ae89a 100644 --- a/src/lib/components/channel/MessageInput.svelte +++ b/src/lib/components/channel/MessageInput.svelte @@ -126,7 +126,7 @@ } } - text = text.replaceAll('{{CLIPBOARD}}', clipboardText.replaceAll('\r\n', '\n')); + text = text.replaceAll('{{CLIPBOARD}}', () => clipboardText.replaceAll('\r\n', '\n')); } if (text.includes('{{USER_LOCATION}}')) { diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 02859eb9f4..ec568c9a41 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -305,7 +305,7 @@ } } - text = text.replaceAll('{{CLIPBOARD}}', clipboardText.replaceAll('\r\n', '\n')); + text = text.replaceAll('{{CLIPBOARD}}', () => clipboardText.replaceAll('\r\n', '\n')); } if (text.includes('{{USER_LOCATION}}')) { From 420b4a2797fa283cd15b5ee267380743115eca5f Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 26 Sep 2026 05:28:13 +0200 Subject: [PATCH 15/70] fix(retrieval): name the link when process/web cannot fetch it (#31351) A link whose host refuses the connection, such as a closed port, still came back from POST /api/v1/retrieval/process/web as "Error querying knowledge base", so the caller was told the knowledge base failed when the link was the problem. The web loaders log a failed fetch and return no documents. That empty result then failed while being saved to the vector store, and the save error was the one reported. process_web now answers with the existing "Could not read content from " 400 as soon as the loader returns no documents, the same message a link refused by the fetch filter already gets. The check sits in the endpoint so web search and the other users of the loaders keep their current behaviour. With process=false or embedding bypassed, an unreachable link now gets the same 400 where it used to return 200 with empty content. Fixes #31347 --- backend/open_webui/routers/retrieval.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index b9375e56c6..6517ed0674 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -2457,6 +2457,13 @@ async def process_web( detail=ERROR_MESSAGES.DEFAULT(e, f'Could not read content from {form_data.url}'), ) + # web loaders swallow fetch errors and return no documents + if not docs: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=ERROR_MESSAGES.DEFAULT(f'Could not read content from {form_data.url}'), + ) + try: log.debug('text_content: %s', content) From b0650d04b2bd46b9afd2a41daaedcf7c05829ffe Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:56:20 +0200 Subject: [PATCH 16/70] fix: failed timer leaves a blank, unfinished reply in the chat (#31483) When a scheduled timer failed before the model started answering, for example because its model had been removed, the chat showed the timer's prompt with a blank reply that looked stuck, and the error never appeared in the chat. The reply now shows the error and stops loading, like any other failed message. Fixes #31481 --- backend/open_webui/utils/timers.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/utils/timers.py b/backend/open_webui/utils/timers.py index d8be899dff..15a6b898db 100644 --- a/backend/open_webui/utils/timers.py +++ b/backend/open_webui/utils/timers.py @@ -11,7 +11,7 @@ from datetime import datetime, timezone from typing import Literal from uuid import uuid4 -from fastapi import Request +from fastapi import HTTPException, Request from open_webui.internal.db import get_async_db from open_webui.models.chat_messages import ChatMessages from open_webui.models.chats import Chat, ChatForm, Chats @@ -416,7 +416,20 @@ async def execute_due_timer(app, timer_id: str, claim_id: str | None = None) -> await app.state.CHAT_COMPLETION_HANDLER(request, form_data, user=user) except Exception as exc: log.exception(f'Timer {timer_id} completion failed') - await _set_timer_state(timer_id, 'error', timer_error=str(exc)[:500]) + error_detail = exc.detail if isinstance(exc, HTTPException) else str(exc) + await _set_timer_state(timer_id, 'error', timer_error=error_detail[:500]) + await Chats.upsert_message_to_chat_by_id_and_message_id( + parent_chat_id, assistant_message_id, {'error': {'content': error_detail}, 'done': True} + ) + await sio.emit( + 'events', + { + 'chat_id': parent_chat_id, + 'message_id': assistant_message_id, + 'data': {'type': 'chat:message:error', 'data': {'error': {'content': error_detail}, 'done': True}}, + }, + room=f'user:{timer.user_id}', + ) async def _set_timer_state(timer_id: str, status: str, **fields) -> None: From 2ab5023e5a7d8147d8581e89803ce1e203864630 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:58:28 +0200 Subject: [PATCH 17/70] i18n: complete and correct German (de-DE) translations (#31462) Fills all 191 strings that were still untranslated in the German catalog and fixes existing entries that turned up while checking each string against the spot where it appears in the interface. Several were plainly wrong: "Reason" in the feedback dialog read "Nachdenken" (thinking), the Open Terminal product name was translated as the action "open terminal", the terminal memory limit said "Erinnerungen" (memories) and the share dialog assembled into broken sentences. Leftover English ("API Key", "History", "Policy", "Queue"), informal "du" toward the user and outliers like "Nutzer" next to the dominant "Benutzer" now match the rest of the catalog, and compounds written as two words are joined or hyphenated. Prompts written to the AI model (suggestion cards, system prompt examples) use the informal "du", and the chat bubble label stays "Du". Only de-DE is touched, with no keys added, removed or reordered. --- src/lib/i18n/locales/de-DE/translation.json | 714 ++++++++++---------- 1 file changed, 357 insertions(+), 357 deletions(-) diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 0d08752e99..b4284a02d7 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -6,12 +6,12 @@ "[Today at] h:mm A": "[Heute um] h:mm A", "[Yesterday at] h:mm A": "[Gestern um] h:mm A", "{{ models }}": "{{ models }}", - "{{count}} added lines_one": "", - "{{count}} added lines_other": "", + "{{count}} added lines_one": "{{count}} hinzugefügte Zeile", + "{{count}} added lines_other": "{{count}} hinzugefügte Zeilen", "{{COUNT}} Available Skills": "{{COUNT}} verfügbare Skills", "{{COUNT}} Available Tools": "{{COUNT}} verfügbare Werkzeuge", "{{COUNT}} characters": "{{COUNT}} Zeichen", - "{{COUNT}} document(s) selected.": "", + "{{COUNT}} document(s) selected.": "{{COUNT}} Dokument(e) ausgewählt.", "{{COUNT}} extracted lines": "{{COUNT}} extrahierte Zeilen", "{{count}} files_one": "{{count}} Datei", "{{count}} files_other": "{{count}} Dateien", @@ -26,11 +26,11 @@ "{{COUNT}} members": "{{COUNT}} Mitglieder", "{{count}} of {{total}} accessible_one": "{{count}} von {{total}} zugänglich", "{{count}} of {{total}} accessible_other": "{{count}} von {{total}} zugänglich", - "{{COUNT}} pipeline(s) selected": "", - "{{count}} removed lines_one": "", - "{{count}} removed lines_other": "", + "{{COUNT}} pipeline(s) selected": "{{COUNT}} Pipeline(s) ausgewählt", + "{{count}} removed lines_one": "{{count}} entfernte Zeile", + "{{count}} removed lines_other": "{{count}} entfernte Zeilen", "{{COUNT}} Replies": "{{COUNT}} Antworten", - "{{COUNT}} Rows": "{{COUNT}} Reihen", + "{{COUNT}} Rows": "{{COUNT}} Zeilen", "{{count}} selected_one": "{{count}} ausgewählt", "{{count}} selected_other": "{{count}} ausgewählt", "{{COUNT}} Sources": "{{COUNT}} Quellen", @@ -45,33 +45,33 @@ "{{label}} contains invalid JSON": "{{label}} enthält ungültiges JSON", "{{label}} must be a JSON object": "{{label}} muss ein JSON-Objekt sein", "{{model}} download has been canceled": "Der Download von {{model}} wurde abgebrochen", - "{{modelName}} profile image": "{{modelName}} Profil Bild", + "{{modelName}} profile image": "Profilbild von {{modelName}}", "{{NAMES}} reacted with {{REACTION}}": "{{NAMES}} reagierte(n) mit {{REACTION}}", - "{{page}} / {{totalPages}} ({{rows}} rows)": "", - "{{percent}}% full": "", + "{{page}} / {{totalPages}} ({{rows}} rows)": "{{page}} / {{totalPages}} ({{rows}} Zeilen)", + "{{percent}}% full": "{{percent}} % belegt", "{{user}}'s Chats": "Chats von {{user}}", "{{webUIName}} Backend Required": "{{webUIName}}-Backend erforderlich", - "* (all domains)": "", + "* (all domains)": "* (alle Domains)", "*Prompt node ID(s) are required for image generation": "*Prompt-Node-ID(s) sind für die Bildgenerierung erforderlich", - "*required": "", + "*required": "*erforderlich", "1 file": "1 Datei", "1 group": "1 Gruppe", - "1 hour before": "1 Stunde vor", + "1 hour before": "1 Stunde vorher", "1 Source": "1 Quelle", "1 user": "1 Benutzer", - "10 minutes before": "10 Minuten vor", - "15 minutes before": "15 Minuten vor", - "1m_time_ago": "vor 1 Minute", - "30 minutes before": "30 Minuten vor", - "5 minutes before": "5 Minuten vor", - "A chat run failed.": "", - "A chat run finished successfully.": "", + "10 minutes before": "10 Minuten vorher", + "15 minutes before": "15 Minuten vorher", + "1m_time_ago": "1 min", + "30 minutes before": "30 Minuten vorher", + "5 minutes before": "5 Minuten vorher", + "A chat run failed.": "Ein Chat-Durchlauf ist fehlgeschlagen.", + "A chat run finished successfully.": "Ein Chat-Durchlauf wurde erfolgreich abgeschlossen.", "A collaboration channel where people join as members": "Ein Kanal zur Zusammenarbeit, dem Mitglieder beitreten können", "A discussion channel where access is controlled by groups and permissions": "Ein Diskussionskanal, dessen Zugriff durch Gruppen und Berechtigungen gesteuert wird", "A new version (v{{LATEST_VERSION}}) is now available.": "Eine neue Version (v{{LATEST_VERSION}}) ist jetzt verfügbar.", "A private conversation between you and selected users": "Eine private Unterhaltung zwischen Ihnen und ausgewählten Benutzern", "a user": "ein Benutzer", - "about the Roman Empire": "", + "about the Roman Empire": "über das Römische Reich", "Accept Autocomplete Generation\nJump to Prompt Variable": "Autovervollständigung akzeptieren\nZur Prompt-Variable springen", "Access": "Zugriff", "Access Control": "Zugriffskontrolle", @@ -120,7 +120,7 @@ "Add Terminal Connection": "Terminalverbindung hinzufügen", "Add text content": "Textinhalt hinzufügen", "Add to favorites": "Zu Favoriten hinzufügen", - "Add translation": "", + "Add translation": "Übersetzung hinzufügen", "Add User": "Benutzer hinzufügen", "Add User Group": "Benutzergruppe hinzufügen", "Add User Variable": "Benutzervariable hinzufügen", @@ -128,7 +128,7 @@ "Add webpage": "Webseite hinzufügen", "Add your Open Terminal URL and API key in Settings → Integrations.": "Fügen Sie Ihre Open-Terminal-URL und Ihren API-Schlüssel unter Einstellungen → Integrationen hinzu.", "Additional configuration options for marker. This should be a JSON string with key-value pairs. For example, '{\"key\": \"value\"}'. Supported keys include: disable_links, keep_pageheader_in_output, keep_pagefooter_in_output, filter_blank_pages, drop_repeated_text, layout_coverage_threshold, merge_threshold, height_tolerance, gap_threshold, image_threshold, min_line_length, level_count, default_level": "Zusätzliche Konfigurationsoptionen für Marker. Dies sollte ein JSON-String mit Schlüssel-Wert-Paaren sein. Zum Beispiel '{\"key\": \"value\"}'. Unterstützte Schlüssel sind: disable_links, keep_pageheader_in_output, keep_pagefooter_in_output, filter_blank_pages, drop_repeated_text, layout_coverage_threshold, merge_threshold, height_tolerance, gap_threshold, image_threshold, min_line_length, level_count, default_level", - "Additional feedback comments": "Zusätzliche Feedback Kommentare", + "Additional feedback comments": "Zusätzliche Feedback-Kommentare", "admin": "Administrator", "Admin": "Administrator", "Admin Panel": "Admin-Bereich", @@ -145,11 +145,11 @@ "All models are now hidden": "Alle Modelle sind nun versteckt", "All models are now visible": "Alle Modelle sind nun sichtbar", "All models deleted successfully": "Alle Modelle erfolgreich gelöscht", - "All rights reserved.": "", + "All rights reserved.": "Alle Rechte vorbehalten.", "All shared chats have been unshared.": "Die Freigabe aller geteilten Chats wurde aufgehoben.", "All Sources": "Alle Quellen", "All time": "Gesamte Zeit", - "All Users": "Alle Nutzer", + "All Users": "Alle Benutzer", "All users and system events": "Alle Benutzer- und Systemereignisse", "Allow": "Erlauben", "Allow {{NAME}}?": "{{NAME}} erlauben?", @@ -168,7 +168,7 @@ "Allow Delete Messages": "Löschen von Nachrichten erlauben", "Allow File Upload": "Dateiupload erlauben", "Allow Multiple Models in Chat": "Mehrere Modelle im Chat erlauben", - "Allow public write access": "Erlaubte öffentlichen schreibenden Zugang", + "Allow public write access": "Öffentlichen Schreibzugriff erlauben", "Allow Rate Response": "Antwortbewertung erlauben", "Allow Regenerate Response": "Antwort-Neugenerierung erlauben", "Allow Sharing With Groups": "Teilen mit Gruppen erlauben", @@ -178,7 +178,7 @@ "Allow Text to Speech": "Text-zu-Sprache erlauben", "Allow the AI to delegate tasks to sub-agents. Each sub-agent creates a real chat with full tool access. Uses additional LLM calls.": "Erlaubt der KI, Aufgaben an Sub-Agents zu delegieren. Jeder Sub-Agent erstellt einen echten Chat mit vollem Werkzeugzugriff. Verursacht zusätzliche LLM-Aufrufe.", "Allow Tool Call": "Werkzeugaufruf erlauben", - "Allow Web Upload": "Webseiten Upload erlauben", + "Allow Web Upload": "Webseiten-Upload erlauben", "Already have an account?": "Bereits registriert?", "Also bound to {{action}}": "Auch mit \"{{action}}\" belegt", "Alternative to the top_p, and aims to ensure a balance of quality and variety. The parameter p represents the minimum probability for a token to be considered, relative to the probability of the most likely token. For example, with p=0.05 and the most likely token having a probability of 0.9, logits with a value less than 0.045 are filtered out.": "Eine Alternative zu top_p, die ein Gleichgewicht zwischen Qualität und Vielfalt anstrebt. Der Parameter p stellt die Mindestwahrscheinlichkeit dar, mit der ein Token relativ zur Wahrscheinlichkeit des wahrscheinlichsten Tokens berücksichtigt wird. Wenn z. B. p = 0.05 ist und das wahrscheinlichste Token eine Wahrscheinlichkeit von 0.9 hat, werden Logits mit einem Wert kleiner als 0.045 gefiltert.", @@ -187,9 +187,9 @@ "an assistant": "ein Assistent", "Analytics": "Analyse", "Analyzed": "Analysiert", - "Analyzing...": "Analysiere...", + "Analyzing...": "Wird analysiert...", "and {{COUNT}} more": "und {{COUNT}} weitere", - "and create a new shared link.": "und erstellen Sie einen neuen Freigabe-Link.", + "and create a new shared link.": "und einen neuen Freigabe-Link zu erstellen.", "Anyone": "Jeder", "Anyone with the link can view": "Für alle mit dem Link einsehbar", "API Base URL": "API-Basis-URL", @@ -198,10 +198,10 @@ "API Key created.": "API-Schlüssel erstellt.", "API Key deleted.": "API-Schlüssel gelöscht.", "API Keys": "API-Schlüssel", - "API Type": "API Typ", + "API Type": "API-Typ", "API Version": "API-Version", "API Version is required": "API-Version ist erforderlich", - "App navigation": "", + "App navigation": "App-Navigation", "applies to all users with the \"user\" role": "gilt für alle Benutzer mit der Rolle \"Benutzer\"", "April": "April", "Archive": "Archivieren", @@ -216,7 +216,7 @@ "Are you sure you want to delete this directory?": "Sind Sie sicher, dass Sie dieses Verzeichnis löschen möchten?", "Are you sure you want to delete this memory? This action cannot be undone.": "Möchten Sie diese Erinnerung wirklich löschen? Dieser Vorgang kann nicht rückgängig gemacht werden.", "Are you sure you want to delete this message?": "Sind Sie sicher, dass Sie diese Nachricht löschen möchten?", - "Are you sure you want to delete this version? Child versions will be relinked to this version's parent.": "Sind Sie sicher, dass Sie diese Version löschen wollen? Child-Versionen werden zu dem Parent dieser Version verlinkt.", + "Are you sure you want to delete this version? Child versions will be relinked to this version's parent.": "Sind Sie sicher, dass Sie diese Version löschen möchten? Untergeordnete Versionen werden mit der übergeordneten Version dieser Version verknüpft.", "Are you sure you want to delete this webhook? This action cannot be undone.": "Sind Sie sicher, dass Sie diesen Webhook löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.", "Are you sure you want to delete this?": "Sind Sie sicher, dass Sie das löschen wollen?", "Are you sure you want to reset all permissions to their default values? You will still need to save to apply the changes.": "Sind Sie sicher, dass Sie alle Berechtigungen auf ihre Standardwerte zurücksetzen möchten? Sie müssen dennoch speichern, um die Änderungen anzuwenden.", @@ -227,7 +227,7 @@ "Ask": "Fragen", "Ask a question": "Stellen Sie eine Frage", "Ask a test question": "Eine Testfrage stellen", - "Ask for approval": "", + "Ask for approval": "Um Bestätigung bitten", "Ask this knowledge source a test question": "Dieser Wissensquelle eine Testfrage stellen", "Assistant": "Assistent", "Assistant messages": "Assistentennachrichten", @@ -239,7 +239,7 @@ "Attach Notes": "Notizen anhängen", "Attach Webpage": "Webseite anhängen", "Attention to detail": "Liebe zum Detail", - "Audio player": "", + "Audio player": "Audioplayer", "August": "August", "Auth": "Authentifizierung", "Auth Mode": "Authentifizierungsmodus", @@ -265,7 +265,7 @@ "Available Skills": "Verfügbare Skills", "Available Tools": "Verfügbare Werkzeuge", "Available variables": "Verfügbare Variablen", - "available!": "Verfügbar!", + "available!": "verfügbar!", "Average messages per active day": "Durchschnittliche Nachrichten pro aktivem Tag", "Average tokens per chat": "Durchschnittliche Token pro Chat", "Away": "Abwesend", @@ -273,21 +273,21 @@ "Azure AI Speech": "Azure AI Speech", "Azure OpenAI": "Azure OpenAI", "Back": "Zurück", - "Background Image": "", - "Background image must be at most 25 megapixels.": "", - "Background image must be at most 5 MiB.": "", - "Background image must be PNG, JPEG, WebP, or GIF.": "", - "Background image preview": "", + "Background Image": "Hintergrundbild", + "Background image must be at most 25 megapixels.": "Das Hintergrundbild darf höchstens 25 Megapixel groß sein.", + "Background image must be at most 5 MiB.": "Das Hintergrundbild darf höchstens 5 MiB groß sein.", + "Background image must be PNG, JPEG, WebP, or GIF.": "Das Hintergrundbild muss im Format PNG, JPEG, WebP oder GIF vorliegen.", + "Background image preview": "Vorschau des Hintergrundbilds", "Background sub-agent finished": "Sub-Agent im Hintergrund abgeschlossen", - "background sub-agents": "Sub-Agents", + "background sub-agents": "Sub-Agents im Hintergrund", "Bad Response": "Schlechte Antwort", "Base Model (From)": "Basismodell (Von)", - "Base Model is required.": "Basis Modell ist notwendig.", - "Base Models": "", - "Basic text only": "", + "Base Model is required.": "Basismodell ist erforderlich.", + "Base Models": "Basismodelle", + "Basic text only": "Nur einfacher Text", "Basics": "Grundeinstellungen", "Bearer": "Bearer", - "before": "zuvor", + "before": "bereits geteilt", "Being lazy": "Faulheit", "Bing": "Bing", "Bold": "Fett", @@ -297,7 +297,7 @@ "Button ID": "Schaltflächen-ID", "Button Label": "Schaltflächenbeschriftung", "Button Prompt": "Schaltflächen-Prompt", - "By": "", + "By": "Von", "by {{name}}": "von {{name}}", "By {{name}}": "Von {{name}}", "By supporting the project through sponsorship or an enterprise license, you help us stay independent, ship new features faster, improve stability, and grow Open WebUI for the long haul.": "Mit einem Sponsoring oder einer Enterprise-Lizenz unterstützen Sie uns dabei, unabhängig zu bleiben, neue Funktionen schneller auszuliefern, die Stabilität zu verbessern und Open WebUI langfristig weiterzuentwickeln.", @@ -312,12 +312,12 @@ "Camera": "Kamera", "Cancel": "Abbrechen", "Cancel download of {{model}}": "Download von {{model}} abbrechen", - "Cannot create an empty note.": "Leere Notiz kann nicht gespeichert werden.", + "Cannot create an empty note.": "Leere Notiz kann nicht erstellt werden.", "Cannot delete the production version": "Die produktive Version kann nicht gelöscht werden", "Capture": "Aufnahme", "Capture Audio": "Audio aufnehmen", - "Change folder icon": "Ordner-Icon ändern", - "Change User Role": "Nutzerrolle ändern", + "Change folder icon": "Ordnersymbol ändern", + "Change User Role": "Benutzerrolle ändern", "Channel": "Kanal", "Channel deleted successfully": "Kanal erfolgreich gelöscht", "Channel is required": "Kanal ist erforderlich", @@ -335,16 +335,16 @@ "Chat Conversation": "Chat-Unterhaltung", "Chat deleted.": "Chat gelöscht.", "Chat exported successfully": "Chat erfolgreich exportiert", - "Chat failed": "", - "Chat finished": "", + "Chat failed": "Chat fehlgeschlagen", + "Chat finished": "Chat abgeschlossen", "Chat forked": "Chat verzweigt", "Chat history": "Chatverlauf", "Chat ID": "Chat-ID", "Chat is too short to compact": "Der Chat ist zu kurz zum Verdichten", - "Chat Menu": "", + "Chat Menu": "Chat-Menü", "Chat moved successfully": "Chat erfolgreich verschoben", "Chat Permissions": "Chat-Berechtigungen", - "Chat unarchived.": "", + "Chat unarchived.": "Chat aus dem Archiv wiederhergestellt.", "Chat unshared successfully.": "Chat-Freigabe erfolgreich aufgehoben", "Chat Uploads": "Chat-Uploads", "Chat Variables": "Chat-Variablen", @@ -355,7 +355,7 @@ "Chats Public Sharing": "Öffentliche Chat-Freigabe", "Check Again": "Erneut prüfen", "Check OAuth Discovery": "OAuth-Discovery prüfen", - "Check what is running in this chat.": "", + "Check what is running in this chat.": "Prüfen, was in diesem Chat gerade läuft.", "Checking for updates...": "Suche nach Updates...", "Choose a model before saving...": "Wählen Sie vor dem Speichern ein Modell...", "Choose channel": "Kanal auswählen", @@ -381,7 +381,7 @@ "Click to connect": "Zum Verbinden klicken", "Click to copy ID": "Zum Kopieren der ID klicken", "Click to rebind": "Zum Neubelegen klicken", - "Client ID": "Client ID", + "Client ID": "Client-ID", "Client Secret": "Client Secret", "Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Schreibzugriff auf Zwischenablage verweigert. Bitte prüfen Sie Ihre Browsereinstellungen.", "Clone": "Klonen", @@ -389,15 +389,15 @@ "Clone of {{TITLE}}": "Kopie von {{TITLE}}", "Close": "Schließen", "Close Banner": "Banner schließen", - "Close chat controls": "Chat Controls schließen", + "Close chat controls": "Chat-Steuerung schließen", "Close citation modal": "Zitat-Popup schließen", "Close Configure Connection Modal": "Verbindungs-Konfiguration schließen", - "Close embed": "", + "Close embed": "Einbettung schließen", "Close feedback": "Feedback schließen", "Close modal": "Modal schließen", "Close Modal": "Modal schließen", "Close Sidebar": "Seitenleiste schließen", - "Close terminal": "", + "Close terminal": "Terminal schließen", "cloud": "Cloud", "CMU ARCTIC speaker embedding name": "Name des CMU ARCTIC Sprecher-Embeddings", "Code Block": "Code-Block", @@ -420,10 +420,10 @@ "Command": "Befehl", "Commands": "Befehle", "Comment": "Kommentar", - "Commit Message": "Commit Nachricht", - "Community Reviews": "Community Bewertungen", - "Compact": "", - "Compact: shorten older messages so this chat can keep going.": "", + "Commit Message": "Commit-Nachricht", + "Community Reviews": "Community-Bewertungen", + "Compact": "Verdichten", + "Compact: shorten older messages so this chat can keep going.": "Verdichten: ältere Nachrichten kürzen, damit dieser Chat fortgesetzt werden kann.", "Compacting context": "Kontext wird verdichtet", "Compacting context...": "Kontext wird verdichtet...", "Compare": "Vergleichen", @@ -441,7 +441,7 @@ "Confirm your action": "Bitte bestätigen", "Confirm your new password": "Neues Passwort bestätigen", "Confirm Your Password": "Passwort bestätigen", - "Connect to an AI provider to start chatting": "Zum Chatten mit einem AI provider verbinden", + "Connect to an AI provider to start chatting": "Verbinden Sie sich mit einem KI-Anbieter, um zu chatten", "Connect to Open Terminal instances. Admins and users granted access can use file browsing and terminal tools through these servers.": "Stellt eine Verbindung zu Open-Terminal-Instanzen her. Administratoren und Benutzer mit Zugriff können über diese Server die Dateiansicht und Terminal-Werkzeuge nutzen.", "Connect to your own OpenAPI compatible external tool servers.": "Verbinden Sie Ihre eigenen OpenAPI-kompatiblen externen Tool-Server.", "Connected": "Verbunden", @@ -450,19 +450,19 @@ "Connection lost. Reconnecting...": "Verbindung unterbrochen. Wird wiederhergestellt...", "Connection successful": "Verbindung erfolgreich", "Connection Type": "Verbindungstyp", - "Connections managed through the Admin Panel are recommended for everyday use. Direct connections provide convenient access to your own endpoints, but rely on your browser session to keep requests running, making them better suited to testing and temporary use.": "", + "Connections managed through the Admin Panel are recommended for everyday use. Direct connections provide convenient access to your own endpoints, but rely on your browser session to keep requests running, making them better suited to testing and temporary use.": "Für den täglichen Gebrauch werden Verbindungen empfohlen, die über den Admin-Bereich verwaltet werden. Direkte Verbindungen bieten bequemen Zugriff auf Ihre eigenen Endpunkte, sind aber darauf angewiesen, dass Ihre Browsersitzung die Anfragen am Laufen hält. Daher eignen sie sich eher für Tests und die vorübergehende Nutzung.", "Connections saved successfully": "Verbindungen erfolgreich gespeichert", "Connections settings updated": "Verbindungseinstellungen aktualisiert", "Contact Admin for WebUI Access": "Kontaktieren Sie den Administrator für WebUI-Zugriff", "Content": "Inhalt", "Content Field": "Inhaltsfeld", - "Content lengths (character counts only)": "Content-Längen (nur Zeichen)", + "Content lengths (character counts only)": "Inhaltslängen (nur Zeichenanzahl)", "Content matches": "Treffer im Inhalt", "Context": "Kontext", "Context compacted": "Kontext verdichtet", "Context compaction failed": "Kontextverdichtung fehlgeschlagen", "Context compaction is disabled": "Kontextverdichtung ist deaktiviert", - "Context usage": "", + "Context usage": "Kontextauslastung", "Continue": "Fortfahren", "Continue Response": "Antwort fortsetzen", "Continue with {{provider}}": "Mit {{provider}} fortfahren", @@ -477,9 +477,9 @@ "Copied shared chat URL to clipboard!": "Chat-Freigabe-URL in die Zwischenablage kopiert!", "Copied to clipboard": "In die Zwischenablage kopiert", "Copy": "Kopieren", - "Copy API Key": "API Key kopieren", + "Copy API Key": "API-Schlüssel kopieren", "Copy content": "Inhalt kopieren", - "Copy default": "", + "Copy default": "Standard übernehmen", "Copy Last Code Block": "Letzten Code-Block kopieren", "Copy Last Response": "Letzte Antwort kopieren", "Copy link": "Link kopieren", @@ -491,19 +491,19 @@ "Copy Token": "Token kopieren", "Copy URL": "URL kopieren", "Copying to clipboard was successful!": "Erfolgreich in die Zwischenablage kopiert!", - "Copyright (c)": "", + "Copyright (c)": "Copyright (c)", "CORS must be properly configured by the provider to allow requests from Open WebUI.": "CORS muss vom Anbieter korrekt konfiguriert sein, um Anfragen von Open WebUI zuzulassen.", - "Could not check for updates": "", + "Could not check for updates": "Suche nach Updates fehlgeschlagen", "Could not load release notes.": "Die Versionshinweise konnten nicht geladen werden.", "Could not read file.": "Datei konnte nicht gelesen werden.", - "Could you start by asking me about instances when I procrastinate the most and then give me some suggestions to overcome it?": "", - "Couldn't find your language?": "", + "Could you start by asking me about instances when I procrastinate the most and then give me some suggestions to overcome it?": "Könntest du mich zuerst fragen, in welchen Situationen ich am meisten prokrastiniere, und mir dann Vorschläge machen, wie ich das überwinden kann?", + "Couldn't find your language?": "Ihre Sprache ist nicht dabei?", "CPU": "CPU", "Create": "Erstellen", "Create a knowledge base": "Wissensspeicher erstellen", "Create a model": "Modell erstellen", "Create a new note": "Neue Notiz erstellen", - "Create a reusable terminal skill from this chat.": "", + "Create a reusable terminal skill from this chat.": "Aus diesem Chat einen wiederverwendbaren Terminal-Skill erstellen.", "Create Account": "Konto erstellen", "Create Admin Account": "Admin-Konto erstellen", "Create announcements shown to users in the app.": "Erstellt Ankündigungen, die Benutzern in der App angezeigt werden.", @@ -514,8 +514,8 @@ "Create new key": "Neuen Schlüssel erstellen", "Create Prompt": "Prompt erstellen", "Create scheduled prompts that run automatically on a recurring basis.": "Erstellen Sie geplante Prompts, die automatisch in regelmäßigen Abständen ausgeführt werden.", - "Create skill": "", - "Create skill: create a reusable terminal skill from this chat.": "", + "Create skill": "Skill erstellen", + "Create skill: create a reusable terminal skill from this chat.": "Skill erstellen: aus diesem Chat einen wiederverwendbaren Terminal-Skill erstellen.", "Create your first note from the Create menu.": "Erstellen Sie Ihre erste Notiz über das Menü \"Erstellen\".", "Created": "Erstellt", "Created at": "Erstellt am", @@ -526,9 +526,9 @@ "CSV Import": "CSV-Import", "CSV: Name,Email": "CSV: Name,Email", "Ctrl+Enter to Send": "Strg+Enter zum Senden", - "Cumulative": "", + "Cumulative": "Kumuliert", "Current": "Aktuell", - "Current branch": "", + "Current branch": "Aktueller Zweig", "Current Model": "Aktuelles Modell", "Current streak": "Aktuelle Serie", "Custom": "Benutzerdefiniert", @@ -547,7 +547,7 @@ "Database": "Datenbank", "Datalab Marker API": "Datalab Marker API", "Date is required": "Datum ist erforderlich", - "Date Modified": "Datum geändert", + "Date Modified": "Änderungsdatum", "Day": "Tag", "DD/MM/YYYY": "DD.MM.YYYY", "December": "Dezember", @@ -564,7 +564,7 @@ "Default permissions": "Standardberechtigungen", "Default permissions updated successfully": "Standardberechtigungen erfolgreich aktualisiert", "Default Prompt Suggestions": "Standard-Prompt-Vorschläge", - "Default to 389 or 636 if TLS is enabled": "Standard auf 389 oder 636, wenn TLS aktiviert ist", + "Default to 389 or 636 if TLS is enabled": "Standardmäßig 389 oder 636, wenn TLS aktiviert ist", "Default to ALL": "Standardmäßig ALLE", "Default to memberOf": "Standardmäßig memberOf", "Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.": "Standardmäßig segmentierter Abruf für fokussierte Inhaltsextraktion (empfohlen).", @@ -593,7 +593,7 @@ "Delete note?": "Notiz löschen?", "Delete prompt?": "Prompt löschen?", "Delete skill?": "Skill löschen?", - "delete this link": "diesen Link löschen", + "delete this link": "diesen Link zu löschen", "Delete tool?": "Werkzeug löschen?", "Delete User": "Benutzer löschen", "Delete Version": "Version löschen", @@ -610,15 +610,15 @@ "Describe the edit...": "Beschreiben Sie die Änderung...", "Describe the image...": "Beschreiben Sie das Bild...", "Describe what changed...": "Beschreiben Sie, was sich geändert hat...", - "Describe your knowledge base and objectives": "Beschreiben Sie Ihren Wissensspeicher und Ziele", + "Describe your knowledge base and objectives": "Beschreiben Sie Ihren Wissensspeicher und Ihre Ziele", "Description": "Beschreibung", - "Description ({{language}})": "", + "Description ({{language}})": "Beschreibung ({{language}})", "Deselect": "Abwählen", "Destination": "Ziel", "Detected Variables": "Erkannte Variablen", "Dictate": "Diktieren", "Didn't fully follow instructions": "Anweisungen nicht vollständig befolgt", - "Diff settings": "", + "Diff settings": "Vergleichseinstellungen", "Direct": "Direkt", "Direct Message": "Direktnachricht", "Direct Tool Servers": "Direkte Tool-Server", @@ -642,15 +642,15 @@ "Discover, download, and explore custom tools": "Benutzerdefinierte Werkzeuge entdecken und herunterladen", "Discover, download, and explore model presets": "Modellvorlagen entdecken und herunterladen", "Discussion channel where access is based on groups and permissions": "Diskussionskanal mit gruppenbasiertem Zugriff", - "Dismiss": "", - "Dismiss notification": "", + "Dismiss": "Schließen", + "Dismiss notification": "Benachrichtigung schließen", "Display": "Anzeige", "Do not install functions from sources you do not fully trust.": "Installieren Sie keine Funktionen aus nicht vertrauenswürdigen Quellen.", "Do not install tools from sources you do not fully trust.": "Installieren Sie keine Werkzeuge aus nicht vertrauenswürdigen Quellen.", "Do you want to sync your usage stats with Open WebUI Community?": "Möchten Sie Ihre Nutzungsstatistiken mit der Open WebUI Community synchronisieren?", "Docling": "Docling", "Docling Parameters": "Docling-Parameter", - "Docling Server URL required.": "Docling Server-URL erforderlich.", + "Docling Server URL required.": "Docling-Server-URL erforderlich.", "Document": "Dokument", "Document ID Field": "Dokument-ID-Feld", "Document Intelligence": "Dokumentenintelligenz", @@ -670,10 +670,10 @@ "Download CSV Template": "CSV-Vorlage herunterladen", "Download failed": "Download fehlgeschlagen", "Download Model": "Modell herunterladen", - "Downloading \"{{name}}\"": "", + "Downloading \"{{name}}\"": "Wird heruntergeladen: \"{{name}}\"", "Downloading \"{{searchValue}}\"": "\"{{searchValue}}\" wird heruntergeladen", "Downloading stats...": "Statistiken werden heruntergeladen...", - "Drag and Drop Container": "", + "Drag and Drop Container": "Drag-and-Drop-Bereich", "Drag to reorder": "Zum Umsortieren ziehen", "Draw": "Zeichnen", "Drop any files here to upload": "Dateien zum Hochladen hier ablegen", @@ -687,7 +687,7 @@ "e.g. A filter to remove profanity from text": "z. B. Ein Filter zum Entfernen von Schimpfwörtern", "e.g. about the Roman Empire": "z. B. über das Römische Reich", "e.g. alloy, echo, shimmer": "z. B. alloy, echo, shimmer", - "e.g. Code Review Guidelines": "z. B. Code Review Richtlinien", + "e.g. Code Review Guidelines": "z. B. Code-Review-Richtlinien", "e.g. code-review-guidelines": "z. B. code-review-richtlinien", "e.g. en": "z. B. de", "e.g. My Filter": "z. B. Mein Filter", @@ -695,9 +695,9 @@ "e.g. my_filter": "z. B. mein_filter", "e.g. my_tools": "z. B. meine_werkzeuge", "e.g. pdf, docx, txt": "z. B. pdf, docx, txt", - "e.g. Step-by-step instructions for code reviews": "z. B. Schritt für Schritt Anleitung für ein Code Review", + "e.g. Step-by-step instructions for code reviews": "z. B. Schritt-für-Schritt-Anleitung für Code-Reviews", "e.g. Tell me a fun fact": "z. B. Erzähl mir einen Fun Fact", - "e.g. Tell me a fun fact about the Roman Empire": "z. B. Erzähl mir etwas Interessantes über Rom", + "e.g. Tell me a fun fact about the Roman Empire": "z. B. Erzähl mir einen Fun Fact über das Römische Reich", "e.g. Tools for performing various operations": "z. B. Werkzeuge für verschiedene Operationen", "e.g., 3, 4, 5 (leave blank for default)": "z. B. 3, 4, 5 (leer lassen für Standard)", "e.g., audio/wav,audio/mpeg,video/* (leave blank for defaults)": "z. B. audio/wav,audio/mpeg,video/* (leer für Standard)", @@ -712,26 +712,26 @@ "Edit Knowledge Connection": "Wissensverbindung bearbeiten", "Edit Last Message": "Letzte Nachricht bearbeiten", "Edit Memory": "Erinnerung bearbeiten", - "Edit Prompt": "Prompt editieren", - "Edit Terminal Connection": "Terminal Verbindung bearbeiten", + "Edit Prompt": "Prompt bearbeiten", + "Edit Terminal Connection": "Terminalverbindung bearbeiten", "Edit User": "Benutzer bearbeiten", "Edit User Group": "Benutzergruppe bearbeiten", "Edit User Variable": "Benutzervariable bearbeiten", "Edit webhook": "Webhook bearbeiten", "edited": "bearbeitet", - "Editing language": "", + "Editing language": "Bearbeitungssprache", "Eject": "Auswerfen", "Eject model": "Modell auswerfen", "ElevenLabs": "ElevenLabs", "Email": "E-Mail", - "Embedded content": "", + "Embedded content": "Eingebetteter Inhalt", "Emoji": "Emoji", - "Emoji graphics provided by": "", - "Emojis": "Emoji", + "Emoji graphics provided by": "Emoji-Grafiken bereitgestellt von", + "Emojis": "Emojis", "Empty": "Leer", "Empty message": "Leere Nachricht", "Enable All": "Alle aktivieren", - "Enable all ({{COUNT}})": "", + "Enable all ({{COUNT}})": "Alle aktivieren ({{COUNT}})", "Enable Code Interpreter": "Code-Interpreter aktivieren", "Enable Memory Locking (mlock) to prevent model data from being swapped out of RAM. This option locks the model's working set of pages into RAM, ensuring that they will not be swapped out to disk. This can help maintain performance by avoiding page faults and ensuring fast data access.": "Aktiviert Memory Locking (mlock), um das Auslagern von Modelldaten aus dem RAM zu verhindern. Dies sperrt den Arbeitsspeicherbereich des Modells und sichert schnellen Datenzugriff sowie konstante Leistung.", "Enable Memory Mapping (mmap) to load model data. This option allows the system to use disk storage as an extension of RAM by treating disk files as if they were in RAM. This can improve model performance by allowing for faster data access. However, it may not work correctly with all systems and can consume a significant amount of disk space.": "Aktiviert Memory Mapping (mmap) zum Laden von Modelldaten. Dies nutzt Festplattenspeicher als RAM-Erweiterung, was die Leistung durch schnelleren Datenzugriff verbessern kann, jedoch viel Speicherplatz benötigt und systemabhängig ist.", @@ -753,8 +753,8 @@ "Enter api auth string (e.g. username:password)": "API-Auth-String eingeben (z. B. username:password)", "Enter Application DN": "Anwendungs-DN eingeben", "Enter Application DN Password": "Anwendungs-DN-Passwort eingeben", - "Enter Bing Search V7 Endpoint": "Bing Search V7 Endpunkt eingeben", - "Enter Bing Search V7 Subscription Key": "Bing Search V7 Key eingeben", + "Enter Bing Search V7 Endpoint": "Bing Search V7-Endpunkt eingeben", + "Enter Bing Search V7 Subscription Key": "Bing Search V7 Abonnement-Schlüssel eingeben", "Enter Bocha Search API Key": "Bocha Search API-Schlüssel eingeben", "Enter Brave Search API Key": "Brave Search API-Schlüssel eingeben", "Enter certificate path": "Zertifikatpfad eingeben", @@ -763,10 +763,10 @@ "Enter Chunk Size": "Chunk-Größe eingeben", "Enter Client ID": "Client-ID eingeben", "Enter Client Secret": "Client Secret eingeben", - "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Kommagetrennte \"token:bias_value\"-Paare eingeben (Bsp: 5432:100, 413:-100)", + "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Kommagetrennte \"token:bias_value\"-Paare eingeben (z. B. 5432:100, 413:-100)", "Enter content for the pending user info overlay. Leave empty for default.": "Inhalt für das Overlay 'Ausstehende Aktivierung'. Leer lassen für Standard.", "Enter coordinates (e.g. 51.505, -0.09)": "Koordinaten eingeben (z. B. 51.505, -0.09)", - "Enter Datalab Marker API Base URL": "Datalab Marker API Basis-URL eingeben", + "Enter Datalab Marker API Base URL": "Datalab Marker API-Basis-URL eingeben", "Enter Datalab Marker API Key": "Datalab Marker API-Schlüssel eingeben", "Enter description": "Beschreibung eingeben", "Enter Docling API Key": "Docling API-Schlüssel eingeben", @@ -782,9 +782,9 @@ "Enter External Web Loader URL": "URL für ext. Web-Loader", "Enter External Web Search API Key": "API-Schlüssel für ext. Websuche", "Enter External Web Search URL": "URL für ext. Websuche", - "Enter Firecrawl API Base URL": "Firecrawl API Basis-URL eingeben", + "Enter Firecrawl API Base URL": "Firecrawl API-Basis-URL eingeben", "Enter Firecrawl API Key": "Firecrawl API-Schlüssel eingeben", - "Enter Firecrawl Timeout": "Firecrawl Timeout eingeben", + "Enter Firecrawl Timeout": "Firecrawl-Timeout eingeben", "Enter folder name": "Ordnername eingeben", "Enter function name filter list (e.g. func1, !func2)": "Funktionsnamen-Filterliste eingeben (z. B. func1, !func2)", "Enter GitHub Raw URL": "GitHub-Raw-URL eingeben", @@ -792,7 +792,7 @@ "Enter Google PSE Engine Id": "Google PSE Engine-ID eingeben", "Enter hex color (e.g. #FF0000)": "Hex-Farbe eingeben (z. B. #FF0000)", "Enter Image Size (e.g. 512x512)": "Bildgröße eingeben (z. B. 512x512)", - "Enter Jina API Base URL": "Jina API Base URL eingeben", + "Enter Jina API Base URL": "Jina API-Basis-URL eingeben", "Enter Jina API Key": "Jina API-Schlüssel eingeben", "Enter JSON config (e.g., {\"disable_links\": true})": "JSON-Konfig eingeben (z. B. {\"disable_links\": true})", "Enter Jupyter Password": "Jupyter-Passwort eingeben", @@ -805,7 +805,7 @@ "Enter Microsoft Web IQ API Base URL": "Microsoft Web IQ API-Basis-URL eingeben", "Enter Microsoft Web IQ API Key": "Microsoft Web IQ API-Schlüssel eingeben", "Enter MinerU API Key": "MinerU-API-Schlüssel eingeben", - "Enter Mistral API Base URL": "Mistral API Basis-URL eingeben", + "Enter Mistral API Base URL": "Mistral API-Basis-URL eingeben", "Enter Mistral API Key": "Mistral API-Schlüssel eingeben", "Enter model tag (e.g. {{modelTag}})": "Modell-Tag eingeben (z. B. {{modelTag}})", "Enter Mojeek Search API Key": "Mojeek Search API-Schlüssel eingeben", @@ -814,7 +814,7 @@ "Enter Number of Steps (e.g. 50)": "Anzahl der Schritte eingeben (z. B. 50)", "Enter Ollama Cloud API Key": "Ollama Cloud API-Schlüssel eingeben", "Enter OpenSERP Base URL": "OpenSERP-Basis-URL eingeben", - "Enter PaddleOCR-vl API Base URL": "PaddleOCR-vl API Basis-URL eingeben", + "Enter PaddleOCR-vl API Base URL": "PaddleOCR-vl API-Basis-URL eingeben", "Enter PaddleOCR-vl API Token": "PaddleOCR-vl API-Token eingeben", "Enter Perplexity API Key": "Perplexity API-Schlüssel eingeben", "Enter Perplexity Search API URL": "Perplexity Search API-URL eingeben", @@ -827,8 +827,8 @@ "Enter Score": "Wertung eingeben", "Enter SearchApi API Key": "SearchApi API-Schlüssel eingeben", "Enter SearchApi Engine": "SearchApi Engine eingeben", - "Enter Searxng Query URL": "Searxng Query-URL eingeben", - "Enter Searxng search language": "Searxng-Such Sprache eingeben", + "Enter Searxng Query URL": "Searxng-Abfrage-URL eingeben", + "Enter Searxng search language": "Searxng-Suchsprache eingeben", "Enter Seed": "Seed eingeben", "Enter SerpApi API Key": "SerpApi API-Schlüssel eingeben", "Enter SerpApi Engine": "SerpApi Engine eingeben", @@ -842,7 +842,7 @@ "Enter skill instructions in markdown...": "Skill-Anweisungen in Markdown eingeben...", "Enter Sougou Search API sID": "Sougou Search API sID eingeben", "Enter Sougou Search API SK": "Sougou Search API SK eingeben", - "Enter Staan API Key": "", + "Enter Staan API Key": "Staan API-Schlüssel eingeben", "Enter stop sequence": "Stoppsequenz eingeben", "Enter system prompt": "System-Prompt eingeben", "Enter system prompt here": "System-Prompt hier eingeben", @@ -853,7 +853,7 @@ "Enter Tika Server URL": "Tika Server-URL eingeben", "Enter to Send": "Enter zum Senden", "Enter token threshold": "Token-Schwellenwert eingeben", - "Enter Tokenizer Model": "Tokenizer Modell eingeben", + "Enter Tokenizer Model": "Tokenizer-Modell eingeben", "Enter Top K": "Top K eingeben", "Enter Top K Reranker": "Top K Reranker eingeben", "Enter URL (e.g. http://127.0.0.1:7860/)": "URL eingeben (z. B. http://127.0.0.1:7860/)", @@ -863,9 +863,9 @@ "Enter Yacy Password": "Yacy-Passwort eingeben", "Enter Yacy URL (e.g. http://yacy.example.com:8090)": "Yacy-URL eingeben (z. B. http://yacy.example.com:8090)", "Enter Yacy Username": "Yacy-Benutzername eingeben", - "Enter Yandex Web Search API Key": "Yandex Web-Such API Key eingeben", - "Enter Yandex Web Search URL": "Yandex Web-Such URL eingeben", - "Enter You.com API Key": "You.com API Key eingeben", + "Enter Yandex Web Search API Key": "Yandex Web Search API-Schlüssel eingeben", + "Enter Yandex Web Search URL": "Yandex Web Search URL eingeben", + "Enter You.com API Key": "You.com API-Schlüssel eingeben", "Enter your code here...": "Code hier eingeben...", "Enter your current password": "Aktuelles Passwort eingeben", "Enter Your Email": "Ihre E-Mail eingeben", @@ -889,7 +889,7 @@ "Error accessing Google Drive: {{error}}": "Fehler beim Zugriff auf Google Drive: {{error}}", "Error accessing media devices.": "Fehler beim Zugriff auf Mediengeräte.", "Error deleting model: {{error}}": "Fehler beim Löschen des Modells: {{error}}", - "Error previewing file: {{error}}": "", + "Error previewing file: {{error}}": "Fehler bei der Dateivorschau: {{error}}", "Error starting recording.": "Fehler beim Starten der Aufnahme.", "Error unloading model: {{error}}": "Fehler beim Entladen des Modells: {{error}}", "Error uploading file: {{error}}": "Fehler beim Hochladen der Datei: {{error}}", @@ -908,22 +908,22 @@ "Every {{count}} minutes_other": "Alle {{count}} Minuten", "Every minute": "Jede Minute", "Example": "Beispiel", - "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Bsp: (&(objectClass=inetOrgPerson)(uid=%s))", - "Example: ALL": "Bsp: ALL", - "Example: mail": "Bsp: mail", - "Example: ou=users,dc=foo,dc=example": "Bsp: ou=users,dc=foo,dc=example", - "Example: sAMAccountName or uid or userPrincipalName": "Bsp: sAMAccountName oder uid oder userPrincipalName", + "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Beispiel: (&(objectClass=inetOrgPerson)(uid=%s))", + "Example: ALL": "Beispiel: ALL", + "Example: mail": "Beispiel: mail", + "Example: ou=users,dc=foo,dc=example": "Beispiel: ou=users,dc=foo,dc=example", + "Example: sAMAccountName or uid or userPrincipalName": "Beispiel: sAMAccountName oder uid oder userPrincipalName", "Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "Die Benutzeranzahl Ihrer Lizenz wurde überschritten. Bitte kontaktieren Sie den Support für eine Erweiterung.", "Exclude": "Ausschließen", "Execute code for analysis": "Code zur Analyse ausführen", "Executing {{NAME}}...": "{{NAME}} wird ausgeführt...", "Expand": "Ausklappen", - "Expand input": "", + "Expand input": "Eingabefeld erweitern", "Experience": "Benutzererlebnis", "Experimental": "Experimentell", "Explain": "Erklären", - "Explain options trading": "", - "Explain options trading in simple terms if I'm familiar with buying and selling stocks.": "", + "Explain options trading": "Erklär mir den Optionshandel", + "Explain options trading in simple terms if I'm familiar with buying and selling stocks.": "Erklär mir den Optionshandel in einfachen Worten. Mit dem Kauf und Verkauf von Aktien kenne ich mich aus.", "Explored": "Untersucht", "Exploring": "Untersuche", "Export": "Exportieren", @@ -942,15 +942,15 @@ "External Knowledge Source": "Externe Wissensquelle", "External vectors must be generated with the same embedding model configured in Open WebUI.": "Externe Vektoren müssen mit demselben Embedding-Modell erzeugt werden, das in Open WebUI konfiguriert ist.", "Extract action items from this note.": "Aufgaben aus dieser Notiz extrahieren.", - "Extracted text lines": "", - "Extracting text and comparing…": "", + "Extracted text lines": "Extrahierte Textzeilen", + "Extracting text and comparing…": "Text wird extrahiert und verglichen...", "Failed to add file.": "Hinzufügen der Datei fehlgeschlagen.", "Failed to add members": "Mitglieder konnten nicht hinzugefügt werden", "Failed to archive chat.": "Chat konnte nicht archiviert werden.", "Failed to clear status": "Status konnte nicht geleert werden", "Failed to compare files.": "Dateien konnten nicht verglichen werden.", - "Failed to connect to {{URL}} OpenAPI tool server": "Verbindung zum OpenAPI-Toolserver {{URL}} fehlgeschlagen", - "Failed to connect to {{URL}} terminal server": "Fehler beim Verbinden zum Terminal Server {{URL}}", + "Failed to connect to {{URL}} OpenAPI tool server": "Verbindung zum OpenAPI-Tool-Server {{URL}} fehlgeschlagen", + "Failed to connect to {{URL}} terminal server": "Verbindung zum Terminal-Server {{URL}} fehlgeschlagen", "Failed to copy link": "Link konnte nicht kopiert werden", "Failed to create API Key.": "API-Schlüssel konnte nicht erstellt werden.", "Failed to create chat": "Chat konnte nicht erstellt werden", @@ -971,13 +971,13 @@ "Failed to load Excel/CSV file. Please try downloading it instead.": "Excel/CSV-Datei konnte nicht geladen werden. Bitte versuchen Sie stattdessen, sie herunterzuladen.", "Failed to load file content.": "Dateiinhalt konnte nicht geladen werden.", "Failed to load folder": "Ordner konnte nicht geladen werden", - "Failed to load Interface settings": "Interface Einstellungen konnten nicht geladen werden", + "Failed to load Interface settings": "Oberflächeneinstellungen konnten nicht geladen werden", "Failed to load policy: {{error}}": "Richtlinie konnte nicht geladen werden: {{error}}", "Failed to load PPTX file. Please try downloading it instead.": "PPTX-Datei konnte nicht geladen werden. Versuchen Sie stattdessen, sie herunterzuladen.", "Failed to load usage": "Nutzungsdaten konnten nicht geladen werden", - "Failed to load valves": "", + "Failed to load valves": "Valves konnten nicht geladen werden", "Failed to move chat": "Chat konnte nicht verschoben werden", - "Failed to open database": "", + "Failed to open database": "Datenbank konnte nicht geöffnet werden", "Failed to process URL: {{url}}": "{{url}} konnte nicht verarbeitet werden", "Failed to read clipboard contents": "Zwischenablage konnte nicht gelesen werden", "Failed to refresh terminals: {{error}}": "Terminals konnten nicht aktualisiert werden: {{error}}", @@ -987,22 +987,22 @@ "Failed to save chat variables": "Chat-Variablen konnten nicht gespeichert werden", "Failed to save connections": "Verbindungen konnten nicht gespeichert werden", "Failed to save conversation": "Unterhaltung konnte nicht gespeichert werden", - "Failed to save model": "", + "Failed to save model": "Modell konnte nicht gespeichert werden", "Failed to save models configuration": "Modellkonfiguration konnte nicht gespeichert werden", - "Failed to save policy: {{error}}": "Fehler beim Speichern der Policy: {{error}}", - "Failed to save terminal servers": "Terminal Server konnten nicht gespeichert werden", + "Failed to save policy: {{error}}": "Richtlinie konnte nicht gespeichert werden: {{error}}", + "Failed to save terminal servers": "Terminal-Server konnten nicht gespeichert werden", "Failed to save webhook": "Webhook konnte nicht gespeichert werden", "Failed to search files": "Dateien konnten nicht durchsucht werden", "Failed to unshare chat.": "Chat-Freigabe konnte nicht entfernt werden", "Failed to update settings": "Einstellungen konnten nicht aktualisiert werden", "Failed to update status": "Status konnte nicht aktualisiert werden", "Failed to update webhook": "Webhook konnte nicht aktualisiert werden", - "Failed to upload background image.": "", + "Failed to upload background image.": "Hintergrundbild konnte nicht hochgeladen werden.", "Failed to upload file.": "Datei-Upload fehlgeschlagen.", "Features Permissions": "Funktionsberechtigungen", "February": "Februar", "Feedback": "Feedback", - "Feedback Activity": "Feedback Aktivität", + "Feedback Activity": "Feedback-Aktivität", "Feedback deleted successfully": "Feedback erfolgreich gelöscht", "Feedback Details": "Feedback-Details", "Feel free to add specific details": "Fügen Sie gerne Details hinzu", @@ -1014,7 +1014,7 @@ "File content": "Datei-Inhalt", "File content updated successfully.": "Dateiinhalt erfolgreich aktualisiert.", "File deleted successfully.": "Datei erfolgreich gelöscht.", - "File differences": "", + "File differences": "Dateiunterschiede", "File Mode": "Datei-Modus", "File moved.": "Datei verschoben.", "File name": "Dateiname", @@ -1043,7 +1043,7 @@ "Folder Name": "Ordnername", "Folder name cannot be empty.": "Ordnername darf nicht leer sein.", "Folder name updated successfully": "Ordnername erfolgreich aktualisiert", - "Folder options": "Ordner Optionen", + "Folder options": "Ordneroptionen", "Folder updated successfully": "Ordner erfolgreich aktualisiert", "Folders": "Ordner", "Folders Sharing": "Ordnerfreigabe", @@ -1051,24 +1051,24 @@ "Follow up: {{question}}": "Folgefrage: {{question}}", "Followed instructions perfectly": "Anweisungen perfekt befolgt", "for placeholders": "für Platzhalter", - "for what to do with my kids' art": "", - "Fork": "", - "Fork chat": "", - "Fork the current chat branch into a new chat.": "", - "Fork: fork the current chat branch into a new chat.": "", + "for what to do with my kids' art": "für die Kunstwerke meiner Kinder", + "Fork": "Verzweigen", + "Fork chat": "Chat verzweigen", + "Fork the current chat branch into a new chat.": "Den aktuellen Chat-Zweig als neuen Chat abzweigen.", + "Fork: fork the current chat branch into a new chat.": "Verzweigen: den aktuellen Chat-Zweig als neuen Chat abzweigen.", "Forking chat...": "Chat wird verzweigt...", "Form": "Formular", - "Format Markdown as you type and paste. Turn off to keep Markdown characters and paste plain text. Existing formatting is preserved.": "", - "Formatting": "", + "Format Markdown as you type and paste. Turn off to keep Markdown characters and paste plain text. Existing formatting is preserved.": "Markdown beim Tippen und Einfügen formatieren. Deaktivieren, um Markdown-Zeichen beizubehalten und reinen Text einzufügen. Bestehende Formatierungen bleiben erhalten.", + "Formatting": "Formatierung", "Formatting may be inconsistent from source.": "Formatierung kann von der Quelle abweichen.", "Forward": "Weiterleiten", - "Forward cookies": "", - "Forward cookies from your Open WebUI request to this server.": "", + "Forward cookies": "Cookies weiterleiten", + "Forward cookies from your Open WebUI request to this server.": "Cookies aus Ihrer Open-WebUI-Anfrage an diesen Server weiterleiten.", "Forwards system user OAuth access token to authenticate": "Leitet OAuth-Zugriffstoken des Systembenutzers zur Authentifizierung weiter", "Forwards system user session credentials to authenticate": "Leitet Sitzungsdaten des Systembenutzers zur Authentifizierung weiter", "Fr_day_of_week": "Fr", - "from {{provider}}": "", - "Full access": "", + "from {{provider}}": "von {{provider}}", + "Full access": "Vollzugriff", "Function created successfully": "Funktion erfolgreich erstellt", "Function deleted successfully": "Funktion erfolgreich gelöscht", "Function Description": "Funktionsbeschreibung", @@ -1094,13 +1094,13 @@ "Generate Message Pair": "Nachrichtenpaar generieren", "Generated Image": "Generiertes Bild", "Generated images will appear here": "Generierte Bilder werden hier erscheinen", - "Generating search query": "Generiere Suchanfrage", - "Generating...": "Generiere...", + "Generating search query": "Suchanfrage wird generiert", + "Generating...": "Wird generiert...", "Get information on {{name}} in the UI": "Informationen zu {{name}} in der UI abrufen", "Get started": "Loslegen", "Get started with {{WEBUI_NAME}}": "Loslegen mit {{WEBUI_NAME}}", - "Give me ideas": "", - "give me tips": "", + "Give me ideas": "Gib mir Ideen", + "give me tips": "mit ein paar Tipps", "Global": "Global", "Good Response": "Gute Antwort", "Google": "Google", @@ -1126,10 +1126,10 @@ "Height": "Höhe", "Hello, {{name}}": "Hallo, {{name}}", "Help": "Hilfe", - "Help me study": "", - "Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option.": "", - "Help the community discover great models": "Hilf der Community dabei großartige Modelle zu entdecken", - "Help us translate Open WebUI!": "", + "Help me study": "Hilf mir beim Lernen", + "Help me study vocabulary: write a sentence for me to fill in the blank, and I'll try to pick the correct option.": "Hilf mir beim Vokabellernen: Schreib einen Lückensatz, und ich versuche, die richtige Option auszuwählen.", + "Help the community discover great models": "Helfen Sie der Community, großartige Modelle zu entdecken", + "Help us translate Open WebUI!": "Helfen Sie uns, Open WebUI zu übersetzen!", "Hex Color": "Hex-Farbe", "Hex Color - Leave empty for default color": "Hex-Farbe - Leer lassen für Standard", "Hidden": "Versteckt", @@ -1138,27 +1138,27 @@ "Hide from Sidebar": "Aus Seitenleiste ausblenden", "Hide Hidden Files": "Versteckte Dateien ausblenden", "Hide Model": "Modell verbergen", - "Hide whitespace": "", + "Hide whitespace": "Leerraum ausblenden", "High": "Hoch", "History": "Verlauf", "Home": "Startseite", - "Horizontal Layout": "", + "Horizontal Layout": "Horizontales Layout", "Hourly": "Stündlich", "Hourly Messages": "Stündliche Nachrichten", "How can I help you today?": "Wie kann ich Ihnen heute helfen?", "How would you rate this response?": "Wie bewerten Sie diese Antwort?", "HTML": "HTML", - "HTML Preview": "", + "HTML Preview": "HTML-Vorschau", "http://localhost:8000": "http://localhost:8000", "https://mineru.net/api/v4": "https://mineru.net/api/v4", - "I acknowledge that I have read and I understand the implications of my action. I am aware of the risks associated with executing arbitrary code and I have verified the trustworthiness of the source.": "Ich bestätige, dass ich die Auswirkungen meiner Handlung verstanden habe. Ich bin mir der Risiken bei der Ausführung von beliebigem Code bewusst und habe die Vertrauenswürdigkeit der Quelle überprüft.", + "I acknowledge that I have read and I understand the implications of my action. I am aware of the risks associated with executing arbitrary code and I have verified the trustworthiness of the source.": "Ich bestätige, dass ich dies gelesen habe und die Auswirkungen meiner Handlung verstehe. Ich bin mir der Risiken bei der Ausführung von beliebigem Code bewusst und habe die Vertrauenswürdigkeit der Quelle überprüft.", "ID": "ID", "ID cannot contain \":\" or \"|\" characters": "ID darf keine \":\" oder \"|\" Zeichen enthalten", "ID copied to clipboard": "ID in die Zwischenablage kopiert", "Identity audit": "Identitätsprüfung", "Idle only": "Nur im Leerlauf", "Idle Timeout": "Inaktivitäts-Timeout", - "if I'm familiar with buying and selling stocks": "", + "if I'm familiar with buying and selling stocks": "für jemanden, der sich mit Aktienkauf und -verkauf auskennt", "Image": "Bild", "Image Generation": "Bildgenerierung", "Image Max Compression Size": "Max. Bildkompressionsgröße", @@ -1195,10 +1195,10 @@ "Instructions": "Anweisungen", "Integrations": "Integrationen", "Interface Settings Access": "Zugriff auf Oberflächeneinstellungen", - "Invalid background image.": "", + "Invalid background image.": "Ungültiges Hintergrundbild.", "Invalid file format.": "Ungültiges Dateiformat.", "Invalid format.": "Ungültiges Format.", - "Invalid JSON": "", + "Invalid JSON": "Ungültiges JSON", "Invalid JSON file": "Ungültige JSON-Datei", "Invalid JSON format": "Ungültiges JSON-Format", "Invalid JSON format for ComfyUI Edit Workflow.": "Ungültiges JSON-Format für ComfyUI-Bearbeitungsworkflow.", @@ -1213,7 +1213,7 @@ "join our Discord for help.": "Treten Sie unserem Discord bei, um Hilfe zu erhalten.", "JSON": "JSON", "JSON Base64": "JSON Base64", - "JSON parse error: {{error}}": "", + "JSON parse error: {{error}}": "JSON-Parsefehler: {{error}}", "JSON Preview": "JSON-Vorschau", "JSON Spec": "JSON-Spezifikation", "July": "Juli", @@ -1253,7 +1253,7 @@ "Learn more about Open Terminal": "Mehr über Open Terminal erfahren", "Learn more about OpenAPI tool servers.": "Erfahren Sie mehr über OpenAPI-Tool-Server.", "Learn more about Voxtral transcription.": "Erfahren Sie mehr über Voxtral-Transkription.", - "Leave a public review for {{modelName}}": "Hinterlasse eine öffentliche Bewertung für {{modelName}}", + "Leave a public review for {{modelName}}": "Hinterlassen Sie eine öffentliche Bewertung für {{modelName}}", "Leave empty for no compression": "Leer lassen für keine Kompression", "Leave empty for unlimited": "Leer lassen für unbegrenzt", "Leave empty to include all models from \"{{url}}\" endpoint": "Leer lassen, um alle Modelle vom Endpunkt \"{{url}}\" einzuschließen", @@ -1265,26 +1265,26 @@ "Leave empty to use the default prompt, or enter a custom prompt": "Leer lassen, um den Standard-Prompt zu verwenden, oder geben Sie einen eigenen Prompt ein", "Legacy": "Veraltet", "lexical": "lexikalisch", - "License Error": "", - "license purchased by": "", + "License Error": "Lizenzfehler", + "license purchased by": "Lizenz erworben von", "Lifecycle JSON": "Lifecycle-JSON", "Lifetime tokens": "Token insgesamt", - "Lift List": "Liste anheben", + "Lift List": "Listeneinzug verringern", "Light": "Hell", "List": "Liste", - "Listening...": "Höre zu...", + "Listening...": "Hört zu...", "LiteLLM": "LiteLLM", "Live": "Live", "llama.cpp": "llama.cpp", "LLMs can make mistakes. Verify important information.": "KI-Modelle können Fehler machen. Überprüfen Sie wichtige Informationen.", "LM Studio": "LM Studio", "Load Model": "Modell laden", - "Loaded": "geladen", - "Loading": "", - "Loading Kokoro.js...": "Lade Kokoro.js...", + "Loaded": "Geladen", + "Loading": "Wird geladen", + "Loading Kokoro.js...": "Kokoro.js wird geladen...", "Loading policy...": "Richtlinie wird geladen...", "Loading release notes...": "Versionshinweise werden geladen...", - "Loading...": "Lade...", + "Loading...": "Wird geladen...", "local": "lokal", "Local": "Lokal", "Location": "Standort", @@ -1309,12 +1309,12 @@ "Mark all as read": "Alle als gelesen markieren", "Mark as unread": "Als ungelesen markieren", "Markdown": "Markdown", - "Market": "", - "Matching tabs: {{count}}_one": "", - "Matching tabs: {{count}}_other": "", - "Max Snippets": "", + "Market": "Markt", + "Matching tabs: {{count}}_one": "Passender Tab: {{count}}", + "Matching tabs: {{count}}_other": "Passende Tabs: {{count}}", + "Max Snippets": "Max. Ausschnitte", "Max tokens to retrieve (1024-32768, default 8192)": "Max. Token zum Abrufen (1024-32768, Standard 8192)", - "Maximum extra snippets returned per result. Set to 0 to disable them.": "", + "Maximum extra snippets returned per result. Set to 0 to disable them.": "Maximale Anzahl zusätzlicher Ausschnitte pro Ergebnis. Auf 0 setzen, um sie zu deaktivieren.", "Maximum number of files per folder is {{max}}.": "Die maximale Anzahl der Dateien pro Ordner ist {{max}}.", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es können maximal 3 Modelle gleichzeitig heruntergeladen werden. Bitte versuchen Sie es später erneut.", "May": "Mai", @@ -1326,7 +1326,7 @@ "Members": "Mitglieder", "Members added successfully": "Mitglieder erfolgreich hinzugefügt", "Memories": "Erinnerungen", - "Memory": "Erinnerungen", + "Memory": "Arbeitsspeicher", "Memory added successfully": "Erinnerung erfolgreich hinzugefügt", "Memory cleared successfully": "Erinnerungen erfolgreich gelöscht", "Memory deleted successfully": "Erinnerung erfolgreich gelöscht", @@ -1368,7 +1368,7 @@ "Model filesystem path detected. Model shortname is required for update, cannot continue.": "Modell-Dateisystempfad erkannt. Modellkurzname ist für das Update erforderlich; Vorgang kann nicht fortgesetzt werden.", "Model Filtering": "Modellfilterung", "Model ID": "Modell-ID", - "Model ID cannot contain whitespace.": "", + "Model ID cannot contain whitespace.": "Die Modell-ID darf keine Leerzeichen enthalten.", "Model ID is already added": "Modell-ID wurde bereits hinzugefügt", "Model ID is required.": "Modell-ID ist erforderlich.", "Model IDs": "Modell-IDs", @@ -1385,7 +1385,7 @@ "Model order saved successfully": "Reihenfolge der Modelle erfolgreich gespeichert", "Model Params": "Modell-Parameter", "Model Permissions": "Modellberechtigungen", - "model profile": "", + "model profile": "Modellprofil", "Model providers": "Modellanbieter", "Model removed from pinned models": "Modell von den angehefteten Modellen entfernt", "Model removed from selected models": "Modell von den ausgewählten Modellen entfernt", @@ -1393,17 +1393,17 @@ "Model unloaded successfully": "Modell erfolgreich entladen", "Model updated successfully": "Modell erfolgreich aktualisiert", "Model Usage": "Modell-Nutzung", - "Model: show or switch the current model.": "", + "Model: show or switch the current model.": "Modell: aktuelles Modell anzeigen oder wechseln.", "Model(s) do not support file upload": "Modell(e) unterstützen keinen Dateiupload", "Modelfile Content": "Modelfile-Inhalt", - "modelfile profile": "", + "modelfile profile": "Modelfile-Profil", "Models": "Modelle", "Models Access": "Modellzugriff", "Models configuration saved successfully": "Modellkonfiguration erfolgreich gespeichert", "Models imported successfully": "Modelle erfolgreich importiert", "Models Public Sharing": "Öffentliche Freigabe von Modellen", "Models Sharing": "Modelle teilen", - "Modified": "", + "Modified": "Geändert", "Mojeek": "Mojeek", "Monday – Friday": "Montag – Freitag", "Month": "Monat", @@ -1417,9 +1417,9 @@ "Multipart Upload": "Multipart-Upload", "Mute": "Stummschalten", "Muted": "Stumm", - "My Terminal": "Meine Terminals", + "My Terminal": "Mein Terminal", "Name": "Name", - "Name and description are required": "", + "Name and description are required": "Name und Beschreibung sind erforderlich", "Name and ID are required, please fill them out": "Name und ID sind erforderlich, bitte füllen Sie diese aus", "Name is required": "Name ist erforderlich", "Name your knowledge base": "Benennen Sie Ihren Wissensspeicher", @@ -1429,7 +1429,7 @@ "Navigate to Previous Chat": "Zum vorherigen Chat wechseln", "Never": "Nie", "New": "Neu", - "New Button": "Neuer Button", + "New Button": "Neue Schaltfläche", "New calendar": "Neuer Kalender", "New Calendar": "Neuer Kalender", "New chat": "Neuer Chat", @@ -1469,7 +1469,7 @@ "No chats found for this user.": "Keine Chats für diesen Benutzer gefunden.", "No chats found.": "Keine Chats gefunden.", "No content": "Kein Inhalt", - "No content available": "", + "No content available": "Kein Inhalt verfügbar", "No content found": "Kein Inhalt gefunden", "No content to speak": "Kein Inhalt zum Vorlesen", "No conversation to save": "Keine Unterhaltung zum Speichern vorhanden", @@ -1488,7 +1488,7 @@ "No folders": "Keine Ordner", "No functions found": "Keine Funktionen gefunden", "No groups found": "Keine Gruppen gefunden", - "No history available": "Keine History verfügbar", + "No history available": "Kein Verlauf verfügbar", "No HTML, CSS, or JavaScript content found.": "Keine HTML-, CSS- oder JavaScript-Inhalte gefunden.", "No inference engine with management support found": "Keine Inferenz-Engine mit Verwaltungsunterstützung gefunden", "No kernel": "Kein Kernel", @@ -1520,10 +1520,10 @@ "No source available": "Keine Quelle verfügbar", "No sources found": "Keine Quellen gefunden", "No suggestion prompts": "Keine Vorschlags-Prompts", - "No Terminal connection configured.": "Keine Terminal Verbindung konfiguriert.", - "No terminal connections configured.": "Keine Terminal Verbindungen konfiguriert.", - "No text differences": "", - "No tool server connections configured.": "Keine Werkzeug-Server Verbindungen konfiguriert.", + "No Terminal connection configured.": "Keine Terminalverbindung konfiguriert.", + "No terminal connections configured.": "Keine Terminalverbindungen konfiguriert.", + "No text differences": "Keine Textunterschiede", + "No tool server connections configured.": "Keine Tool-Server-Verbindungen konfiguriert.", "No tools accessible": "Keine Werkzeuge zugänglich", "No tools found": "Keine Werkzeuge gefunden", "No usage data found": "Keine Nutzungsdaten gefunden", @@ -1554,10 +1554,10 @@ "OAuth ID": "OAuth-ID", "OAuth Resource Parameter": "OAuth-Ressourcenparameter", "OAuth Scopes": "OAuth-Scopes", - "OAuth Server URL": "OAuth Server URL", + "OAuth Server URL": "OAuth-Server-URL", "OAuth session disconnected": "OAuth-Sitzung getrennt", "October": "Oktober", - "of a website's sticky header": "", + "of a website's sticky header": "für einen Sticky Header einer Website", "Off": "Aus", "Okay, Let's Go!": "Okay, los geht's!", "OLED Dark": "OLED Dunkel", @@ -1595,13 +1595,13 @@ "Open Model Selector": "Modell-Selektor öffnen", "Open note": "Notiz öffnen", "Open Settings": "Einstellungen öffnen", - "Open settings.": "", + "Open settings.": "Einstellungen öffnen.", "Open Sidebar": "Seitenleiste öffnen", - "Open terminal": "", + "Open terminal": "Terminal öffnen", "Open the changelog modal after sign-in when enabled.": "Zeigt nach der Anmeldung die Versionshinweise an, wenn aktiviert.", "Open User Profile Menu": "Benutzerprofilmenü öffnen", "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI kann Werkzeuge verwenden, die von jedem OpenAPI-Server bereitgestellt werden.", - "Open WebUI version": "Open WebUI Version", + "Open WebUI version": "Open-WebUI-Version", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Die installierte Open-WebUI-Version (v{{OPEN_WEBUI_VERSION}}) ist niedriger als die erforderliche Version (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API Key is required.": "OpenAI-API-Schlüssel ist erforderlich.", @@ -1614,15 +1614,15 @@ "or": "oder", "Orchestrator": "Orchestrator", "Ordered List": "Nummerierte Liste", - "Original": "", + "Original": "Original", "Other": "Andere", "out of": "von", "Output": "Ausgabe", "OUTPUT": "AUSGABE", - "Overcome procrastination": "", + "Overcome procrastination": "Hilf mir, Prokrastination zu überwinden", "Overview": "Übersicht", "PaddleOCR-vl": "PaddleOCR-vl", - "PaddleOCR-vl API URL required.": "PaddleOCR-vl API URL erforderlich.", + "PaddleOCR-vl API URL required.": "PaddleOCR-vl API-URL erforderlich.", "page": "Seite", "Page": "Seite", "Parameters": "Parameter", @@ -1661,7 +1661,7 @@ "Plain text (.md)": "Klartext (.md)", "Plain text (.txt)": "Klartext (.txt)", "Playground": "Testumgebung", - "Playground Chat": "", + "Playground Chat": "Testumgebungs-Chat", "Please carefully review the following warnings:": "Bitte lesen Sie die folgenden Warnungen sorgfältig durch:", "Please connect all required integrations before sending a message": "Bitte verbinden Sie alle erforderlichen Integrationen, bevor Sie eine Nachricht senden", "Please do not close the settings page while loading the model.": "Bitte schließen Sie die Einstellungsseite nicht, während das Modell lädt.", @@ -1682,9 +1682,9 @@ "Please select a valid JSON file": "Bitte wählen Sie eine gültige JSON-Datei aus", "Please select at least one user for Direct Message channel.": "Bitte wählen Sie mindestens einen Benutzer für den Direktnachrichten-Kanal aus.", "Please wait until all files are uploaded.": "Bitte warten Sie, bis alle Dateien hochgeladen sind.", - "PNG, JPEG, WebP, or GIF. Up to 5 MiB and 25 megapixels.": "", + "PNG, JPEG, WebP, or GIF. Up to 5 MiB and 25 megapixels.": "PNG, JPEG, WebP oder GIF. Bis zu 5 MiB und 25 Megapixel.", "Policy changes apply to newly provisioned terminals. Refresh matching terminals to apply them to existing terminals.": "Änderungen an der Richtlinie gelten für neu bereitgestellte Terminals. Aktualisieren Sie die passenden Terminals, um die Änderungen auch dort zu übernehmen.", - "Policy ID": "Policy-ID", + "Policy ID": "Richtlinien-ID", "Policy ID is required": "Richtlinien-ID ist erforderlich", "Policy is still loading": "Die Richtlinie wird noch geladen", "Ports": "Ports", @@ -1709,7 +1709,7 @@ "Previous version": "Vorherige Version", "Private": "Privat", "Private conversation between selected users": "Private Unterhaltung zwischen ausgewählten Benutzern", - "Production version updated": "Produktiv-Version updated", + "Production version updated": "Produktivversion aktualisiert", "Profile": "Profil", "Prompt": "Prompt", "Prompt Content": "Prompt-Inhalt", @@ -1726,15 +1726,15 @@ "Pull \"{{searchValue}}\" from Ollama.com": "\"{{searchValue}}\" von Ollama.com laden", "Pull a model from Ollama.com": "Ein Modell von Ollama.com laden", "Pull Model": "Modell laden", - "Pyodide file browser": "Pyodide Datei Explorer", + "Pyodide file browser": "Pyodide-Dateibrowser", "Quality": "Qualität", - "Query failed": "", - "Querying": "Frage ab...", - "Queued messages": "", + "Query failed": "Abfrage fehlgeschlagen", + "Querying": "Abfrage läuft...", + "Queued messages": "Nachrichten in der Warteschlange", "Quick Actions": "Schnellaktionen", "Ran {{COUNT}} analyses": "{{COUNT}} Analysen durchgeführt", "Ran {{COUNT}} analysis": "{{COUNT}} Analyse durchgeführt", - "Rate {{rating}} out of 10": "Bewerte {{rating}} von 10", + "Rate {{rating}} out of 10": "Mit {{rating}} von 10 bewerten", "Rating": "Bewertung", "Read": "Lesen", "Read Aloud": "Vorlesen", @@ -1742,9 +1742,9 @@ "Read only": "Schreibgeschützt", "Read Only": "Nur lesend", "Read the docs": "Zur Dokumentation", - "Read-only": "", + "Read-only": "Schreibgeschützt", "Read-Only Access": "Nur lesender Zugriff", - "Reason": "Nachdenken", + "Reason": "Grund", "Reasoning text...": "Reasoning-Text...", "Rebuild knowledge file, knowledge search, and memory vectors using the current embedding model.": "Erstellt die Vektoren für Wissensdateien, Wissenssuche und Erinnerungen mit dem aktuellen Embedding-Modell neu.", "Receives matching events across the instance, including system/config events and events associated with any user.": "Empfängt passende Ereignisse instanzweit, einschließlich System-/Konfigurationsereignissen und Ereignissen, die einem beliebigen Benutzer zugeordnet sind.", @@ -1766,11 +1766,11 @@ "Refused when it shouldn't have": "Fälschlicherweise abgelehnt", "Regenerate": "Neu generieren", "Regenerate Response": "Antwort neu generieren", - "Region and language of the search results, e.g. en-us.": "", + "Region and language of the search results, e.g. en-us.": "Region und Sprache der Suchergebnisse, z. B. en-us.", "Register Again": "Erneut registrieren", "Register Client": "Client registrieren", "Registered": "Registriert", - "registered to": "", + "registered to": "registriert für", "Registration failed": "Registrierung fehlgeschlagen", "Registration successful": "Registrierung erfolgreich", "Reindex Embedding Data": "Embedding-Daten neu indizieren", @@ -1781,7 +1781,7 @@ "Reminder": "Erinnerung", "Remove": "Entfernen", "Remove {{MODELID}} from list.": "{{MODELID}} von der Liste entfernen.", - "Remove action": "Action entfernen", + "Remove action": "Aktion entfernen", "Remove file": "Datei entfernen", "Remove File": "Datei entfernen", "Remove from favorites": "Von Favoriten entfernen", @@ -1793,9 +1793,9 @@ "Removing {{count}} stale files..._other": "{{count}} veraltete Dateien werden entfernt...", "Rename": "Umbenennen", "Renamed to {{name}}": "In {{name}} umbenannt", - "Reorder": "", - "Repeat": "Wiederholen", - "Replace": "", + "Reorder": "Neu anordnen", + "Repeat": "Wiederholung", + "Replace": "Ersetzen", "Reply": "Antworten", "Reply in Thread": "Im Thread antworten", "Reply to thread...": "Im Thread antworten...", @@ -1812,7 +1812,7 @@ "Reset to Defaults": "Auf Standardwerte zurücksetzen", "Reset view": "Ansicht zurücksetzen", "Reset zoom": "Zoom zurücksetzen", - "Resize panel": "", + "Resize panel": "Bereichsgröße ändern", "Response": "Antwort", "Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Antwortbenachrichtigungen können nicht aktiviert werden, da die Website-Berechtigungen verweigert wurden. Bitte erteilen Sie in Ihren Browser-Einstellungen den erforderlichen Zugriff.", "Responses": "Responses", @@ -1830,10 +1830,10 @@ "Run": "Ausführen", "Run AI on your own terms. Connect any model, extend with code, and protect what matters without compromise. Your models, your data, your machine, wherever you open it.": "KI zu Ihren Bedingungen. Binden Sie jedes beliebige Modell ein, erweitern Sie es mit eigenem Code und schützen Sie kompromisslos, was Ihnen wichtig ist. Ihre Modelle, Ihre Daten, Ihr Rechner – wo immer Sie es öffnen.", "Run All": "Alle starten", - "Run cell (⌘+Enter)": "", + "Run cell (⌘+Enter)": "Zelle ausführen (⌘+Enter)", "Run now": "Jetzt ausführen", "Run Now": "Jetzt ausführen", - "Run tools without asking for approval.": "", + "Run tools without asking for approval.": "Werkzeuge ohne Bestätigung ausführen.", "Running": "Läuft", "Running Open WebUI for a team?": "Sie betreiben Open WebUI für ein Team?", "Running...": "Läuft...", @@ -1847,14 +1847,14 @@ "Save Chat": "Chat speichern", "Saved": "Gespeichert", "Saving...": "Wird gespeichert...", - "Schedule": "Planen", + "Schedule": "Zeitplan", "Scheduled time must be in the future": "Geplante Zeit muss in der Zukunft liegen", - "Screen Share": "", + "Screen Share": "Bildschirmfreigabe", "Scroll to bottom": "Nach unten scrollen", "Scroll to Top": "Zum Anfang scrollen", "Search": "Suchen", "Search a model": "Ein Modell suchen", - "Search actions": "Actions durchsuchen", + "Search actions": "Aktionen durchsuchen", "Search all emojis": "Alle Emojis durchsuchen", "Search Automations": "Automatisierungen suchen", "Search channels": "Kanäle durchsuchen", @@ -1882,19 +1882,19 @@ "Search skills": "Skills durchsuchen", "Search Skills": "Skills durchsuchen", "Search the internet": "Das Internet durchsuchen", - "Search tools": "Tools durchsuchen", + "Search tools": "Werkzeuge durchsuchen", "Search Tools": "Werkzeuge durchsuchen...", - "Search translations": "", + "Search translations": "Übersetzungen durchsuchen", "Search users or groups": "Benutzer oder Gruppen suchen", "Searched {{count}} sites": "{{count}} Seiten durchsucht", "Searching": "Suche...", "Searching \"{{searchQuery}}\"": "Suche nach \"{{searchQuery}}\"", "Searching Knowledge for \"{{searchQuery}}\"": "Suche im Wissen nach \"{{searchQuery}}\"", - "Searching the web": "Durchsuche das Web...", + "Searching the web": "Web wird durchsucht...", "See readme.md for instructions": "Siehe readme.md für Anweisungen", "Select": "Auswählen", "Select {{modelName}} model": "Modell {{modelName}} auswählen", - "Select {{name}}": "", + "Select {{name}}": "{{name}} auswählen", "Select a base model (e.g. llama3, gpt-4o)": "Wählen Sie ein Basismodell (z. B. llama3, gpt-4o)", "Select a conversation to preview": "Wählen Sie eine Unterhaltung für die Vorschau", "Select a engine": "Wählen Sie eine Engine", @@ -1972,7 +1972,7 @@ "settings configured": "Einstellungen konfiguriert", "Settings Permissions": "Berechtigungen für Einstellungen", "Settings saved successfully!": "Einstellungen erfolgreich gespeichert!", - "Settings: open settings.": "", + "Settings: open settings.": "Einstellungen: Einstellungen öffnen.", "settings.admin.analytics.title": "Analyse", "settings.admin.audio.additionalParameters.description": "Zusätzliche OpenAI-kompatible TTS-Anfrageparameter als JSON eingeben.", "settings.admin.audio.additionalParameters.label": "Weitere Parameter", @@ -1983,7 +1983,7 @@ "settings.admin.audio.outputFormat.label": "Ausgabeformat", "settings.admin.audio.requestFormat.description": "Legt fest, wie Audiodaten an den OpenAI-kompatiblen Endpunkt gesendet werden.", "settings.admin.audio.requestFormat.label": "Anfrageformat", - "settings.admin.audio.responseSplitting.description": "Steuert, wie Nachrichtentext für TTS-Anfragen geteilt wird. 'Punctuation' teilt nach Sätzen, 'paragraphs' nach Absätzen und 'none' behält die Nachricht als Ganzes.", + "settings.admin.audio.responseSplitting.description": "Steuert, wie Nachrichtentext für TTS-Anfragen geteilt wird. 'Punctuation' teilt nach Sätzen, 'Paragraphs' nach Absätzen und 'Keine' behält die Nachricht als Ganzes.", "settings.admin.audio.responseSplitting.label": "Aufteilung der Antwort", "settings.admin.audio.sections.speechToText.title": "Sprache-zu-Text", "settings.admin.audio.sections.textToSpeech.title": "Text-zu-Sprache", @@ -2020,7 +2020,7 @@ "settings.admin.audio.useChatCompletionsApi.description": "Verwenden Sie den Endpunkt /v1/chat/completions statt /v1/audio/transcriptions für potenziell bessere Genauigkeit.", "settings.admin.audio.useChatCompletionsApi.label": "Chat Completions API verwenden", "settings.admin.authentication.adminContactEmail.description": "E-Mail-Adresse, die angezeigt wird, solange ein Konto auf Freigabe wartet.", - "settings.admin.authentication.adminContactEmail.label": "Admin Kontakt E-Mail", + "settings.admin.authentication.adminContactEmail.label": "Admin-Kontakt-E-Mail", "settings.admin.authentication.adminDetails.description": "Zeigt die Kontaktdaten des Administrators an, solange ein Konto auf Freigabe wartet.", "settings.admin.authentication.adminDetails.label": "Administrator-Kontaktdaten", "settings.admin.authentication.adminRoles.description": "Rollen des Anbieters, die Administratorrechte gewähren.", @@ -2032,10 +2032,10 @@ "settings.admin.authentication.allowedRoles.description": "Rollen des Anbieters, die sich anmelden dürfen.", "settings.admin.authentication.allowedRoles.label": "Erlaubte Rollen", "settings.admin.authentication.apiKeyEndpointRestrictions.description": "Beschränkt API-Schlüssel auf die konfigurierten Endpunkte.", - "settings.admin.authentication.apiKeyEndpointRestrictions.label": "API-Schlüssel Endpunkteinschränkungen", + "settings.admin.authentication.apiKeyEndpointRestrictions.label": "Endpunkteinschränkungen für API-Schlüssel", "settings.admin.authentication.apiKeys.description": "Erlaubt Benutzern, API-Schlüssel für den programmatischen Zugriff zu erstellen.", "settings.admin.authentication.apiKeys.label": "API-Schlüssel", - "settings.admin.authentication.applicationDn.description": "Bind DN für die Verzeichnissuche.", + "settings.admin.authentication.applicationDn.description": "Bind-DN für die Verzeichnissuche.", "settings.admin.authentication.applicationDn.label": "Anwendungs-DN", "settings.admin.authentication.applicationDnPassword.description": "Passwort für den Bind-DN.", "settings.admin.authentication.applicationDnPassword.label": "Anwendungs-DN-Passwort", @@ -2052,9 +2052,9 @@ "settings.admin.authentication.ciphers.description": "Liste der TLS-Cipher für LDAP-Verbindungen.", "settings.admin.authentication.ciphers.label": "Chiffren", "settings.admin.authentication.clientId.description": "Client-ID vom OAuth-Anbieter.", - "settings.admin.authentication.clientId.label": "Client ID", + "settings.admin.authentication.clientId.label": "Client-ID", "settings.admin.authentication.clientSecret.description": "Client-Secret vom OAuth-Anbieter.", - "settings.admin.authentication.clientSecret.label": "Client Secret", + "settings.admin.authentication.clientSecret.label": "Client-Secret", "settings.admin.authentication.defaultGroup.description": "Gruppe, der neue Benutzer standardmäßig zugewiesen werden.", "settings.admin.authentication.defaultGroup.label": "Standardgruppe", "settings.admin.authentication.defaultUserRole.description": "Rolle, die neuen Benutzern beim Erstellen eines Kontos zugewiesen wird.", @@ -2081,8 +2081,8 @@ "settings.admin.authentication.label.label": "Label", "settings.admin.authentication.ldap.description": "Erlaubt Benutzern die Anmeldung über ein LDAP-Verzeichnis.", "settings.admin.authentication.ldap.label": "LDAP", - "settings.admin.authentication.loginForm.description": "", - "settings.admin.authentication.loginForm.label": "", + "settings.admin.authentication.loginForm.description": "Zeigt die Anmeldung mit E-Mail und Passwort auf der Anmeldeseite an. Richten Sie vor dem Deaktivieren SSO oder LDAP ein. Das Deaktivieren sperrt auch lokale Registrierungen; der API-Zugriff per Passwort bleibt unverändert.", + "settings.admin.authentication.loginForm.label": "Anmeldeformular", "settings.admin.authentication.mergeAccountsByEmail.description": "Verknüpft OAuth-Anmeldungen mit vorhandenen Konten derselben E-Mail-Adresse.", "settings.admin.authentication.mergeAccountsByEmail.label": "Konten anhand der E-Mail-Adresse zusammenführen", "settings.admin.authentication.newSignUps.description": "Erlaubt neuen Benutzern, ein Konto zu erstellen.", @@ -2170,8 +2170,8 @@ "settings.admin.connections.cacheBaseModelList.label": "Basismodell-Liste cachen", "settings.admin.connections.directConnections.description": "Direktverbindungen erlauben Benutzern die Verbindung zu eigenen OpenAI-kompatiblen API-Endpunkten.", "settings.admin.connections.directConnections.label": "Direktverbindungen", - "settings.admin.connections.directIntegrations.description": "", - "settings.admin.connections.directIntegrations.label": "", + "settings.admin.connections.directIntegrations.description": "Zeigt den Tab \"Integrationen\" für Benutzer mit der Berechtigung, eigene Werkzeug- und Terminalverbindungen zu verwalten, einschließlich Administratoren. Das Ausblenden deaktiviert keine bestehenden Verbindungen.", + "settings.admin.connections.directIntegrations.label": "Direkte Integrationen", "settings.admin.connections.manageOllamaApiConnections.description": "Probleme beim Zugriff auf Ollama?", "settings.admin.connections.manageOllamaApiConnections.label": "Ollama-API-Verbindungen verwalten", "settings.admin.connections.manageOpenaiApiConnections.label": "OpenAI-API-Verbindungen verwalten", @@ -2244,7 +2244,7 @@ "settings.admin.documents.embeddingBatchSize.description": "Anzahl der Elemente, die pro Embedding-Batch verarbeitet werden.", "settings.admin.documents.embeddingBatchSize.label": "Embedding-Batch-Größe", "settings.admin.documents.embeddingConcurrentRequests.description": "Maximale Anzahl gleichzeitiger Embedding-Anfragen. 0 bedeutet unbegrenzt.", - "settings.admin.documents.embeddingConcurrentRequests.label": "Gleichzeitige Embedding Anfragen", + "settings.admin.documents.embeddingConcurrentRequests.label": "Gleichzeitige Embedding-Anfragen", "settings.admin.documents.embeddingModel.description": "Modell, das die Embeddings erzeugt. Nach einer Änderung muss der Wissensspeicher neu indexiert werden.", "settings.admin.documents.embeddingModel.label": "Embedding-Modell", "settings.admin.documents.embeddingModelEngine.description": "Anbieter, der die Embeddings für Dokumente erzeugt.", @@ -2256,7 +2256,7 @@ "settings.admin.documents.externalDocumentLoaderApiKey.description": "API-Schlüssel, der an den externen Dokumenten-Loader gesendet wird.", "settings.admin.documents.externalDocumentLoaderApiKey.label": "API-Schlüssel", "settings.admin.documents.fileExtensions.description": "Kommagetrennte Dateiendungen, die MinerU verarbeiten soll.", - "settings.admin.documents.fileExtensions.label": "Dateierweiterungen", + "settings.admin.documents.fileExtensions.label": "Dateiendungen", "settings.admin.documents.forceOcr.description": "Führt die Texterkennung auf allen PDF-Seiten aus, auch auf Seiten mit eingebettetem Text.", "settings.admin.documents.forceOcr.label": "OCR erzwingen", "settings.admin.documents.formatLines.description": "Formatiert Zeilen, um Inline-Formeln und Textstile zu erkennen.", @@ -2271,9 +2271,9 @@ "settings.admin.documents.hybridSearch.description": "Kombiniert semantische und stichwortbasierte Suche.", "settings.admin.documents.hybridSearch.label": "Hybride Suche", "settings.admin.documents.imageCompressionHeight.description": "Höhe in Pixeln, auf die Bilder komprimiert werden. Leer lassen, um nicht zu komprimieren.", - "settings.admin.documents.imageCompressionHeight.label": "Bildkompression Höhe", + "settings.admin.documents.imageCompressionHeight.label": "Bildkompressionshöhe", "settings.admin.documents.imageCompressionWidth.description": "Breite in Pixeln, auf die Bilder komprimiert werden. Leer lassen, um nicht zu komprimieren.", - "settings.admin.documents.imageCompressionWidth.label": "Bildkompression Breite", + "settings.admin.documents.imageCompressionWidth.label": "Bildkompressionsbreite", "settings.admin.documents.markdownHeaderTextSplitter.description": "Teilt Dokumente an Markdown-Überschriften auf, bevor nach Zeichen oder Token aufgeteilt wird.", "settings.admin.documents.markdownHeaderTextSplitter.label": "Markdown-Header-Text-Splitter", "settings.admin.documents.maxUploadCount.description": "Maximale Anzahl Dateien, die gleichzeitig im Chat verwendet werden können.", @@ -2307,7 +2307,7 @@ "settings.admin.documents.pdfExtractImagesOcr.description": "Extrahiert Bilder aus PDFs, damit OCR auch reine Bildseiten verarbeiten kann.", "settings.admin.documents.pdfExtractImagesOcr.label": "Bilder aus PDFs extrahieren (OCR)", "settings.admin.documents.pdfLoaderMode.description": "Der Seitenmodus erzeugt ein Dokument pro Seite. Der Einzelmodus hält die Seiten zusammen, sodass Chunks über Seitengrenzen hinweg gebildet werden können.", - "settings.admin.documents.pdfLoaderMode.label": "PDF Loader Modus", + "settings.admin.documents.pdfLoaderMode.label": "PDF-Loader-Modus", "settings.admin.documents.ragExternalRerankerApiKey.description": "API-Schlüssel, der an den externen Reranker gesendet wird.", "settings.admin.documents.ragExternalRerankerApiKey.label": "API-Schlüssel", "settings.admin.documents.ragExternalRerankerUrl.description": "Endpunkt des externen Rerankers.", @@ -2349,11 +2349,11 @@ "settings.admin.documents.tikaServerVersion.label": "Tika-Server-Version", "settings.admin.documents.title": "Dokumente", "settings.admin.documents.tokenizerModel.description": "Tokenizer-Modell für die tokenbasierte Aufteilung mit Transformern.", - "settings.admin.documents.tokenizerModel.label": "Tokenizer Modell", + "settings.admin.documents.tokenizerModel.label": "Tokenizer-Modell", "settings.admin.documents.topK.description": "Maximale Anzahl abgerufener Chunks, die an das Modell übergeben werden.", "settings.admin.documents.topK.label": "Top-K", "settings.admin.documents.topKReranker.description": "Maximale Anzahl an Ergebnissen der hybriden Suche, die an den Reranker gesendet werden.", - "settings.admin.documents.topKReranker.label": "Top-K Reranker", + "settings.admin.documents.topKReranker.label": "Top-K-Reranker", "settings.admin.documents.updateEmbeddingModel.label": "Embedding-Modell aktualisieren", "settings.admin.documents.useBase64.description": "Sendet PDFs als Base64-Daten-URLs, statt sie zuvor hochzuladen.", "settings.admin.documents.useBase64.label": "Base64 verwenden", @@ -2403,10 +2403,10 @@ "settings.admin.general.sections.ui.title": "Benutzeroberfläche", "settings.admin.general.seeWhatSNew.label": "Entdecken Sie, was neu ist", "settings.admin.general.title": "Allgemein", - "settings.admin.general.translations.addTranslation.label": "", - "settings.admin.general.translations.uiTranslations.label": "", + "settings.admin.general.translations.addTranslation.label": "Übersetzung hinzufügen", + "settings.admin.general.translations.uiTranslations.label": "Oberflächenübersetzungen", "settings.admin.general.userStatus.description": "Zeigt Statusinformationen zu Benutzern in der App an.", - "settings.admin.general.userStatus.label": "Nutzerstatus", + "settings.admin.general.userStatus.label": "Benutzerstatus", "settings.admin.general.userWebhooks.description": "Erlaubt Benutzern, Webhooks in ihrem Konto einzurichten.", "settings.admin.general.userWebhooks.label": "Benutzer-Webhooks", "settings.admin.general.version.label": "Version", @@ -2427,9 +2427,9 @@ "settings.admin.images.comfyuiComfyuiWorkflow.label": "ComfyUI-Workflow", "settings.admin.images.editingWorkflowNodes.description": "Ordnet die Workflow-Node-Eingaben für die Bildbearbeitung zu.", "settings.admin.images.editingWorkflowNodes.label": "ComfyUI-Workflow-Nodes", - "settings.admin.images.editWorkflowJsonContent.label": "workflow.json Inhalt bearbeiten", + "settings.admin.images.editWorkflowJsonContent.label": "Inhalt von workflow.json bearbeiten", "settings.admin.images.geminiEndpointMethod.description": "Wählt die aufzurufende Methode des Gemini-Endpunkts.", - "settings.admin.images.geminiEndpointMethod.label": "Gemini Endpunkt-Methode", + "settings.admin.images.geminiEndpointMethod.label": "Gemini-Endpunkt-Methode", "settings.admin.images.generationWorkflowNodes.description": "Ordnet die Workflow-Node-Eingaben für die Bildgenerierung zu.", "settings.admin.images.generationWorkflowNodes.label": "ComfyUI-Workflow-Nodes", "settings.admin.images.imageEdit.description": "Erlaubt Benutzern, vorhandene Bilder zu bearbeiten.", @@ -2469,14 +2469,14 @@ "settings.admin.images.serverConnectionVerified.label": "Serververbindung überprüft", "settings.admin.images.steps.label": "Schritte", "settings.admin.images.title": "Bilder", - "settings.admin.images.verifyConnection.label": "", + "settings.admin.images.verifyConnection.label": "Verbindung prüfen", "settings.admin.integrations.addConnection.label": "Verbindung hinzufügen", "settings.admin.integrations.externalKnowledge.addConnection.label": "Verbindung hinzufügen", "settings.admin.integrations.externalKnowledge.title": "Externe Wissensquellen", - "settings.admin.integrations.externalToolServers.label": "Externe Werkzeug-Server", + "settings.admin.integrations.externalToolServers.label": "Externe Tool-Server", "settings.admin.integrations.mcp.label": "MCP", "settings.admin.integrations.openApi.label": "OpenAPI", - "settings.admin.integrations.openTerminal.label": "Terminal öffnen", + "settings.admin.integrations.openTerminal.label": "Open Terminal", "settings.admin.integrations.sections.knowledge.title": "Wissen", "settings.admin.integrations.sections.terminal.title": "Terminal", "settings.admin.integrations.sections.tools.title": "Werkzeuge", @@ -2503,7 +2503,7 @@ "settings.admin.interface.imagePromptGenerationPrompt.label": "Prompt für Bild-Prompt-Generierung", "settings.admin.interface.localTaskModel.label": "Lokales Aufgabenmodell", "settings.admin.interface.promptTemplate.description": "Legt das Verhalten für gesprochene Unterhaltungen fest.", - "settings.admin.interface.promptTemplate.label": "Prompt Vorlage", + "settings.admin.interface.promptTemplate.label": "Prompt-Vorlage", "settings.admin.interface.queryGenerationPrompt.description": "Gemeinsamer Prompt für das Umformulieren von Wissens- und Websuchanfragen.", "settings.admin.interface.queryGenerationPrompt.label": "Abfrage-Generierungs-Prompt", "settings.admin.interface.retainedMessages.description": "Prozentsatz der neuesten Nachrichten, die erhalten bleiben, nachdem ältere Nachrichten zusammengefasst wurden.", @@ -2529,12 +2529,12 @@ "settings.admin.interface.tokenCap.label": "Token-Obergrenze", "settings.admin.interface.tokenThreshold.description": "Ältere Nachrichten werden zusammengefasst, wenn der geschätzte Kontext dieses Token-Limit überschreitet.", "settings.admin.interface.tokenThreshold.label": "Token-Schwellenwert", - "settings.admin.interface.toolPermissions.description": "Zeigt \"Full access\" und \"Ask for approval\" im Menü der Chat-Eingabe an.", + "settings.admin.interface.toolPermissions.description": "Zeigt \"Vollzugriff\" und \"Um Bestätigung bitten\" im Menü der Chat-Eingabe an.", "settings.admin.interface.toolPermissions.label": "Werkzeug-Berechtigungen", "settings.admin.interface.toolsFunctionCallingPrompt.description": "Gibt vor, wie der Assistent Werkzeug- und Funktionsaufrufe formatiert.", "settings.admin.interface.toolsFunctionCallingPrompt.label": "Prompt für Werkzeug-Funktionsaufrufe", "settings.admin.interface.voiceModePrompt.description": "Wendet spezielle Anweisungen an, solange der Sprachmodus aktiv ist.", - "settings.admin.interface.voiceModePrompt.label": "Anruf-Modus Prompt", + "settings.admin.interface.voiceModePrompt.label": "Prompt für Sprachmodus", "settings.admin.interface.webSearchQueryGeneration.description": "Formuliert Benutzeranfragen in Websuchanfragen um.", "settings.admin.interface.webSearchQueryGeneration.label": "Suchanfragen-Generierung", "settings.admin.models.builtinTools.automations.description": "Geplante Automatisierungen erstellen und verwalten", @@ -2551,7 +2551,7 @@ "settings.admin.models.builtinTools.files.label": "Dateien", "settings.admin.models.builtinTools.imageGeneration.description": "Bilder generieren und bearbeiten", "settings.admin.models.builtinTools.imageGeneration.label": "Bildgenerierung", - "settings.admin.models.builtinTools.knowledge.description": "Wissensbasen durchsuchen und abfragen", + "settings.admin.models.builtinTools.knowledge.description": "Wissensspeicher durchsuchen und abfragen", "settings.admin.models.builtinTools.knowledge.label": "Wissensspeicher", "settings.admin.models.builtinTools.memory.description": "Erinnerungen des Benutzers durchsuchen und verwalten", "settings.admin.models.builtinTools.memory.label": "Erinnerungen", @@ -2602,10 +2602,10 @@ "settings.admin.models.defaultFeatures.title": "Standardfunktionen", "settings.admin.models.defaultFeatures.webSearch.description": "Modell kann das Web nach Informationen durchsuchen", "settings.admin.models.defaultFeatures.webSearch.label": "Websuche", - "settings.admin.models.defaults.modelCapabilities.label": "Modell Fähigkeiten", + "settings.admin.models.defaults.modelCapabilities.label": "Modellfähigkeiten", "settings.admin.models.defaults.modelDefaults.label": "Modell-Standardwerte", - "settings.admin.models.defaults.modelParameters.label": "Modell Parameter", - "settings.admin.models.defaults.promptSuggestions.label": "Prompt Vorschläge", + "settings.admin.models.defaults.modelParameters.label": "Modellparameter", + "settings.admin.models.defaults.promptSuggestions.label": "Prompt-Vorschläge", "settings.admin.models.disableAllModels.label": "Alle deaktivieren", "settings.admin.models.enableAllModels.label": "Alle aktivieren", "settings.admin.models.exportModels.label": "Exportieren", @@ -2639,7 +2639,7 @@ "settings.admin.subagents.systemPrompt.description": "Leer lassen, um den integrierten Standard zu verwenden.", "settings.admin.subagents.systemPrompt.label": "System-Prompt", "settings.admin.subagents.title": "Sub-Agents", - "settings.admin.web.bingSearchV7Endpoint.label": "Bing Search V7 Endpunkt", + "settings.admin.web.bingSearchV7Endpoint.label": "Bing Search V7-Endpunkt", "settings.admin.web.bingSearchV7SubscriptionKey.label": "Bing Search V7 Abonnement-Schlüssel", "settings.admin.web.bochaSearchApiKey.label": "Bocha Search API-Schlüssel", "settings.admin.web.braveSearchApiKey.label": "Brave Search API-Schlüssel", @@ -2650,7 +2650,7 @@ "settings.admin.web.concurrentRequests.description": "Begrenzt die parallelen Anfragen des Web-Loaders.", "settings.admin.web.concurrentRequests.label": "Gleichzeitige Anfragen", "settings.admin.web.contextTokens.label": "Kontext-Token", - "settings.admin.web.ddgsBackend.label": "DDGS Backend", + "settings.admin.web.ddgsBackend.label": "DDGS-Backend", "settings.admin.web.domainFilterList.description": "Beschränkt Domains anhand einer kommagetrennten Liste oder schließt sie aus.", "settings.admin.web.domainFilterList.label": "Domain-Filterliste", "settings.admin.web.exaApiKey.label": "Exa API-Schlüssel", @@ -2660,18 +2660,18 @@ "settings.admin.web.externalWebSearchUrl.label": "URL für ext. Websuche", "settings.admin.web.fetchUrlContentLengthLimit.description": "Maximale Zeichenanzahl für Fetch URL-Inhalte. Leer lassen für unbegrenzt.", "settings.admin.web.fetchUrlContentLengthLimit.label": "Max. Inhaltslänge für Fetch URL", - "settings.admin.web.firecrawlApiBaseUrl.label": "Firecrawl API Basis-URL", + "settings.admin.web.firecrawlApiBaseUrl.label": "Firecrawl API-Basis-URL", "settings.admin.web.firecrawlApiKey.label": "Firecrawl API-Schlüssel", "settings.admin.web.firecrawlTimeoutS.label": "Firecrawl-Timeout (s)", "settings.admin.web.googlePseApiKey.label": "Google PSE API-Schlüssel", "settings.admin.web.googlePseEngineId.label": "Google PSE Engine-ID", - "settings.admin.web.jinaApiBaseUrl.label": "Jina API Base URL", + "settings.admin.web.jinaApiBaseUrl.label": "Jina API-Basis-URL", "settings.admin.web.jinaApiKey.label": "Jina-API-Schlüssel", "settings.admin.web.kagiSearchApiKey.label": "Kagi Search API-Schlüssel", "settings.admin.web.language.label": "Sprache", "settings.admin.web.linkupApiKey.label": "Linkup-API-Schlüssel", - "settings.admin.web.maxContentLength.description": "", - "settings.admin.web.maxContentLength.label": "", + "settings.admin.web.maxContentLength.description": "Maximale Zeichenanzahl pro Exa-Suchergebnis. Leer lassen für kein Limit.", + "settings.admin.web.maxContentLength.label": "Max. Inhaltslänge", "settings.admin.web.microsoftWebIqApiBaseUrl.label": "Microsoft Web IQ API-Basis-URL", "settings.admin.web.microsoftWebIqApiKey.label": "Microsoft Web IQ API-Schlüssel", "settings.admin.web.mojeekSearchApiKey.label": "Mojeek Search API-Schlüssel", @@ -2693,7 +2693,7 @@ "settings.admin.web.searxngQueryUrl.label": "Searxng-Abfrage-URL", "settings.admin.web.searxngSearchLanguageAllEnEsDeFrEtc.label": "SearxNG-Suchsprache (all, en, es, de, fr, etc.)", "settings.admin.web.sections.loader.title": "Loader", - "settings.admin.web.sections.search.title": "Suchen", + "settings.admin.web.sections.search.title": "Suche", "settings.admin.web.serpapiApiKey.label": "SerpApi-API-Schlüssel", "settings.admin.web.serpapiEngine.label": "SerpApi-Engine", "settings.admin.web.serperApiKey.label": "Serper-API-Schlüssel", @@ -2725,10 +2725,10 @@ "settings.admin.web.yacyInstanceUrl.label": "Yacy-Instanz-URL", "settings.admin.web.yacyPassword.label": "Yacy-Passwort", "settings.admin.web.yacyUsername.label": "Yacy-Benutzername", - "settings.admin.web.yandexWebSearchApiKey.label": "Yandex Web Search API Key", + "settings.admin.web.yandexWebSearchApiKey.label": "Yandex Web Search API-Schlüssel", "settings.admin.web.yandexWebSearchConfig.label": "Yandex Web Search Konfiguration", "settings.admin.web.yandexWebSearchUrl.label": "Yandex Web Search URL", - "settings.admin.web.youComApiKey.label": "You.com API Key", + "settings.admin.web.youComApiKey.label": "You.com API-Schlüssel", "settings.admin.web.youtubeLanguage.description": "Bevorzugte Sprachcodes für Transkripte, durch Kommas getrennt.", "settings.admin.web.youtubeLanguage.label": "YouTube-Sprache", "settings.admin.web.youtubeProxyUrl.description": "Proxy-URL für Anfragen des YouTube-Loaders.", @@ -2798,7 +2798,7 @@ "settings.personal.connections.addConnection.label": "Verbindung hinzufügen", "settings.personal.connections.sections.directConnections.title": "Direktverbindungen", "settings.personal.connections.title": "Verbindungen", - "settings.personal.dataControls.archiveAll.label": "Alle Archivieren", + "settings.personal.dataControls.archiveAll.label": "Alle archivieren", "settings.personal.dataControls.archiveAllChats.description": "Verschiebt nach Bestätigung alle Chats ins Archiv.", "settings.personal.dataControls.archiveAllChats.label": "Alle Chats archivieren", "settings.personal.dataControls.deleteAllChats.description": "Löscht nach Bestätigung alle Chats endgültig.", @@ -2820,34 +2820,34 @@ "settings.personal.general.modelParameters.label": "Modellparameter", "settings.personal.general.parameters.contextCompactionThreshold.description": "Legt einen modellspezifischen Token-Schwellenwert für die Kontextverdichtung fest. Ist er gesetzt, ersetzt er den globalen Schwellenwert bis zur globalen Obergrenze.", "settings.personal.general.parameters.contextCompactionThreshold.label": "Schwellenwert für Kontextverdichtung", - "settings.personal.general.parameters.format.label": "", - "settings.personal.general.parameters.frequencyPenalty.label": "", - "settings.personal.general.parameters.functionCalling.description": "Der native Modus (Standard) nutzt die integrierten Funktionsaufruf-Fähigkeiten des Modells. Der Legacy-Modus funktioniert mit einer größeren Bandbreite an Modellen, indem Werkzeuge einmalig vor der Ausführung per Prompt-Injektion aufgerufen werden.", + "settings.personal.general.parameters.format.label": "format", + "settings.personal.general.parameters.frequencyPenalty.label": "frequency_penalty", + "settings.personal.general.parameters.functionCalling.description": "Der Modus \"Nativ\" (Standard) nutzt die integrierten Werkzeugaufruf-Fähigkeiten des Modells. Der Modus \"Veraltet\" funktioniert mit mehr Modellen, da Werkzeuge einmalig vor der Ausführung per Prompt-Injection aufgerufen werden.", "settings.personal.general.parameters.functionCalling.label": "Funktionsaufruf", - "settings.personal.general.parameters.keepAlive.label": "", - "settings.personal.general.parameters.logitBias.label": "", - "settings.personal.general.parameters.maxTokens.label": "", - "settings.personal.general.parameters.minP.label": "", - "settings.personal.general.parameters.mirostat.label": "", - "settings.personal.general.parameters.mirostatEta.label": "", - "settings.personal.general.parameters.mirostatTau.label": "", - "settings.personal.general.parameters.numBatch.label": "", - "settings.personal.general.parameters.numCtx.label": "", - "settings.personal.general.parameters.numGpu.label": "", - "settings.personal.general.parameters.numKeep.label": "", - "settings.personal.general.parameters.numThread.label": "", - "settings.personal.general.parameters.ollama.description": "Diese Option aktiviert die Reasoning-Funktion in Ollama, wodurch das Modell vor der Antwort nachdenken kann. Wenn aktiviert, nimmt sich das Modell einen Moment Zeit, um den Kontext zu verarbeiten und eine durchdachtere Antwort zu generieren.", + "settings.personal.general.parameters.keepAlive.label": "keep_alive", + "settings.personal.general.parameters.logitBias.label": "logit_bias", + "settings.personal.general.parameters.maxTokens.label": "max_tokens", + "settings.personal.general.parameters.minP.label": "min_p", + "settings.personal.general.parameters.mirostat.label": "mirostat", + "settings.personal.general.parameters.mirostatEta.label": "mirostat_eta", + "settings.personal.general.parameters.mirostatTau.label": "mirostat_tau", + "settings.personal.general.parameters.numBatch.label": "num_batch", + "settings.personal.general.parameters.numCtx.label": "num_ctx", + "settings.personal.general.parameters.numGpu.label": "num_gpu", + "settings.personal.general.parameters.numKeep.label": "num_keep", + "settings.personal.general.parameters.numThread.label": "num_thread", + "settings.personal.general.parameters.ollama.description": "Diese Option aktiviert oder deaktiviert die Reasoning-Funktion in Ollama, mit der das Modell vor der Antwort nachdenken kann. Wenn sie aktiviert ist, nimmt sich das Modell einen Moment Zeit, um den Gesprächskontext zu verarbeiten und eine durchdachtere Antwort zu generieren.", "settings.personal.general.parameters.ollama.label": "Ollama", - "settings.personal.general.parameters.presencePenalty.label": "", - "settings.personal.general.parameters.reasoningEffort.description": "Beschränkt den Aufwand für Reasoning-Modelle. Nur anwendbar auf Modelle bestimmter Anbieter, die 'Reasoning Effort' unterstützen.", + "settings.personal.general.parameters.presencePenalty.label": "presence_penalty", + "settings.personal.general.parameters.reasoningEffort.description": "Begrenzt den Reasoning-Aufwand von Reasoning-Modellen. Gilt nur für Reasoning-Modelle bestimmter Anbieter, die Reasoning Effort unterstützen.", "settings.personal.general.parameters.reasoningEffort.label": "Reasoning Effort", - "settings.personal.general.parameters.reasoningTags.description": "Aktivieren, deaktivieren oder passen Sie Reasoning-Tags an. \"Aktiviert\" nutzt Standard-Tags, \"Deaktiviert\" schaltet sie aus, \"Benutzerdefiniert\" erlaubt eigene Start/End-Tags.", + "settings.personal.general.parameters.reasoningTags.description": "Aktiviert, deaktiviert oder konfiguriert die vom Modell verwendeten Reasoning-Tags. \"Aktiviert\" nutzt die Standard-Tags, \"Deaktiviert\" schaltet Reasoning-Tags aus und mit \"Benutzerdefiniert\" können Sie eigene Start- und End-Tags festlegen.", "settings.personal.general.parameters.reasoningTags.label": "Reasoning-Tags", - "settings.personal.general.parameters.repeatLastN.label": "", - "settings.personal.general.parameters.repeatPenalty.label": "", + "settings.personal.general.parameters.repeatLastN.label": "repeat_last_n", + "settings.personal.general.parameters.repeatPenalty.label": "repeat_penalty", "settings.personal.general.parameters.seed.description": "Legt den Startwert (Seed) für die Zufallszahlengenerierung fest. Mit einem festen Wert erzeugt das Modell für denselben Prompt immer denselben Text.", "settings.personal.general.parameters.seed.label": "Seed", - "settings.personal.general.parameters.stopSequence.description": "Legt die zu verwendenden Stoppsequenzen fest. Wenn dieses Muster erkannt wird, stoppt das LLM die Textgenerierung. Mehrere Stoppmuster können durch separate Stopp-Parameter in einer Modelldatei angegeben werden.", + "settings.personal.general.parameters.stopSequence.description": "Legt die zu verwendenden Stoppsequenzen fest. Wenn dieses Muster erkannt wird, beendet das LLM die Textgenerierung und gibt das Ergebnis zurück. Mehrere Stoppmuster können durch separate Stopp-Parameter in einem Modelfile angegeben werden.", "settings.personal.general.parameters.stopSequence.label": "Stoppsequenz", "settings.personal.general.parameters.streamChatResponse.description": "Wenn aktiviert, antwortet das Modell in Echtzeit auf jede Chat-Nachricht. Dieser Modus ist nützlich für Live-Chats, kann jedoch die Leistung auf langsamerer Hardware beeinträchtigen.", "settings.personal.general.parameters.streamChatResponse.label": "Chat-Antwort streamen", @@ -2855,12 +2855,12 @@ "settings.personal.general.parameters.streamDeltaChunkSize.label": "Stream-Delta-Chunk-Größe", "settings.personal.general.parameters.temperature.description": "Die Temperatur des Modells. Eine Erhöhung führt zu kreativeren Antworten.", "settings.personal.general.parameters.temperature.label": "Temperatur", - "settings.personal.general.parameters.tfsZ.label": "", - "settings.personal.general.parameters.think.label": "", - "settings.personal.general.parameters.topK.label": "", - "settings.personal.general.parameters.topP.label": "", - "settings.personal.general.parameters.useMlock.label": "", - "settings.personal.general.parameters.useMmap.label": "", + "settings.personal.general.parameters.tfsZ.label": "tfs_z", + "settings.personal.general.parameters.think.label": "think", + "settings.personal.general.parameters.topK.label": "top_k", + "settings.personal.general.parameters.topP.label": "top_p", + "settings.personal.general.parameters.useMlock.label": "use_mlock", + "settings.personal.general.parameters.useMmap.label": "use_mmap", "settings.personal.general.sections.advancedParameters.title": "Erweiterte Parameter", "settings.personal.general.sections.systemPrompt.description": "Legt den Standard-System-Prompt für neue Chats fest.", "settings.personal.general.sections.systemPrompt.title": "System-Prompt", @@ -2909,7 +2909,7 @@ "settings.personal.interface.displayTheUsernameInsteadOfYouInTheChat.description": "Zeigt in den Sprechblasen Ihren Benutzernamen statt \"Du\" an.", "settings.personal.interface.displayTheUsernameInsteadOfYouInTheChat.label": "Benutzernamen statt \"Du\" im Chat anzeigen", "settings.personal.interface.enableMessageQueue.description": "Stellt ausgehende Nachrichten in eine Warteschlange, statt laufende Antworten zu unterbrechen.", - "settings.personal.interface.enableMessageQueue.label": "Nachrichten Queue aktivieren", + "settings.personal.interface.enableMessageQueue.label": "Nachrichtenwarteschlange aktivieren", "settings.personal.interface.enterKeyBehavior.description": "Legt fest, ob die Eingabetaste sofort sendet oder Strg+Eingabe erforderlich ist.", "settings.personal.interface.enterKeyBehavior.label": "Eingabetasten-Verhalten", "settings.personal.interface.fadeEffectForStreamingText.description": "Blendet Text während des Streamings sanft ein.", @@ -2947,7 +2947,7 @@ "settings.personal.interface.promptAutocompletion.description": "Schlägt beim Schreiben von Prompts Vervollständigungen vor.", "settings.personal.interface.promptAutocompletion.label": "Prompt-Autovervollständigung", "settings.personal.interface.regenerateMenu.description": "Zeigt bei Antworten des Assistenten das Menü zum erneuten Generieren an.", - "settings.personal.interface.regenerateMenu.label": "Menü neu generieren", + "settings.personal.interface.regenerateMenu.label": "Menü zum Neugenerieren", "settings.personal.interface.renderMarkdownInAssistantMessages.description": "Stellt Markdown in Antworten des Assistenten formatiert dar.", "settings.personal.interface.renderMarkdownInAssistantMessages.label": "Markdown in Assistentennachrichten rendern", "settings.personal.interface.renderMarkdownInPreviews.description": "Stellt Markdown in Vorschauen und kompakten Ansichten formatiert dar.", @@ -3001,7 +3001,7 @@ "settings.personal.personalization.savedMemories.label": "Gespeicherte Erinnerungen", "settings.personal.personalization.sections.memory.title": "Erinnerungen", "settings.personal.personalization.title": "Personalisierung", - "settings.personal.shortcuts.acceptAutocomplete.label": "", + "settings.personal.shortcuts.acceptAutocomplete.label": "Autovervollständigung akzeptieren\nZur Prompt-Variable springen", "settings.personal.shortcuts.addPrompt.label": "Benutzerdefinierten Prompt hinzufügen", "settings.personal.shortcuts.allowToolCall.label": "Werkzeugaufruf erlauben", "settings.personal.shortcuts.attachFile.label": "Datei aus Wissensspeicher anhängen", @@ -3037,10 +3037,10 @@ "settings.personal.tools.addConnection.description": "Verbinden Sie Ihre eigenen OpenAPI-kompatiblen externen Tool-Server.", "settings.personal.tools.addConnection.label": "Verbindung hinzufügen", "settings.personal.tools.openApi.label": "OpenAPI", - "settings.personal.tools.sections.externalToolServers.title": "Externe Werkzeug-Server", + "settings.personal.tools.sections.externalToolServers.title": "Externe Tool-Server", "settings.personal.tools.terminals.addConnection.description": "Verbinden Sie sich mit Open-Terminal-Instanzen, um Dateien zu durchsuchen und sie als dauerhaft verfügbare Werkzeuge zu nutzen. Es kann immer nur eine aktiv sein.", "settings.personal.tools.terminals.addConnection.label": "Verbindung hinzufügen", - "settings.personal.tools.terminals.sections.openTerminal.title": "Terminal öffnen", + "settings.personal.tools.terminals.sections.openTerminal.title": "Open Terminal", "settings.personal.tools.title": "Integrationen", "settings.personal.usage.sections.activity.title": "Aktivität", "settings.personal.usage.sections.activityInsights.title": "Aktivitätsübersicht", @@ -3057,20 +3057,20 @@ "Shared Chats": "Geteilte Chats", "Shared with you": "Mit Ihnen geteilt", "Sharing Permissions": "Freigabeberechtigungen", - "Shell": "", - "Shorten older messages so this chat can keep going.": "", + "Shell": "Shell", + "Shorten older messages so this chat can keep going.": "Ältere Nachrichten kürzen, damit dieser Chat fortgesetzt werden kann.", "Show": "Anzeigen", - "Show \"What's New\" Modal on Login": "\"Was gibt's Neues\"-Fenster beim Anmelden anzeigen", + "Show \"What's New\" Modal on Login": "\"Neuigkeiten\"-Fenster beim Anmelden anzeigen", "Show All": "Alle anzeigen", "Show all ({{COUNT}} characters)": "Alle anzeigen ({{COUNT}} Zeichen)", "Show Files": "Dateien anzeigen", "Show Hidden Files": "Versteckte Dateien anzeigen", "Show image preview": "Bildvorschau anzeigen", - "Show me a code snippet": "", - "Show me a code snippet of a website's sticky header in CSS and JavaScript.": "", + "Show me a code snippet": "Zeig mir ein Code-Beispiel", + "Show me a code snippet of a website's sticky header in CSS and JavaScript.": "Zeig mir ein Code-Beispiel für einen Sticky Header einer Website in CSS und JavaScript.", "Show Model": "Modell anzeigen", "Show more": "Mehr anzeigen", - "Show or switch the current model.": "", + "Show or switch the current model.": "Aktuelles Modell anzeigen oder wechseln.", "Show Shortcuts": "Tastenkombinationen anzeigen", "Show the floating quick-action toolbar in chat.": "Zeigt die schwebende Leiste für Schnellaktionen im Chat an.", "Show your support!": "Zeigen Sie Ihre Unterstützung!", @@ -3083,9 +3083,9 @@ "Sign up": "Registrieren", "Sign up to {{WEBUI_NAME}}": "Bei {{WEBUI_NAME}} registrieren", "Signing in to {{WEBUI_NAME}}": "Anmeldung bei {{WEBUI_NAME}}...", - "simultaneous sub-agents": "Sub-Agents", + "simultaneous sub-agents": "gleichzeitige Sub-Agents", "Single": "Einzeln", - "Sink List": "Sink-Liste", + "Sink List": "Listeneinzug erhöhen", "Size": "Größe", "sk-1234": "sk-1234", "Skill created successfully": "Skill erfolgreich erstellt", @@ -3102,8 +3102,8 @@ "Skills Public Sharing": "Öffentliches Teilen von Skills", "Skills Sharing": "Teilen von Skills", "Skip to main content": "Zum Hauptinhalt springen", - "Slim requires external services for embeddings, vector storage, and document extraction. Basic text files can be read locally.": "", - "Slim requires external speech providers. Local speech models and audio conversion are unavailable.": "", + "Slim requires external services for embeddings, vector storage, and document extraction. Basic text files can be read locally.": "Slim benötigt externe Dienste für Embeddings, Vektorspeicherung und Dokumentextraktion. Einfache Textdateien können lokal gelesen werden.", + "Slim requires external speech providers. Local speech models and audio conversion are unavailable.": "Slim benötigt externe Sprachanbieter. Lokale Sprachmodelle und Audiokonvertierung sind nicht verfügbar.", "Something went wrong :/": "Etwas ist schiefgelaufen :/", "Sonar": "Sonar", "Sonar Deep Research": "Sonar Deep Research", @@ -3114,30 +3114,30 @@ "Source": "Quelle", "Specific users or groups": "Bestimmte Benutzer oder Gruppen", "Speech recognition error: {{error}}": "Spracherkennungsfehler: {{error}}", - "Speech-to-Text Language": "Speech-to-Text Sprache", + "Speech-to-Text Language": "Sprache für Spracherkennung", "Sponsor on GitHub": "Auf GitHub sponsern", - "Staan API Key": "", + "Staan API Key": "Staan API-Schlüssel", "Start a new conversation": "Neue Unterhaltung beginnen", "Start of the channel": "Beginn des Kanals", "Start Tag": "Start-Tag", "Start the chat to use this terminal.": "Starten Sie den Chat, um dieses Terminal zu verwenden.", "Starting in {{count}} minutes_one": "Beginnt in {{count}} Minute", "Starting in {{count}} minutes_other": "Beginnt in {{count}} Minuten", - "Starting in 1 minute": "Beginnt in 1 minute", - "Starting kernel...": "Kernel starten...", + "Starting in 1 minute": "Beginnt in 1 Minute", + "Starting kernel...": "Kernel wird gestartet...", "Starting now": "Startet jetzt", "Status": "Status", "Status cleared successfully": "Status erfolgreich gelöscht", "Status updated successfully": "Status erfolgreich aktualisiert", - "Status: check what is running in this chat.": "", + "Status: check what is running in this chat.": "Status: prüfen, was in diesem Chat gerade läuft.", "STDOUT/STDERR": "STDOUT/STDERR", "Stop": "Stopp", - "Stop before each tool call until you allow or deny it.": "", + "Stop before each tool call until you allow or deny it.": "Vor jedem Werkzeugaufruf anhalten, bis Sie ihn erlauben oder ablehnen.", "Stop camera": "Kamera ausschalten", "Stop Download": "Download stoppen", "Stop Generating": "Generierung stoppen", "Storage": "Speicher", - "Streamable HTTP": "Streambares HTTP", + "Streamable HTTP": "Streamable HTTP", "Strikethrough": "Durchgestrichen", "Su_day_of_week": "So", "Submit answers": "Antworten absenden", @@ -3152,7 +3152,7 @@ "Summarize this note.": "Diese Notiz zusammenfassen.", "Support": "Unterstützung", "Support this plugin:": "Unterstützen Sie dieses Plugin:", - "Swap": "", + "Swap": "Tauschen", "Switch camera": "Kamera wechseln", "Switch to JSON editor": "Zum JSON-Editor wechseln", "Switch to visual editor": "Zum visuellen Editor wechseln", @@ -3181,15 +3181,15 @@ "Task List": "Aufgabenliste", "Tasks": "Aufgaben", "tasks completed": "Aufgaben abgeschlossen", - "Tell me a fun fact": "", - "Tell me a random fun fact about the Roman Empire": "", + "Tell me a fun fact": "Erzähl mir einen Fun Fact", + "Tell me a random fun fact about the Roman Empire": "Erzähl mir einen zufälligen Fun Fact über das Römische Reich", "Tell us more:": "Erzählen Sie uns mehr:", - "Temporary": "", + "Temporary": "Temporär", "Temporary Chat": "Temporärer Chat", - "Temporary: toggle temporary chat for this new chat.": "", + "Temporary: toggle temporary chat for this new chat.": "Temporär: temporären Chat für diesen neuen Chat ein- oder ausschalten.", "Terminal": "Terminal", "Terminal Contexts": "Terminal-Kontexte", - "Terminal servers saved": "Terminal Server gespeichert", + "Terminal servers saved": "Terminal-Server gespeichert", "Test": "Testen", "Test must pass before a source is created.": "Der Test muss erfolgreich sein, bevor eine Quelle angelegt werden kann.", "Test notification sent.": "Testbenachrichtigung gesendet.", @@ -3215,7 +3215,7 @@ "There was an error syncing your stats. Please try again.": "Beim Synchronisieren Ihrer Statistiken ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.", "These settings are read from environment variables and cannot be edited here while {{ENV_VAR}} is disabled.": "Diese Einstellungen werden aus Umgebungsvariablen gelesen und können hier nicht bearbeitet werden, solange {{ENV_VAR}} deaktiviert ist.", "thinking, output_config": "thinking, output_config", - "Thinking...": "Denke nach...", + "Thinking...": "Denkt nach...", "This action cannot be undone. Do you wish to continue?": "Diese Aktion kann nicht rückgängig gemacht werden. Möchten Sie fortfahren?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Dieser Kanal wurde am {{createdAt}} erstellt. Dies ist der Anfang des Kanals {{channelName}}.", "This chat won't appear in history and your messages will not be saved.": "Dieser Chat erscheint nicht im Verlauf und Ihre Nachrichten werden nicht gespeichert.", @@ -3243,7 +3243,7 @@ "Thought for less than a second": "Für weniger als eine Sekunde nachgedacht", "Thread": "Thread", "Through": "Bis", - "Thumbs up/down ratings from users on model responses": "Daumen hoch/runter von Benutzer für Modell Antworten", + "Thumbs up/down ratings from users on model responses": "Daumen-hoch/-runter-Bewertungen von Benutzern zu Modellantworten", "Tika": "Tika", "Tika 3.x": "Tika 3.x", "Tika 4.x": "Tika 4.x", @@ -3257,15 +3257,15 @@ "Title is required": "Titel ist erforderlich", "To access the available model names for downloading,": "Um die verfügbaren Modellnamen für den Download anzuzeigen,", "To access the GGUF models available for downloading,": "Um die verfügbaren GGUF-Modelle für den Download anzuzeigen,", - "To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Für Zugriff auf die WebUI wenden Sie sich bitte an den Administrator. Administratoren können den Benutzerstatus im Admin-Panel verwalten.", - "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Um einen Wissensspeicher hier anzuhängen, fügen Sie sie zuerst dem Arbeitsbereich \"Wissen\" hinzu.", + "To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Für Zugriff auf die WebUI wenden Sie sich bitte an den Administrator. Administratoren können den Benutzerstatus im Admin-Bereich verwalten.", + "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Um hier Wissensspeicher anzuhängen, fügen Sie diese zuerst dem Arbeitsbereich \"Wissen\" hinzu.", "To learn more about available endpoints, visit our documentation.": "Um mehr über verfügbare Endpunkte zu erfahren, besuchen Sie unsere Dokumentation.", "To learn more about SpeechT5,": "Um mehr über SpeechT5 zu erfahren,", "To see the available CMU Arctic speaker embeddings,": "Um die verfügbaren CMU-Arctic-Speaker-Embeddings zu sehen,", "To select actions here, add them to the \"Functions\" workspace first.": "Um hier Aktionen auswählen zu können, fügen Sie sie zuerst dem Arbeitsbereich \"Funktionen\" hinzu.", "To select default filters here, enable toggleable filters for this model first.": "Um hier Standardfilter auswählen zu können, aktivieren Sie zuerst umschaltbare Filter für dieses Modell.", "To select filters here, add them to the \"Functions\" workspace first.": "Um hier Filter auswählen zu können, fügen Sie sie zuerst dem Arbeitsbereich \"Funktionen\" hinzu.", - "To select skills here, add them to the \"Skills\" workspace first.": "Um hier Skills auszuwählen, füge sie zuerst dem Workspace \"Skills\" hinzu.", + "To select skills here, add them to the \"Skills\" workspace first.": "Um hier Skills auswählen zu können, fügen Sie sie zuerst dem Arbeitsbereich \"Skills\" hinzu.", "To select toolkits here, add them to the \"Tools\" workspace or enable a tool server first.": "Um hier Toolkits auswählen zu können, fügen Sie sie zuerst dem Arbeitsbereich \"Werkzeuge\" hinzu oder aktivieren Sie einen Tool-Server.", "Today": "Heute", "Today at": "Heute um", @@ -3276,8 +3276,8 @@ "Toggle Dictation": "Diktieren umschalten", "Toggle Mute": "Stummschaltung umschalten", "Toggle Sidebar": "Seitenleiste umschalten", - "Toggle status history": "Status Updates umschalten", - "Toggle temporary chat for this new chat.": "", + "Toggle status history": "Statusverlauf umschalten", + "Toggle temporary chat for this new chat.": "Temporären Chat für diesen neuen Chat ein- oder ausschalten.", "Toggle whether current connection is active.": "Umschalten, ob die aktuelle Verbindung aktiv ist.", "Token": "Token", "Token activity": "Token-Aktivität", @@ -3306,8 +3306,8 @@ "Top": "Oben", "Total chats": "Chats insgesamt", "Transformers": "Transformers", - "Translation key": "", - "Trial License": "", + "Translation key": "Übersetzungsschlüssel", + "Trial License": "Testlizenz", "Try adjusting your search or filter to find what you are looking for.": "Versuchen Sie, Ihre Suche oder Filter anzupassen, um zu finden, was Sie suchen.", "Try Again": "Erneut versuchen", "TTS Voice": "TTS-Stimme", @@ -3315,10 +3315,10 @@ "Type": "Typ", "Type a model ref": "Modellreferenz eingeben", "Type here...": "Hier eingeben...", - "Type Hugging Face Resolve (Download) URL": "Hugging Face Resolve (Download) URL eingeben", + "Type Hugging Face Resolve (Download) URL": "Hugging-Face-Resolve-URL (Download) eingeben", "Type your answer": "Antwort eingeben", "Uh-oh! There was an issue with the response.": "Es ist ein Problem mit der Antwort aufgetreten.", - "Unarchive": "", + "Unarchive": "Aus dem Archiv wiederherstellen", "Unarchive Chat": "Chat wiederherstellen", "Unassigned": "Nicht belegt", "Underline": "Unterstreichen", @@ -3345,17 +3345,17 @@ "Updated": "Aktualisiert", "Updated at": "Aktualisiert am", "Updated At": "Aktualisiert am", - "Updating \"{{modelId}}\"": "", + "Updating \"{{modelId}}\"": "Wird aktualisiert: \"{{modelId}}\"", "Upgrade to a licensed plan for enhanced capabilities, including custom theming and branding, and dedicated support.": "Upgraden Sie auf einen lizenzierten Plan für erweiterte Funktionen, einschließlich individuellem Design, Branding und dediziertem Support.", "Upload": "Hochladen", "Upload a GGUF model": "GGUF-Modell hochladen", "Upload Audio": "Audio hochladen", - "Upload directory": "Ordner Hochladen", + "Upload directory": "Ordner hochladen", "Upload failed": "Upload fehlgeschlagen", "Upload failed for {{failed}} of {{total}} files.": "Upload für {{failed}} von {{total}} Dateien fehlgeschlagen.", "Upload files": "Dateien hochladen", "Upload Files": "Datei(en) hochladen", - "Upload Folder": "", + "Upload Folder": "Ordner hochladen", "Upload Model": "Modell hochladen", "Upload Photo": "Foto hochladen", "Upload profile image": "Profilbild hochladen", @@ -3363,13 +3363,13 @@ "Uploaded files or images": "Hochgeladene Dateien oder Bilder", "Uploading": "Wird hochgeladen", "Uploading {{current}}/{{total}}: {{file}}": "Wird hochgeladen {{current}}/{{total}}: {{file}}", - "Uploading...": "Lade hoch...", + "Uploading...": "Wird hochgeladen...", "URL": "URL", "URL is required": "URL ist erforderlich", "URL Mode": "URL-Modus", "Use": "Verwenden Sie", "Use a valid event name or pattern like user.*": "Verwenden Sie einen gültigen Ereignisnamen oder ein Muster wie user.*", - "Use default": "", + "Use default": "Standard verwenden", "Use device vibration feedback on supported Android devices.": "Nutzt die Vibration des Geräts auf unterstützten Android-Geräten.", "Use discovered scopes": "Erkannte Scopes verwenden", "Use groups to organize your users and assign permissions.": "Verwenden Sie Gruppen, um Ihre Benutzer zu organisieren und Berechtigungen zu vergeben.", @@ -3380,8 +3380,8 @@ "Use Web Search?": "Websuche verwenden?", "user": "Benutzer", "User": "Benutzer", - "User Activity": "Benutzer Aktivität", - "User Count": "", + "User Activity": "Benutzeraktivität", + "User Count": "Benutzeranzahl", "User Groups": "Benutzergruppen", "User location successfully retrieved.": "Benutzerstandort erfolgreich abgerufen.", "User menu": "Benutzermenü", @@ -3413,8 +3413,8 @@ "Verify Connection": "Verbindung prüfen", "Version {{selectedVersion}} of {{totalVersions}}": "Version {{selectedVersion}} von {{totalVersions}}", "Version deleted": "Version gelöscht", - "Vertical Layout": "", - "Video player": "", + "Vertical Layout": "Vertikales Layout", + "Video player": "Videoplayer", "View channel": "Kanal anzeigen", "View chat": "Chat ansehen", "View Replies": "Antworten anzeigen", @@ -3427,7 +3427,7 @@ "Visible": "Sichtbar", "Visible to all users": "Für alle Benutzer sichtbar", "Visual": "Visuell", - "vocabulary for a college entrance exam": "", + "vocabulary for a college entrance exam": "Vokabeln für eine Aufnahmeprüfung", "Voice": "Stimme", "Voice Input": "Spracheingabe", "Voice mode": "Sprachmodus", @@ -3437,7 +3437,7 @@ "Waiting for upload...": "Warten auf Upload...", "Warning": "Warnung", "Warning:": "Warnung:", - "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Warnung: Wenn Sie dies aktivieren, können Nutzer geplante Prompts automatisch ausführen.", + "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Warnung: Wenn Sie dies aktivieren, können Benutzer geplante Prompts automatisch ausführen.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Warnung: Wenn Sie dies aktivieren, können Benutzer beliebigen Code auf den Server hochladen.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Warnung: Die Jupyter-Ausführung ermöglicht beliebige Codeausführung und birgt erhebliche Sicherheitsrisiken – gehen Sie mit äußerster Vorsicht vor.", "We_day_of_week": "Mi", @@ -3449,7 +3449,7 @@ "Webhook Name": "Webhook-Name", "Webhook saved": "Webhook gespeichert", "Webhooks": "Webhooks", - "Webpage URLs": "Webseiten URLs", + "Webpage URLs": "Webseiten-URLs", "WebUI will make requests to \"{{url}}\"": "WebUI wird Anfragen an \"{{url}}\" senden", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI wird Anfragen an \"{{url}}/api/chat\" senden", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI wird Anfragen an \"{{url}}/chat/completions\" senden", @@ -3458,7 +3458,7 @@ "Weekly": "Wöchentlich", "Weekly at": "Wöchentlich um", "Welcome to your AI home.": "Willkommen in Ihrem KI-Zuhause.", - "What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter.": "", + "What are 5 creative things I could do with my kids' art? I don't want to throw them away, but it's also so much clutter.": "Was sind 5 kreative Ideen für die Kunstwerke meiner Kinder? Ich möchte sie nicht wegwerfen, aber sie nehmen so viel Platz weg.", "What are you trying to achieve?": "Was möchten Sie erreichen?", "What are you working on?": "Woran arbeiten Sie?", "What is NOT shared:": "Was NICHT geteilt wird:", @@ -3475,12 +3475,12 @@ "Working Directory": "Arbeitsverzeichnis", "Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text.": "Funktioniert zusammen mit Top-K. Ein höherer Wert (z. B. 0.95) führt zu vielfältigerem Text, während ein niedrigerer Wert (z. B. 0.5) fokussierteren und konservativeren Text erzeugt.", "Workspace": "Arbeitsbereich", - "Workspace Models": "", + "Workspace Models": "Arbeitsbereichsmodelle", "Workspace Permissions": "Arbeitsbereichsberechtigungen", "Write": "Schreiben", "Write a summary in 50 words that summarizes {{topic}}.": "Schreiben Sie eine Zusammenfassung in 50 Wörtern über {{topic}}.", "Write something...": "Schreiben Sie etwas...", - "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "Schreiben Sie hier den Inhalt des System-Prompts Ihres Modells\nz. B.: Sie sind Mario aus Super Mario Bros und agieren als Assistent.", + "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "Schreiben Sie hier den Inhalt des System-Prompts Ihres Modells\nz. B.: Du bist Mario aus Super Mario Bros und agierst als Assistent.", "Yahoo": "Yahoo", "Yandex": "Yandex", "Yearly": "Jährlich", @@ -3497,13 +3497,13 @@ "You do not have permission to make this public": "Sie haben keine Berechtigung, das zu veröffentlichen.", "You do not have permission to send messages in this channel.": "Sie haben keine Berechtigung, Nachrichten in diesem Kanal zu senden.", "You do not have permission to send messages in this thread.": "Sie haben keine Berechtigung, Nachrichten in diesem Thread zu senden.", - "You do not have permission to upload files to this knowledge base.": "Sie haben keine Berechtigung, Dateien in diese Wissensspeicher hochzuladen.", + "You do not have permission to upload files to this knowledge base.": "Sie haben keine Berechtigung, Dateien in diesen Wissensspeicher hochzuladen.", "You do not have permission to upload files.": "Sie haben keine Berechtigung, Dateien hochzuladen.", - "You do not have permission to upload web content.": "Sie haben keine Berechtigung Webseiten hochzuladen.", + "You do not have permission to upload web content.": "Sie haben keine Berechtigung, Webinhalte hochzuladen.", "You have more than 50 users, which often means this workspace is supporting organizational use. Open WebUI is free to use as-is, with no restrictions or hidden limits, and we want to keep it that way.": "Sie haben mehr als 50 Benutzer – das deutet meist darauf hin, dass dieser Arbeitsbereich organisationsweit genutzt wird. Open WebUI ist in dieser Form kostenlos nutzbar, ohne Einschränkungen oder versteckte Limits, und das soll auch so bleiben.", "You have no archived conversations.": "Sie haben keine archivierten Unterhaltungen.", "You have no shared conversations.": "Sie haben keine geteilten Unterhaltungen.", - "You have shared this chat": "Sie haben diesen Chat geteilt", + "You have shared this chat": "Sie haben diesen Chat", "You're a helpful assistant.": "Du bist ein hilfreicher Assistent.", "You're now logged in.": "Sie sind jetzt angemeldet.", "Your account status is currently pending activation.": "Ihr Kontostatus wartet derzeit auf Aktivierung.", @@ -3514,7 +3514,7 @@ "Your query will be sent to the configured web search provider.": "Ihre Anfrage wird an den konfigurierten Web-Suchanbieter gesendet.", "Your usage stats have been successfully synced.": "Ihre Nutzungsstatistiken wurden erfolgreich synchronisiert.", "YouTube": "YouTube", - "YouTube video player": "", + "YouTube video player": "YouTube-Videoplayer", "Zoom in": "Vergrößern", "Zoom out": "Verkleinern" } From 8a90f0fc9325f42e6e104ab865c1a74fbefc311e Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:58:42 +0200 Subject: [PATCH 18/70] fix: file uploads and hybrid search fail on Qdrant with strict mode enabled (#31461) With Qdrant strict mode on and a max_query_limit below 999999999, Qdrant rejects Open WebUI's reads with "Limit exceeded", so every file upload after the first fails in the default multitenancy mode, and hybrid search finds nothing. Reads now go in pages of 1000 points, so any strict-mode limit of 1000 or more works. Without strict mode the results are the same as before. Tested against Qdrant 1.19.1 with max_query_limit 1000, for both multitenancy on and off: collections of up to 2500 points come back complete, limits are respected, and tenants stay separated. Fixes #31459 --- .../open_webui/retrieval/vector/dbs/qdrant.py | 37 ++++++++++++------- .../vector/dbs/qdrant_multitenancy.py | 35 ++++++++++-------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/backend/open_webui/retrieval/vector/dbs/qdrant.py b/backend/open_webui/retrieval/vector/dbs/qdrant.py index f8ed600773..d1b302b34f 100644 --- a/backend/open_webui/retrieval/vector/dbs/qdrant.py +++ b/backend/open_webui/retrieval/vector/dbs/qdrant.py @@ -28,6 +28,7 @@ from qdrant_client.http.models import PointStruct from qdrant_client.models import models NO_LIMIT = 999999999 +SCROLL_PAGE_SIZE = 1000 log = logging.getLogger(__name__) @@ -92,6 +93,24 @@ class QdrantClient(VectorDBBase): } ) + def _scroll_points( + self, collection_name: str, scroll_filter: Optional[models.Filter] = None, limit: Optional[int] = None + ) -> list: + # Paged so a strict-mode max_query_limit does not reject the read + points = [] + offset = None + while True: + page_size = SCROLL_PAGE_SIZE if limit is None else min(SCROLL_PAGE_SIZE, limit - len(points)) + page, offset = self.client.scroll( + collection_name=f'{self.collection_prefix}_{collection_name}', + scroll_filter=scroll_filter, + limit=page_size, + offset=offset, + ) + points.extend(page) + if offset is None or len(points) == limit: + return points + def _create_collection(self, collection_name: str, dimension: int): collection_name_with_prefix = f'{self.collection_prefix}_{collection_name}' self.client.create_collection( @@ -180,32 +199,22 @@ class QdrantClient(VectorDBBase): if not self.has_collection(collection_name): return None try: - if limit is None: - limit = NO_LIMIT # otherwise qdrant would set limit to 10! - field_conditions = [] for key, value in filter.items(): field_conditions.append( models.FieldCondition(key=f'metadata.{key}', match=models.MatchValue(value=value)) ) - points = self.client.scroll( - collection_name=f'{self.collection_prefix}_{collection_name}', - scroll_filter=models.Filter(should=field_conditions), - limit=limit, - ) - return self._result_to_get_result(points[0]) + points = self._scroll_points(collection_name, models.Filter(should=field_conditions), limit) + return self._result_to_get_result(points) except Exception as e: log.exception(f"Error querying a collection '{collection_name}': {e}") return None def get(self, collection_name: str) -> Optional[GetResult]: # Get all the items in the collection. - points = self.client.scroll( - collection_name=f'{self.collection_prefix}_{collection_name}', - limit=NO_LIMIT, # otherwise qdrant would set limit to 10! - ) - return self._result_to_get_result(points[0]) + points = self._scroll_points(collection_name) + return self._result_to_get_result(points) def insert(self, collection_name: str, items: list[VectorItem]): # Insert the items into the collection, if the collection does not exist, it will be created. diff --git a/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py b/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py index 870cd2b02f..6bf71717e2 100644 --- a/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py +++ b/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py @@ -29,7 +29,7 @@ from qdrant_client.http.exceptions import UnexpectedResponse from qdrant_client.http.models import PointStruct from qdrant_client.models import models -NO_LIMIT = 999999999 +SCROLL_PAGE_SIZE = 1000 TENANT_ID_FIELD = 'tenant_id' DEFAULT_DIMENSION = 384 @@ -97,6 +97,21 @@ class QdrantClient(VectorDBBase): metadatas.append(payload['metadata']) return GetResult(ids=[ids], documents=[documents], metadatas=[metadatas]) + def _scroll_points(self, collection_name: str, scroll_filter: models.Filter, limit: Optional[int] = None) -> List: + # Paged so a strict-mode max_query_limit does not reject the read + points, offset = [], None + while True: + page_size = SCROLL_PAGE_SIZE if limit is None else min(SCROLL_PAGE_SIZE, limit - len(points)) + page, offset = self.client.scroll( + collection_name=collection_name, + scroll_filter=scroll_filter, + limit=page_size, + offset=offset, + ) + points.extend(page) + if offset is None or len(points) == limit: + return points + def _get_collection_and_tenant_id(self, collection_name: str) -> Tuple[str, str]: """ Maps the traditional collection name to multi-tenant collection and tenant ID. @@ -287,17 +302,11 @@ class QdrantClient(VectorDBBase): if not self.client.collection_exists(collection_name=mt_collection): log.debug("Collection %s doesn't exist, query returns None", mt_collection) return None - if limit is None: - limit = NO_LIMIT tenant_filter = _tenant_filter(tenant_id) field_conditions = [_metadata_filter(k, '$eq', v) for k, v in filter.items()] combined_filter = models.Filter(must=[tenant_filter, *field_conditions]) - points = self.client.scroll( - collection_name=mt_collection, - scroll_filter=combined_filter, - limit=limit, - ) - return self._result_to_get_result(points[0]) + points = self._scroll_points(mt_collection, combined_filter, limit) + return self._result_to_get_result(points) def get(self, collection_name: str) -> Optional[GetResult]: """ @@ -310,12 +319,8 @@ class QdrantClient(VectorDBBase): log.debug("Collection %s doesn't exist, get returns None", mt_collection) return None tenant_filter = _tenant_filter(tenant_id) - points = self.client.scroll( - collection_name=mt_collection, - scroll_filter=models.Filter(must=[tenant_filter]), - limit=NO_LIMIT, - ) - return self._result_to_get_result(points[0]) + points = self._scroll_points(mt_collection, models.Filter(must=[tenant_filter])) + return self._result_to_get_result(points) def upsert(self, collection_name: str, items: List[VectorItem]): """ From eda8d85361768aa000e2f9fc199ee841b78ae9b3 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:59:02 +0200 Subject: [PATCH 19/70] fix: hybrid search finds nothing when a collection cannot be read (#31460) With hybrid search on and a vector database without built-in hybrid search, a collection that failed to load (for example Qdrant strict mode rejecting the request) was skipped quietly, so retrieval returned no documents and never fell back to normal vector search. A failed load now counts as a failed collection, so when every collection fails retrieval falls back to vector search, the same way it already does when the search itself fails. The retrieval API returns its usual error in that case. Part of #31459 --- backend/open_webui/retrieval/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index 055f750122..b1597aa2db 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -838,6 +838,7 @@ async def query_collection_with_hybrid_search( return name, await ASYNC_VECTOR_DB_CLIENT.get(collection_name=name) except Exception as e: log.exception(f'Failed to fetch collection {name}: {e}') + failed_collection_names.add(name) return name, None collection_results = dict(await asyncio.gather(*(_fetch_collection(name) for name in collection_names))) From 31a09a1eeb1448d9f35ccab16bfd3b95cb9662f8 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:59:11 +0200 Subject: [PATCH 20/70] refac: check the owner's role before continuing a chat after a subagent finishes (#31451) The parent chat now only continues with a finished subagent's result while its owner still has a verified role, the same check timers already make. --- backend/open_webui/utils/subagents.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/utils/subagents.py b/backend/open_webui/utils/subagents.py index 809dd601ae..13b9699216 100644 --- a/backend/open_webui/utils/subagents.py +++ b/backend/open_webui/utils/subagents.py @@ -14,7 +14,7 @@ from open_webui.models.chats import Chat, ChatForm, Chats from open_webui.models.config import Config from open_webui.models.users import UserModel, Users from open_webui.tasks import create_task, has_active_tasks -from open_webui.utils.auth import create_token +from open_webui.utils.auth import VERIFIED_USER_ROLES, create_token from open_webui.utils.json_codec import JSONCodec from open_webui.utils.misc import get_message_list from sqlalchemy import select @@ -84,7 +84,7 @@ async def process_pending_internal_messages( return user = await Users.get_user_by_id(user_id) - if not user: + if not user or user.role not in VERIFIED_USER_ROLES: return async with get_async_db() as db: From b39abad5c28db8e69885b9fbc5f756ff74666a90 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 27 Sep 2026 23:07:52 +0400 Subject: [PATCH 21/70] refac --- .../components/common/RichTextInput.svelte | 4 +-- src/lib/components/notes/NoteEditor.svelte | 4 +-- src/lib/utils/editorJson.ts | 31 +++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/lib/utils/editorJson.ts diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index 7ddf962af4..b4b54d7b43 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -1,7 +1,7 @@ Date: Sun, 27 Sep 2026 15:15:24 -0400 Subject: [PATCH 35/70] fix: clamp the artifacts pane's version when an artifact is removed (#30435) --- src/lib/components/chat/Artifacts.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/components/chat/Artifacts.svelte b/src/lib/components/chat/Artifacts.svelte index 943c6d6a7a..d0a6e195ee 100644 --- a/src/lib/components/chat/Artifacts.svelte +++ b/src/lib/components/chat/Artifacts.svelte @@ -109,6 +109,8 @@ selectedContentIdx = 0; } else if (newContents.length > contents.length) { selectedContentIdx = newContents.length - 1; + } else if (selectedContentIdx > newContents.length - 1) { + selectedContentIdx = newContents.length - 1; } contents = newContents; From 332237662f446f8264cd4db10a1b4513ba5fb76b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 27 Sep 2026 23:18:46 +0400 Subject: [PATCH 36/70] refac --- src/lib/components/chat/Chat.svelte | 9 ++++----- src/lib/components/chat/MessageInput.svelte | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index ea8bd53d30..e304dde6c6 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -429,6 +429,7 @@ let loadedChatIdProp = ''; let currentDraftKey = ''; + // Chat parameters own the approval mode; chats without an override use the user default. $: toolApprovalMode = (params?.tool_approval_mode ?? $settings?.params?.tool_approval_mode) === 'ask' ? 'ask' @@ -769,9 +770,8 @@ webSearchEnabled = input.webSearchEnabled ?? false; imageGenerationEnabled = input.imageGenerationEnabled ?? false; codeInterpreterEnabled = input.codeInterpreterEnabled ?? false; - if (input.toolApprovalMode) { - await handleToolApprovalModeChange(input.toolApprovalMode); - } + // Ignore approval modes in older drafts. Restoring input must not overwrite chat + // parameters or invoke the change handler, which can save settings and approve tools. return true; } catch (e) { return false; @@ -4101,8 +4101,7 @@ selectedFilterIds, imageGenerationEnabled, webSearchEnabled, - codeInterpreterEnabled, - toolApprovalMode + codeInterpreterEnabled }); const saveDraft = async (draft: any, chatId: string | null = null, debounce = true) => { diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index ec568c9a41..0898d3be05 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -238,6 +238,7 @@ } let chatInputDraft: any; + // Approval mode is persisted in chat parameters and user settings, not input drafts. $: chatInputDraft = { prompt, files: files @@ -254,8 +255,7 @@ selectedFilterIds, imageGenerationEnabled, webSearchEnabled, - codeInterpreterEnabled, - toolApprovalMode + codeInterpreterEnabled }; $: onChange(chatInputDraft); From 0fe9ed0d3cc44817eeabea26751e23372ed54aed Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:20:50 +0200 Subject: [PATCH 37/70] fix: Anthropic API streams report a failed response as a finished one (#31405) When the provider failed partway through a streaming request to the Anthropic Messages endpoint, the stream still ended like a normally finished answer, so Claude Code and the Anthropic SDKs took the cut-off text as complete. The stream now ends with an Anthropic error event, with the provider's error message if it sent one, so clients raise an error. Successful streams are unchanged. Fixes #31403 --- backend/open_webui/utils/anthropic.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backend/open_webui/utils/anthropic.py b/backend/open_webui/utils/anthropic.py index 4121ba202a..bd2cea2e61 100644 --- a/backend/open_webui/utils/anthropic.py +++ b/backend/open_webui/utils/anthropic.py @@ -616,6 +616,7 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str server_tool_use = None service_tier = None stop_reason = 'end_turn' + error_message = None # Track content blocks with a running index. # Each text block or tool_use block gets its own index. @@ -671,6 +672,13 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str except (JSONCodec.JSONDecodeError, TypeError): continue + error = data.get('error') + if error: + error_message = ( + error.get('message') if isinstance(error, dict) else error + ) or 'Chat completion stream failed' + break + usage_data = data.get('usage') if isinstance(usage_data, dict): cache_creation = usage_data.get('cache_creation_input_tokens') @@ -904,8 +912,18 @@ async def openai_stream_to_anthropic_stream(openai_stream_generator, model: str } stop_reason = stop_reason_map.get(finish_reason, 'end_turn') + if error_message: + break + except Exception as e: log.error(f'Error in Anthropic stream conversion: {e}') + error_message = 'Chat completion stream failed' + + # Skip message_stop so a failed stream is not reported as complete. + if error_message: + error_event = {'type': 'error', 'error': {'type': 'api_error', 'message': error_message}} + yield f'event: error\ndata: {JSONCodec.dumps(error_event)}\n\n'.encode() + return # Close any open thinking block if thinking_block_open: From 1c813902ec02c8bf2f86dd1d045ecc1ddc57981f Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 21:21:21 +0200 Subject: [PATCH 38/70] fix: keep relevance scores on knowledge tool citations (#31307) With native function calling, citations produced by query_knowledge_files and query_chat_files never showed the relevance percentage badge, while the same knowledge base queried through classic RAG did. The tools already return a distance per chunk, but the step that groups tool results into citation sources dropped it. Each grouped source now carries a distances list aligned with its documents, the same shape the classic RAG path emits, so the existing citation UI shows the badge without frontend changes. Chunks without a score (notes) leave the list empty, which the UI already treats as no score. Fixes #29776 --- backend/open_webui/utils/middleware.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index be4fa816ec..47f7617554 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -510,6 +510,7 @@ def get_citation_source_from_tool_result( }, 'document': [], 'metadata': [], + 'distances': [], } sources_by_file[key]['document'].append(content) @@ -521,6 +522,8 @@ def get_citation_source_from_tool_result( **({'note_id': note_id} if note_id else {}), } ) + if 'distance' in chunk: + sources_by_file[key]['distances'].append(chunk['distance']) # Return all grouped sources as a list if sources_by_file: From 19957bc19b769388a61bc9ebd7322deb006ddd62 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 27 Sep 2026 23:23:24 +0400 Subject: [PATCH 39/70] refac --- .../Markdown/ConsecutiveDetailsGroup.svelte | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/lib/components/chat/Messages/Markdown/ConsecutiveDetailsGroup.svelte b/src/lib/components/chat/Messages/Markdown/ConsecutiveDetailsGroup.svelte index e37a4c820c..fe3b2ce4b5 100644 --- a/src/lib/components/chat/Messages/Markdown/ConsecutiveDetailsGroup.svelte +++ b/src/lib/components/chat/Messages/Markdown/ConsecutiveDetailsGroup.svelte @@ -99,14 +99,18 @@ $: pendingToolTokens = tokens.filter( (t) => t?.attributes?.type === 'tool_calls' && t?.attributes?.status === 'pending' ); - $: hasActiveToolCalls = tokens.some( - (t) => - t?.attributes?.type === 'tool_calls' && - t?.attributes?.status !== 'rejected' && - t?.attributes?.status !== 'failed' && - t?.attributes?.status !== 'incomplete' && - t?.attributes?.done !== 'true' - ); + $: hasActiveDetails = tokens.some((token) => { + const attributes = token?.attributes; + if (attributes?.type === 'tool_calls') { + return ( + attributes.status !== 'rejected' && + attributes.status !== 'failed' && + attributes.status !== 'incomplete' && + attributes.done !== 'true' + ); + } + return !messageDone && attributes?.done && attributes.done !== 'true'; + }); $: hasRejected = tokens.some( (t) => t?.attributes?.type === 'tool_calls' && t?.attributes?.status === 'rejected' ); @@ -174,7 +178,7 @@ return detail; })(); - $: prefixText = hasActiveToolCalls ? $i18n.t('Exploring') : $i18n.t('Explored'); + $: prefixText = hasActiveDetails ? $i18n.t('Exploring') : $i18n.t('Explored');
@@ -199,7 +203,7 @@ >
- {#if hasActiveToolCalls} + {#if hasActiveDetails}
@@ -223,7 +227,7 @@
- {prefixText} {#if summaryText} From bc2416c5db5f5268de0f97730c5a51f55018837a Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 27 Sep 2026 23:29:38 +0400 Subject: [PATCH 40/70] refac --- backend/open_webui/routers/ollama.py | 64 +++++++------- backend/open_webui/routers/openai.py | 85 +------------------ backend/open_webui/utils/headers.py | 87 ++++++++++++++++++++ src/lib/components/AddConnectionModal.svelte | 22 ++++- 4 files changed, 137 insertions(+), 121 deletions(-) diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index b283db9ae8..cc556908ef 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -22,8 +22,6 @@ from open_webui.env import ( AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST, AIOHTTP_FILE_STREAM_CHUNK_SIZE, BYPASS_MODEL_ACCESS_CONTROL, - ENABLE_FORWARD_USER_INFO_HEADERS, - FORWARD_SESSION_INFO_HEADER_CHAT_ID, MODELS_CACHE_TTL, REDIS_KEY_PREFIX, ) @@ -36,7 +34,7 @@ from open_webui.models.models import Models from open_webui.models.users import UserModel from open_webui.utils.access_control import check_model_access from open_webui.utils.auth import get_admin_user, get_verified_user -from open_webui.utils.headers import get_custom_headers, include_user_info_headers +from open_webui.utils.headers import get_headers_and_cookies from open_webui.utils.json_codec import JSONCodec from open_webui.utils.misc import calculate_sha256 from open_webui.utils.model_ids import strip_provider_model_prefix @@ -67,24 +65,21 @@ def _clean_proxy_headers(raw_headers) -> dict: async def send_get_request( - url: str, - key: str | None = None, - user: UserModel | None = None, + request: Request = None, + url=None, + key=None, + user: UserModel = None, + config=None, ): """Issue a GET request to an Ollama backend and return JSON, or *None* on failure.""" try: session = await get_session() - headers: dict = { - 'Content-Type': 'application/json', - } - if key: - headers['Authorization'] = f'Bearer {key}' - if ENABLE_FORWARD_USER_INFO_HEADERS and user: - headers = include_user_info_headers(headers, user) + headers, cookies = await get_headers_and_cookies(request, url, key, config, user=user) async with session.get( url, headers=headers, + cookies=cookies, ssl=AIOHTTP_CLIENT_SESSION_SSL, timeout=_MODEL_LIST_TIMEOUT, ) as r: @@ -114,25 +109,14 @@ async def send_request( try: session = await get_session() - headers = { - 'Content-Type': 'application/json', - **({'Authorization': f'Bearer {key}'} if key else {}), - } - - if ENABLE_FORWARD_USER_INFO_HEADERS and user: - headers = include_user_info_headers(headers, user, request=request) - if metadata and metadata.get('chat_id'): - headers[FORWARD_SESSION_INFO_HEADER_CHAT_ID] = metadata.get('chat_id') - - # Custom per-connection headers last so admin-set headers take precedence. - if api_config and api_config.get('headers'): - headers.update(await get_custom_headers(api_config['headers'], user, metadata, request=request)) + headers, cookies = await get_headers_and_cookies(request, url, key, api_config, metadata, user=user) r = await session.request( method, url, data=payload, headers=headers, + cookies=cookies, ssl=AIOHTTP_CLIENT_SESSION_SSL, timeout=get_client_timeout(stream=stream), ) @@ -249,24 +233,26 @@ class ConnectionVerificationForm(BaseModel): url: str key: str | None = None + config: dict | None = None + @router.post('/verify') async def verify_connection( + request: Request, form_data: ConnectionVerificationForm, user=Depends(get_admin_user), ): """Verify that an Ollama backend at *form_data.url* is reachable.""" try: session = await get_session() - headers: dict = {} - if form_data.key: - headers['Authorization'] = f'Bearer {form_data.key}' - if ENABLE_FORWARD_USER_INFO_HEADERS and user: - headers = include_user_info_headers(headers, user) + headers, cookies = await get_headers_and_cookies( + request, form_data.url, form_data.key, form_data.config, user=user + ) async with session.get( f'{form_data.url}/api/version', headers=headers, + cookies=cookies, ssl=AIOHTTP_CLIENT_SESSION_SSL, timeout=_MODEL_LIST_TIMEOUT, ) as r: @@ -403,9 +389,11 @@ async def get_all_models(request: Request, user: UserModel | None = None): for idx, url in enumerate(base_urls): api_config = resolve_api_config(api_configs, idx, url) if not api_config: - tasks.append(send_get_request(f'{url}/api/tags', user=user)) + tasks.append(send_get_request(request, f'{url}/api/tags', user=user)) elif api_config.get('enable', True): - tasks.append(send_get_request(f'{url}/api/tags', api_config.get('key'), user=user)) + tasks.append( + send_get_request(request, f'{url}/api/tags', api_config.get('key'), user=user, config=api_config) + ) else: tasks.append(asyncio.ensure_future(asyncio.sleep(0, None))) @@ -524,9 +512,11 @@ async def get_ollama_loaded_models( continue api_config = resolve_api_config(api_configs, idx, url) if not api_config: - tasks.append(send_get_request(f'{url}/api/ps', user=user)) + tasks.append(send_get_request(request, f'{url}/api/ps', user=user)) elif api_config.get('enable', True): - tasks.append(send_get_request(f'{url}/api/ps', api_config.get('key'), user=user)) + tasks.append( + send_get_request(request, f'{url}/api/ps', api_config.get('key'), user=user, config=api_config) + ) else: tasks.append(asyncio.ensure_future(asyncio.sleep(0, None))) @@ -570,7 +560,9 @@ async def get_ollama_versions( (await Config.get('ollama.api_configs', {})).get(url, {}), ) if api_config.get('enable', True): - tasks.append(send_get_request(f'{url}/api/version', api_config.get('key'))) + tasks.append( + send_get_request(request, f'{url}/api/version', api_config.get('key'), user=user, config=api_config) + ) raw = await asyncio.gather(*tasks) valid = [r for r in raw if r is not None] diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index 63676d166e..b8a75c2bfb 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -10,7 +10,6 @@ from urllib.parse import quote, urlparse import aiofiles import aiohttp from aiocache import cached -from azure.identity import DefaultAzureCredential, get_bearer_token_provider from fastapi import APIRouter, Depends, HTTPException, Request, status from fastapi.responses import ( FileResponse, @@ -28,7 +27,6 @@ from open_webui.env import ( BYPASS_MODEL_ACCESS_CONTROL, ENABLE_FORWARD_USER_INFO_HEADERS, ENABLE_OPENAI_API_PASSTHROUGH, - FORWARD_SESSION_INFO_HEADER_CHAT_ID, MODELS_CACHE_TTL, REDIS_KEY_PREFIX, ) @@ -42,7 +40,7 @@ from open_webui.models.users import UserModel from open_webui.utils.access_control import check_model_access, has_connection_access, has_permission from open_webui.utils.anthropic import ANTHROPIC_VERSION, get_anthropic_models, is_anthropic_url from open_webui.utils.auth import get_admin_user, get_verified_user -from open_webui.utils.headers import get_custom_headers, include_user_info_headers +from open_webui.utils.headers import get_headers_and_cookies, include_user_info_headers from open_webui.utils.json_codec import JSONCodec from open_webui.utils.misc import convert_logit_bias_input_to_json from open_webui.utils.model_ids import strip_provider_model_prefix @@ -152,87 +150,6 @@ def openai_reasoning_model_handler(payload): return payload -async def get_headers_and_cookies( - request: Request, - url, - key=None, - config=None, - metadata: dict | None = None, - user: UserModel = None, -): - cookies = getattr(request, 'cookies', {}) if config.get('forward_cookies', False) else {} - headers = { - 'Content-Type': 'application/json', - **( - { - # LICENSE covers this Open WebUI upstream metadata identifier. - # Do not alter, remove, obscure, or replace it except as LICENSE permits: - # https://docs.openwebui.com/license. - 'HTTP-Referer': 'https://openwebui.com/', - 'X-Title': 'Open WebUI', - } - if 'openrouter.ai' in url - else {} - ), - } - - if ENABLE_FORWARD_USER_INFO_HEADERS and user: - headers = include_user_info_headers(headers, user, request=request) - if metadata and metadata.get('chat_id'): - headers[FORWARD_SESSION_INFO_HEADER_CHAT_ID] = metadata.get('chat_id') - - token = None - auth_type = config.get('auth_type') - - if auth_type == 'bearer' or auth_type is None: - # Default to bearer if not specified - token = f'{key}' - elif auth_type == 'none': - token = None - elif auth_type == 'session': - token = request.state.token.credentials - elif auth_type == 'system_oauth': - oauth_token = None - try: - if request.cookies.get('oauth_session_id', None): - oauth_token = await request.app.state.oauth_manager.get_oauth_token( - user.id, - request.cookies.get('oauth_session_id', None), - ) - except Exception as e: - log.error(f'Error getting OAuth token: {e}') - - if oauth_token: - token = f'{oauth_token.get("access_token", "")}' - - elif auth_type in ('azure_ad', 'microsoft_entra_id'): - token = get_microsoft_entra_id_access_token() - - if token: - headers['Authorization'] = f'Bearer {token}' - - if config.get('headers') and isinstance(config.get('headers'), dict): - custom_headers = await get_custom_headers(config.get('headers'), user, metadata, request=request) - headers.update(custom_headers) - - return headers, cookies - - -def get_microsoft_entra_id_access_token(): - """ - Get Microsoft Entra ID access token using DefaultAzureCredential for Azure OpenAI. - Returns the token string or None if authentication fails. - """ - try: - token_provider = get_bearer_token_provider( - DefaultAzureCredential(), 'https://cognitiveservices.azure.com/.default' - ) - return token_provider() - except Exception as e: - log.error(f'Error getting Microsoft Entra ID access token: {e}') - return None - - ########################################## # # API routes diff --git a/backend/open_webui/utils/headers.py b/backend/open_webui/utils/headers.py index 91cd088834..75368a43ef 100644 --- a/backend/open_webui/utils/headers.py +++ b/backend/open_webui/utils/headers.py @@ -5,7 +5,10 @@ from typing import Any, Optional from urllib.parse import quote import jwt +from fastapi import Request from open_webui.env import ( + ENABLE_FORWARD_USER_INFO_HEADERS, + FORWARD_SESSION_INFO_HEADER_CHAT_ID, FORWARD_USER_INFO_HEADER_AUTH_TYPE, FORWARD_USER_INFO_HEADER_JWT, FORWARD_USER_INFO_HEADER_JWT_EXPIRES_SECONDS, @@ -161,3 +164,87 @@ def parse_custom_headers( parsed_headers[key] = quote(value, safe=punctuation + ' \t') return parsed_headers + + +async def get_headers_and_cookies( + request: Request, + url, + key=None, + config=None, + metadata: dict | None = None, + user=None, +): + config = config or {} + cookies = getattr(request, 'cookies', {}) if config.get('forward_cookies', False) else {} + headers = { + 'Content-Type': 'application/json', + **( + { + # LICENSE covers this Open WebUI upstream metadata identifier. + # Do not alter, remove, obscure, or replace it except as LICENSE permits: + # https://docs.openwebui.com/license. + 'HTTP-Referer': 'https://openwebui.com/', + 'X-Title': 'Open WebUI', + } + if 'openrouter.ai' in url + else {} + ), + } + + if ENABLE_FORWARD_USER_INFO_HEADERS and user: + headers = include_user_info_headers(headers, user, request=request) + if metadata and metadata.get('chat_id'): + headers[FORWARD_SESSION_INFO_HEADER_CHAT_ID] = metadata.get('chat_id') + + token = None + auth_type = config.get('auth_type') + + if auth_type == 'bearer' or auth_type is None: + # Default to bearer if not specified + token = key + elif auth_type == 'none': + token = None + elif auth_type == 'session': + token = request.state.token.credentials + elif auth_type == 'system_oauth': + oauth_token = None + try: + if request.cookies.get('oauth_session_id', None): + oauth_token = await request.app.state.oauth_manager.get_oauth_token( + user.id, + request.cookies.get('oauth_session_id', None), + ) + except Exception as e: + log.error(f'Error getting OAuth token: {e}') + + if oauth_token: + token = f'{oauth_token.get("access_token", "")}' + + elif auth_type in ('azure_ad', 'microsoft_entra_id'): + token = get_microsoft_entra_id_access_token() + + if token: + headers['Authorization'] = f'Bearer {token}' + + if config.get('headers') and isinstance(config.get('headers'), dict): + custom_headers = await get_custom_headers(config.get('headers'), user, metadata, request=request) + headers.update(custom_headers) + + return headers, cookies + + +def get_microsoft_entra_id_access_token(): + """ + Get Microsoft Entra ID access token using DefaultAzureCredential for Azure OpenAI. + Returns the token string or None if authentication fails. + """ + from azure.identity import DefaultAzureCredential, get_bearer_token_provider + + try: + token_provider = get_bearer_token_provider( + DefaultAzureCredential(), 'https://cognitiveservices.azure.com/.default' + ) + return token_provider() + except Exception as e: + log.error(f'Error getting Microsoft Entra ID access token: {e}') + return None diff --git a/src/lib/components/AddConnectionModal.svelte b/src/lib/components/AddConnectionModal.svelte index 1a5f117929..0ada5f55c3 100644 --- a/src/lib/components/AddConnectionModal.svelte +++ b/src/lib/components/AddConnectionModal.svelte @@ -77,9 +77,29 @@ // remove trailing slash from url url = url.replace(/\/$/, ''); + let _headers = null; + + if (headers) { + try { + _headers = JSON.parse(headers); + if (typeof _headers !== 'object' || Array.isArray(_headers)) { + _headers = null; + throw new Error('Headers must be a valid JSON object'); + } + headers = JSON.stringify(_headers, null, 2); + } catch (error) { + toast.error($i18n.t('Headers must be a valid JSON object')); + return; + } + } + const res = await verifyOllamaConnection(localStorage.token, { url, - key + key, + config: { + auth_type, + ...(_headers ? { headers: _headers } : {}) + } }).catch((error) => { toast.error(`${error}`); }); From 0082c153f52d68cee6e44012069dfb38ec0cdf52 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:04:16 +0200 Subject: [PATCH 41/70] fix: first click in a chat's Share or Delete dialog does nothing (#31488) Choosing Share or Delete from a chat's menu in the sidebar left the menu open behind the dialog, so the first click inside the dialog only closed the menu behind it. Copy Link and Confirm had to be clicked twice. Share and Delete now close the menu before opening their dialog, like Rename, Pin and Clone already do. Fixes #31486 --- src/lib/components/layout/Sidebar/ChatMenu.svelte | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/components/layout/Sidebar/ChatMenu.svelte b/src/lib/components/layout/Sidebar/ChatMenu.svelte index 5e2100d48c..b3286d80a3 100644 --- a/src/lib/components/layout/Sidebar/ChatMenu.svelte +++ b/src/lib/components/layout/Sidebar/ChatMenu.svelte @@ -313,6 +313,7 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { + dropdown.close(); shareHandler(); }} > @@ -468,6 +469,7 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { + dropdown.close(); deleteHandler(); }} > From 00a245b9fa5d98794011e849fc4e36716732b6ea Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 22:04:18 +0200 Subject: [PATCH 42/70] fix: Manage Ollama ignores a connection's custom headers and auth type (#31489) Listing, pulling, creating, copying and deleting models from the Manage Ollama dialog ignored the connection's custom headers and authentication type, so the dialog failed behind gateways such as Cloudflare Access and sent the key as a Bearer token even with the authentication type set to None. Checking a single connection's version sent no key at all. All of these, and the other requests to an Ollama connection such as text generation and embeddings, now use the connection's headers and authentication type, matching what verifying the connection and chatting already do. Fixes #31487 --- backend/open_webui/routers/ollama.py | 75 +++++++++++++++++++++------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index cc556908ef..188cb5d7da 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -483,9 +483,15 @@ async def get_ollama_tags( if url_idx is None: result = await get_all_models(request, user=user) else: - url = (await Config.get('ollama.base_urls', []))[url_idx] - key = get_api_key(url_idx, url, (await Config.get('ollama.api_configs', {}))) - result = await send_request(f'{url}/api/tags', 'GET', key=key, user=user) + url, api_config, key = await get_ollama_connection(url_idx) + result = await send_request( + f'{url}/api/tags', + 'GET', + key=key, + user=user, + api_config=api_config, + request=request, + ) if user.role == 'user' and not BYPASS_MODEL_ACCESS_CONTROL: result['models'] = await get_filtered_models(result, user) @@ -549,8 +555,15 @@ async def get_ollama_versions( return {'version': False} if url_idx is not None: - url = (await Config.get('ollama.base_urls', []))[url_idx] - return await send_request(f'{url}/api/version', 'GET') + url, api_config, key = await get_ollama_connection(url_idx) + return await send_request( + f'{url}/api/version', + 'GET', + key=key, + user=user, + api_config=api_config, + request=request, + ) # Fan-out to every enabled backend tasks = [] @@ -626,6 +639,8 @@ async def unload_model( payload=JSONCodec.dumps(payload), key=key, user=user, + api_config=api_config, + request=request, ) results.append({'url_idx': idx, 'success': True, 'response': res}) except Exception as e: @@ -655,17 +670,19 @@ async def pull_model( form_data = form_data.model_dump(exclude_none=True) form_data['model'] = form_data.get('model', form_data.get('name')) - url = (await Config.get('ollama.base_urls', []))[url_idx] + url, api_config, key = await get_ollama_connection(url_idx) log.info('url: %s', url) # Admins may pull from any registry return await send_request( f'{url}/api/pull', payload=JSONCodec.dumps({**form_data, 'insecure': True}), - key=get_api_key(url_idx, url, (await Config.get('ollama.api_configs', {}))), + key=key, user=user, stream=True, passthrough=True, + api_config=api_config, + request=request, ) @@ -696,16 +713,18 @@ async def push_model( raise HTTPException(status_code=400, detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.model)) url_idx = models[form_data.model]['urls'][0] - url = (await Config.get('ollama.base_urls', []))[url_idx] + url, api_config, key = await get_ollama_connection(url_idx) log.debug('url: %s', url) return await send_request( f'{url}/api/push', payload=form_data.model_dump_json(exclude_none=True).encode(), - key=get_api_key(url_idx, url, (await Config.get('ollama.api_configs', {}))), + key=key, user=user, stream=True, passthrough=True, + api_config=api_config, + request=request, ) @@ -730,15 +749,17 @@ async def create_model( raise HTTPException(status_code=503, detail=ERROR_MESSAGES.OLLAMA_API_DISABLED) log.debug('form_data: %s', form_data) - url = (await Config.get('ollama.base_urls', []))[url_idx] + url, api_config, key = await get_ollama_connection(url_idx) return await send_request( f'{url}/api/create', payload=form_data.model_dump_json(exclude_none=True).encode(), - key=get_api_key(url_idx, url, (await Config.get('ollama.api_configs', {}))), + key=key, user=user, stream=True, passthrough=True, + api_config=api_config, + request=request, ) @@ -768,14 +789,15 @@ async def copy_model( raise HTTPException(status_code=400, detail=ERROR_MESSAGES.MODEL_NOT_FOUND(form_data.source)) url_idx = models[form_data.source]['urls'][0] - url = (await Config.get('ollama.base_urls', []))[url_idx] - key = get_api_key(url_idx, url, (await Config.get('ollama.api_configs', {}))) + url, api_config, key = await get_ollama_connection(url_idx) await send_request( f'{url}/api/copy', payload=form_data.model_dump_json(exclude_none=True).encode(), key=key, user=user, + api_config=api_config, + request=request, ) await publish_event( request, @@ -810,8 +832,7 @@ async def delete_model( raise HTTPException(status_code=400, detail=ERROR_MESSAGES.MODEL_NOT_FOUND(model)) url_idx = models[model]['urls'][0] - url = (await Config.get('ollama.base_urls', []))[url_idx] - key = get_api_key(url_idx, url, (await Config.get('ollama.api_configs', {}))) + url, api_config, key = await get_ollama_connection(url_idx) await send_request( f'{url}/api/delete', @@ -819,6 +840,8 @@ async def delete_model( payload=JSONCodec.dumps(payload), key=key, user=user, + api_config=api_config, + request=request, ) await publish_event( request, @@ -853,14 +876,15 @@ async def show_model_info( raise HTTPException(status_code=400, detail=ERROR_MESSAGES.MODEL_NOT_FOUND(model)) url_idx = random.choice(models[model]['urls']) - url = (await Config.get('ollama.base_urls', []))[url_idx] - key = get_api_key(url_idx, url, (await Config.get('ollama.api_configs', {}))) + url, api_config, key = await get_ollama_connection(url_idx) return await send_request( f'{url}/api/show', payload=JSONCodec.dumps(payload), key=key, user=user, + api_config=api_config, + request=request, ) @@ -914,6 +938,8 @@ async def embed( payload=form_data.model_dump_json(exclude_none=True).encode(), key=key, user=user, + api_config=api_config, + request=request, ) @@ -965,6 +991,8 @@ async def embeddings( payload=form_data.model_dump_json(exclude_none=True).encode(), key=key, user=user, + api_config=api_config, + request=request, ) @@ -1022,6 +1050,8 @@ async def generate_completion( user=user, stream=True, passthrough=True, + api_config=api_config, + request=request, ) @@ -1493,8 +1523,15 @@ async def get_openai_models( model_list = await get_all_models(request, user=user) raw_models = model_list['models'] else: - url = (await Config.get('ollama.base_urls', []))[url_idx] - model_list = await send_request(f'{url}/api/tags', 'GET') + url, api_config, key = await get_ollama_connection(url_idx) + model_list = await send_request( + f'{url}/api/tags', + 'GET', + key=key, + user=user, + api_config=api_config, + request=request, + ) raw_models = model_list.get('models', []) now_ts = int(time.time()) From af6b82a18cc058b43ca1dc13ccf970f242e39a78 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 28 Sep 2026 00:11:04 +0400 Subject: [PATCH 43/70] refac --- backend/open_webui/utils/middleware.py | 66 ++++++++++---------------- 1 file changed, 25 insertions(+), 41 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 47f7617554..64adaef668 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1774,19 +1774,10 @@ async def get_image_urls(delta_images, request, metadata, user) -> list[str]: return image_urls -async def add_file_context(messages: list, chat_id: str, user) -> list: +def add_file_context(messages: list) -> list: """ Add file URLs to messages for native function calling. """ - if not is_saved_chat_id(chat_id): - return messages - - chat = await Chats.get_chat_by_id_and_user_id(chat_id, user.id) - if not chat: - return messages - - history = chat.chat.get('history', {}) - stored_messages = get_message_list(history.get('messages', {}), history.get('currentId')) def format_file_tag(file): # Every file reaching here has a url or a chat id, so id is always set. @@ -1799,20 +1790,13 @@ async def add_file_context(messages: list, chat_id: str, user) -> list: attrs += f' name="{file["name"]}"' return f'' - # Pair only user-role messages from both lists to avoid misalignment. - # After process_messages_with_output(), assistant messages with tool calls - # are expanded into multiple messages (assistant + tool results), making - # the payload message list longer than the stored message list. A naive - # positional zip() would pair user messages with wrong stored messages, - # causing later images to lose their file context (see #21878). - user_messages = [m for m in messages if m.get('role') == 'user'] - stored_user_messages = [m for m in stored_messages if m.get('role') == 'user'] - - for message, stored_message in zip(user_messages, stored_user_messages): + for message in messages: + if message.get('role') != 'user': + continue # Chat references carry no url - they are addressed by id via view_chat. attached_files = [ file - for file in stored_message.get('files', []) + for file in message.get('files', []) if (file.get('url') and not file.get('url').startswith('data:')) or (file.get('type') == 'chat' and file.get('id')) ] @@ -2277,6 +2261,7 @@ def strip_reasoning_details(output: list) -> list: def process_messages_with_output( messages: list[dict], reasoning_format: str | None = None, + include_file_context: bool = False, ) -> list[dict]: """ Process messages with OR-aligned output items for LLM consumption. @@ -2302,10 +2287,15 @@ def process_messages_with_output( continue clean_message = dict(message) - for key in ('id', 'files', 'output', 'model', 'contextSummary', 'context_summary', 'usage'): + for key in ('id', 'output', 'model', 'contextSummary', 'context_summary', 'usage'): clean_message.pop(key, None) processed.append(clean_message) + if include_file_context: + add_file_context(processed) + for message in processed: + message.pop('files', None) + return processed @@ -2432,6 +2422,17 @@ async def process_chat_payload(request, form_data, user, metadata, model): # which the frontend strips, causing tool calls to be merged into content. chat_id = metadata.get('chat_id') user_message_id = metadata.get('user_message_id') + payload_tools = form_data.get('tools', None) # snapshot before filters + chat = await Chats.get_chat_by_id(chat_id) if is_saved_chat_id(chat_id) else None + is_note_chat = bool(chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note') + use_builtin_tools = is_note_chat or ( + bool(metadata.get('session_id')) + and metadata.get('params', {}).get('function_calling') != 'legacy' + and (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('builtin_tools', True) + ) + metadata['include_file_context'] = bool( + chat and chat.user_id == user.id and payload_tools is None and use_builtin_tools + ) if is_saved_chat_id(chat_id) and user_message_id: db_messages = await load_messages_from_db(chat_id, user_message_id) @@ -2468,8 +2469,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): if f.get('url') ], ] - # Strip files field — it's been incorporated into content - message.pop('files', None) if regeneration_prompt: form_data['messages'].append({'role': 'user', 'content': regeneration_prompt}) @@ -2516,6 +2515,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): form_data['messages'] = process_messages_with_output( form_data.get('messages', []), reasoning_format=get_reasoning_format(model), + include_file_context=metadata['include_file_context'], ) form_data['messages'] = sanitize_tool_pairs(form_data['messages']) @@ -2637,7 +2637,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): form_data['files'] = files variables = form_data.pop('variables', None) - payload_tools = form_data.get('tools', None) # snapshot before filters # Process the form_data through the pipeline try: @@ -2770,12 +2769,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): available_skills = [] terminal_skills = [] view_skill_ids = [] - chat = None - if is_saved_chat_id(metadata.get('chat_id')): - chat = await Chats.get_chat_by_id(metadata['chat_id']) - - is_note_chat = bool(chat and (chat.meta or {}).get('internal') is True and (chat.meta or {}).get('type') == 'note') - if is_note_chat: note_id = (chat.meta or {}).get('note_id') note = await Notes.get_note_by_id(note_id) if note_id else None @@ -2799,12 +2792,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): if note_files: files = [*(files or []), *note_files] - use_builtin_tools = is_note_chat or ( - bool(metadata.get('session_id')) - and metadata.get('params', {}).get('function_calling') != 'legacy' - and (model.get('info', {}).get('meta', {}).get('capabilities') or {}).get('builtin_tools', True) - ) - if skill_ids or use_builtin_tools: from open_webui.models.skills import Skills as SkillsModel from open_webui.utils.terminals import ( @@ -3075,10 +3062,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): # Only inject when the request originates from the UI (identified by session_id). # API callers don't expect hidden tools; they can explicitly request tools via tool_ids. if use_builtin_tools: - # Add file context to user messages - chat_id = metadata.get('chat_id') - form_data['messages'] = await add_file_context(form_data.get('messages', []), chat_id, user) - if (model.get('info', {}).get('meta', {}).get('builtinTools') or {}).get('knowledge', True): from html import escape @@ -3554,6 +3537,7 @@ async def drain_approved_tool_calls(request, form_data, user, model, metadata) - form_data['messages'] = process_messages_with_output( db_messages, reasoning_format=get_reasoning_format(model), + include_file_context=metadata.get('include_file_context', False), ) form_data['messages'] = sanitize_tool_pairs(form_data['messages']) From fdae17f8a6fc163f925b73286622eae32f029308 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 28 Sep 2026 00:14:36 +0400 Subject: [PATCH 44/70] refac --- src/lib/components/common/Dropdown.svelte | 8 +++++++- src/lib/components/layout/Sidebar/ChatMenu.svelte | 9 +-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/lib/components/common/Dropdown.svelte b/src/lib/components/common/Dropdown.svelte index e0ac7307aa..781785020a 100644 --- a/src/lib/components/common/Dropdown.svelte +++ b/src/lib/components/common/Dropdown.svelte @@ -14,6 +14,9 @@ /** Close when clicking outside */ export let closeOnOutsideClick = true; + /** Close action menus after selection. Submenu triggers prevent the default click. */ + export let closeOnSelect = false; + /** Called when open/close state changes */ export let onOpenChange: (state: boolean) => void = () => {}; @@ -350,7 +353,10 @@ style:max-height={resolvedMaxHeight} style:overflow-y="auto" transition:flyAndScale - on:click={(e) => e.stopPropagation()} + on:click={(e) => { + e.stopPropagation(); + if (closeOnSelect && !e.defaultPrevented) closeDropdown(); + }} on:pointerdown={(e) => e.stopPropagation()} > diff --git a/src/lib/components/layout/Sidebar/ChatMenu.svelte b/src/lib/components/layout/Sidebar/ChatMenu.svelte index b3286d80a3..1cd001f75a 100644 --- a/src/lib/components/layout/Sidebar/ChatMenu.svelte +++ b/src/lib/components/layout/Sidebar/ChatMenu.svelte @@ -45,7 +45,6 @@ export let chatId = ''; export let archived = false; - let dropdown: Dropdown; let show = false; let pinned = false; @@ -292,7 +291,7 @@ {/if} { if (state) { @@ -313,7 +312,6 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { - dropdown.close(); shareHandler(); }} > @@ -369,7 +367,6 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { - dropdown.close(); renameHandler(); }} > @@ -381,7 +378,6 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { - dropdown.close(); markUnreadHandler(); }} > @@ -395,7 +391,6 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { - dropdown.close(); pinHandler(); }} > @@ -413,7 +408,6 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { - dropdown.close(); cloneChatHandler(); }} > @@ -469,7 +463,6 @@ draggable="false" class="flex h-[1.6875rem] gap-2 items-center rounded-xl px-2 text-[0.8125rem] cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900 w-full" on:click={() => { - dropdown.close(); deleteHandler(); }} > From e8d6a8734a96cbccc434e7ade89c459d564e896e Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:48:26 +0200 Subject: [PATCH 45/70] fix: model upload, download and unload ignore a connection's custom headers and auth type (#31490) Uploading or downloading a GGUF model to an Ollama connection sent neither the key nor the connection's custom headers, so it failed behind gateways such as Cloudflare Access and on servers that need a key. Unloading a model dropped the custom headers and sent the key as a Bearer token even with the authentication type set to None, for Ollama and llama.cpp connections alike. These requests now use the connection's headers and authentication type the same as chatting and the Manage Ollama dialog already do. Follow-up to #31489. --- backend/open_webui/main.py | 13 +++++-------- backend/open_webui/routers/ollama.py | 28 ++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 3e0f9db89f..4eca154fa1 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -237,6 +237,7 @@ from open_webui.utils.chat_variables import ( normalize_chat_variables, ) from open_webui.utils.embeddings import generate_embeddings +from open_webui.utils.headers import get_headers_and_cookies from open_webui.utils.json_codec import JSONCodec from open_webui.utils.json_response import apply_orjson_http_json from open_webui.utils.logger import start_logger @@ -994,14 +995,12 @@ async def unload_model(request: Request, form_data: ModelUnloadForm, user=Depend try: timeout = aiohttp.ClientTimeout(total=30) async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: - headers = { - 'Content-Type': 'application/json', - **({'Authorization': f'Bearer {key}'} if key else {}), - } + headers, cookies = await get_headers_and_cookies(request, url, key, api_config, user=user) async with session.post( f'{url}/api/generate', data=payload, headers=headers, + cookies=cookies, ) as r: if not r.ok: errors.append({'url_idx': idx, 'error': await r.text()}) @@ -1035,14 +1034,12 @@ async def unload_model(request: Request, form_data: ModelUnloadForm, user=Depend try: timeout = aiohttp.ClientTimeout(total=30) async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: - headers = { - 'Content-Type': 'application/json', - **({'Authorization': f'Bearer {key}'} if key else {}), - } + headers, cookies = await get_headers_and_cookies(request, base_url, key, api_config, user=user) async with session.post( f'{root_url}/models/unload', json={'model': actual_model}, headers=headers, + cookies=cookies, ) as r: if not r.ok: detail = await r.text() diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index 188cb5d7da..d354986d37 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -1581,6 +1581,8 @@ async def download_file_stream( file_url: str, file_path: str, file_name: str, + ollama_headers: dict, + ollama_cookies: dict, chunk_size: int = AIOHTTP_FILE_STREAM_CHUNK_SIZE, ): """Stream a model file download from *file_url*, then push the blob to Ollama.""" @@ -1619,7 +1621,12 @@ async def download_file_stream( async with session.post( blob_url, data=blob_chunks(), - headers={'Content-Length': str(blob_size)}, + headers={ + **ollama_headers, + 'Content-Type': 'application/octet-stream', + 'Content-Length': str(blob_size), + }, + cookies=ollama_cookies, ssl=AIOHTTP_CLIENT_SESSION_SSL, timeout=aiohttp.ClientTimeout(total=30), ) as blob_resp: @@ -1646,15 +1653,17 @@ async def download_model( detail='Invalid file_url. Only URLs from allowed hosts are permitted.', ) - url = (await Config.get('ollama.base_urls', []))[url_idx if url_idx is not None else 0] + url, api_config, key = await get_ollama_connection(url_idx if url_idx is not None else 0) file_name = parse_huggingface_url(form_data.url) if not file_name: return None + headers, cookies = await get_headers_and_cookies(request, url, key, api_config, user=user) + file_path = os.path.join(UPLOAD_DIR, file_name) return StreamingResponse( - download_file_stream(url, form_data.url, file_path, file_name), + download_file_stream(url, form_data.url, file_path, file_name, headers, cookies), ) @@ -1667,7 +1676,8 @@ async def upload_model( user=Depends(get_admin_user), ): """Upload a local model file, push it as a blob, and create the model in Ollama.""" - ollama_url = (await Config.get('ollama.base_urls', []))[url_idx if url_idx is not None else 0] + ollama_url, api_config, key = await get_ollama_connection(url_idx if url_idx is not None else 0) + headers, cookies = await get_headers_and_cookies(request, ollama_url, key, api_config, user=user) filename = os.path.basename(file.filename) file_path = os.path.join(UPLOAD_DIR, filename) @@ -1709,7 +1719,12 @@ async def upload_model( async with session.post( blob_url, data=blob_chunks(), - headers={'Content-Length': str(total_size)}, + headers={ + **headers, + 'Content-Type': 'application/octet-stream', + 'Content-Length': str(total_size), + }, + cookies=cookies, ssl=AIOHTTP_CLIENT_SESSION_SSL, timeout=get_client_timeout(), ) as resp: @@ -1731,7 +1746,8 @@ async def upload_model( async with session.post( f'{ollama_url}/api/create', - headers={'Content-Type': 'application/json'}, + headers=headers, + cookies=cookies, data=JSONCodec.dumps(create_payload), ssl=AIOHTTP_CLIENT_SESSION_SSL, timeout=get_client_timeout(), From fc9ad75164f8d5858fc60f07122dc5554264accd Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:51:59 +0200 Subject: [PATCH 46/70] fix: admins can still read and change other users' chats with ENABLE_ADMIN_CHAT_ACCESS off (#31416) With ENABLE_ADMIN_CHAT_ACCESS turned off, opening another user's chat was refused, but through direct API requests an admin could still get the whole chat back in the reply to editing or deleting one of its messages, grant themselves read access in the chat's share settings, clone a chat someone shared privately with another user, or delete the chat. They could also send messages into it, attach it as context to their own chat, approve its tool calls, and list or stop its running replies. All of these are now refused for an admin on another user's chat, the same as opening it. With the setting on, admins keep full access as before. Fixes #31413 --- backend/open_webui/main.py | 14 ++++++++------ backend/open_webui/retrieval/utils.py | 5 ++++- backend/open_webui/routers/chats.py | 16 +++++++++------- backend/open_webui/utils/tool_approval.py | 3 ++- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 4eca154fa1..9573d1df91 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1487,7 +1487,9 @@ async def chat_completion( asyncio.create_task(run_initial_title_generation()) else: # Existing chat — verify ownership - if not await Chats.is_chat_owner(chat_id, user.id) and user.role != 'admin': + if not await Chats.is_chat_owner(chat_id, user.id) and not ( + user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS + ): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.DEFAULT(), @@ -2075,7 +2077,7 @@ async def verify_chat_ownership(chat_id: str | None, user) -> None: detail='Channel chats are not supported on this endpoint', ) - if user.role != 'admin' and not await Chats.is_chat_owner(chat_id, user.id): + if not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS) and not await Chats.is_chat_owner(chat_id, user.id): raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.DEFAULT(), @@ -2139,11 +2141,11 @@ async def list_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De socket_id = get_temporary_chat_session_id(chat_id) if socket_id: owner_id = get_user_id_from_session_pool(socket_id) - if owner_id != user.id and user.role != 'admin': + if owner_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): return {'task_ids': []} else: chat = await Chats.get_chat_by_id(chat_id) - if chat is None or (chat.user_id != user.id and user.role != 'admin'): + if chat is None or (chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS)): return {'task_ids': []} task_ids = await list_task_ids_by_item_id(request.app.state.redis, chat_id) @@ -2158,11 +2160,11 @@ async def stop_tasks_by_chat_id_endpoint(request: Request, chat_id: str, user=De chat = None if socket_id: owner_id = get_user_id_from_session_pool(socket_id) - if owner_id != user.id and user.role != 'admin': + if owner_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND) else: chat = await Chats.get_chat_by_id(chat_id) - if chat is None or (chat.user_id != user.id and user.role != 'admin'): + if chat is None or (chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS)): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND) result = await stop_item_tasks(request.app.state.redis, chat_id) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index b1597aa2db..58a4da1f1b 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -30,6 +30,7 @@ from open_webui.env import ( AIOHTTP_CLIENT_SESSION_SSL, AIOHTTP_CLIENT_TIMEOUT, BYPASS_RETRIEVAL_ACCESS_CONTROL, + ENABLE_ADMIN_CHAT_ACCESS, ENABLE_FORWARD_USER_INFO_HEADERS, ENABLE_RETRIEVAL_UNSCOPED_COLLECTIONS, MPS_INFERENCE_LOCK, @@ -1462,7 +1463,9 @@ async def get_sources_from_items( elif item.get('type') == 'chat': # Chat Attached chat = await Chats.get_chat_by_id(item.get('id')) - has_read_access = bool(chat and (user.role == 'admin' or chat.user_id == user.id)) + has_read_access = bool( + chat and ((user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS) or chat.user_id == user.id) + ) if chat and not has_read_access: has_read_access = await AccessGrants.has_access( diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index e46fed259c..e6194d0f64 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -680,7 +680,7 @@ async def export_single_chat_stats( ) # Verify the chat belongs to the user (unless admin) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1428,7 +1428,7 @@ async def update_chat_message_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1489,7 +1489,7 @@ async def delete_chat_message_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1537,7 +1537,7 @@ async def send_chat_message_event_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - if chat.user_id != user.id and user.role != 'admin': + if chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -1584,6 +1584,8 @@ async def delete_chat_by_id( # not be reachable for a chat the caller may not delete. if user.role == 'admin': chat = await Chats.get_chat_by_id(id, db=db) + if chat and chat.user_id != user.id and not ENABLE_ADMIN_CHAT_ACCESS: + chat = None else: if not await has_permission(user.id, 'chat.delete', await Config.get('user.permissions')): raise HTTPException( @@ -1850,7 +1852,7 @@ async def clone_shared_chat_by_id( # Enforce access grants (owner and admins bypass) shared = await SharedChats.get_by_id(id, db=db) - if shared and user.role != 'admin' and shared.user_id != user.id: + if shared and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS) and shared.user_id != user.id: has_grant = await is_open_shared_chat(shared, db=db) or await AccessGrants.has_access( user_id=user.id, resource_type='shared_chat', @@ -2042,7 +2044,7 @@ async def update_shared_chat_access_by_id( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): - if user.role == 'admin': + if user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: chat = await Chats.get_chat_by_id(id, db=db) else: chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) @@ -2078,7 +2080,7 @@ async def get_shared_chat_access_by_id( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): - if user.role == 'admin': + if user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS: chat = await Chats.get_chat_by_id(id, db=db) else: chat = await Chats.get_chat_by_id_and_user_id(id, user.id, db=db) diff --git a/backend/open_webui/utils/tool_approval.py b/backend/open_webui/utils/tool_approval.py index c59b2d6316..e2c33e9a74 100644 --- a/backend/open_webui/utils/tool_approval.py +++ b/backend/open_webui/utils/tool_approval.py @@ -5,6 +5,7 @@ from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from open_webui.constants import ERROR_MESSAGES +from open_webui.env import ENABLE_ADMIN_CHAT_ACCESS from open_webui.models.chats import Chats from open_webui.socket.main import get_event_emitter from open_webui.utils.json_codec import JSONCodec @@ -25,7 +26,7 @@ async def resolve_tool_call_output( db: AsyncSession | None = None, ) -> dict: chat = await Chats.get_chat_by_id(chat_id, db=db) - if not chat or (chat.user_id != user.id and user.role != 'admin'): + if not chat or (chat.user_id != user.id and not (user.role == 'admin' and ENABLE_ADMIN_CHAT_ACCESS)): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, From b6f9679985b2a910038ce123a5ed3af2a6f7d207 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sun, 27 Sep 2026 23:52:15 +0200 Subject: [PATCH 47/70] refac: only open web, mail, phone and relative file links (#31491) File attachment links and the file links in code execution results now go through the same link check as links in chat messages, so only web, mail, phone and relative links are opened. --- src/lib/components/chat/Messages/CodeExecutionModal.svelte | 3 ++- src/lib/components/common/FileItem.svelte | 4 ++-- src/lib/components/common/FileItemModal.svelte | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/lib/components/chat/Messages/CodeExecutionModal.svelte b/src/lib/components/chat/Messages/CodeExecutionModal.svelte index 4b4ee0b7a7..fd33b7dd23 100644 --- a/src/lib/components/chat/Messages/CodeExecutionModal.svelte +++ b/src/lib/components/chat/Messages/CodeExecutionModal.svelte @@ -1,5 +1,6 @@ { @@ -62,7 +63,6 @@