From bcb71bb5206ac01d97a39fde8ecf0e0541dde636 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 18:01:04 -0500 Subject: [PATCH 001/404] feat: tasks --- ...d5bedd151_add_tasks_and_summary_to_chat.py | 28 +++ backend/open_webui/models/chats.py | 31 ++++ backend/open_webui/tools/builtin.py | 166 ++++++++++++++++++ backend/open_webui/utils/tools.py | 5 + src/lib/components/chat/Chat.svelte | 9 + src/lib/components/chat/MessageInput.svelte | 10 ++ .../components/chat/Messages/Message.svelte | 1 + .../Messages/ResponseMessage/TaskList.svelte | 84 +++++++++ src/lib/components/icons/Collapse.svelte | 17 ++ src/lib/components/icons/Expand.svelte | 22 +-- src/lib/components/icons/TaskList.svelte | 18 ++ .../workspace/Models/BuiltinTools.svelte | 4 + 12 files changed, 382 insertions(+), 13 deletions(-) create mode 100644 backend/open_webui/migrations/versions/a3dd5bedd151_add_tasks_and_summary_to_chat.py create mode 100644 src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte create mode 100644 src/lib/components/icons/Collapse.svelte create mode 100644 src/lib/components/icons/TaskList.svelte diff --git a/backend/open_webui/migrations/versions/a3dd5bedd151_add_tasks_and_summary_to_chat.py b/backend/open_webui/migrations/versions/a3dd5bedd151_add_tasks_and_summary_to_chat.py new file mode 100644 index 0000000000..20a3152cfe --- /dev/null +++ b/backend/open_webui/migrations/versions/a3dd5bedd151_add_tasks_and_summary_to_chat.py @@ -0,0 +1,28 @@ +"""Add tasks and summary columns to chat table + +Revision ID: a3dd5bedd151 +Revises: b2c3d4e5f6a7 +Create Date: 2026-03-29 22:15:00.000000 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision: str = 'a3dd5bedd151' +down_revision: Union[str, None] = 'b2c3d4e5f6a7' +branch_labels: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = None + + +def upgrade() -> None: + op.add_column('chat', sa.Column('tasks', sa.JSON(), nullable=True)) + op.add_column('chat', sa.Column('summary', sa.Text(), nullable=True)) + + +def downgrade() -> None: + op.drop_column('chat', 'summary') + op.drop_column('chat', 'tasks') diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index f19a5e7537..d9caf864ee 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -54,6 +54,9 @@ class Chat(Base): meta = Column(JSON, server_default='{}') folder_id = Column(Text, nullable=True) + tasks = Column(JSON, nullable=True) + summary = Column(Text, nullable=True) + __table_args__ = ( # Performance indexes for common queries # WHERE folder_id = ... @@ -87,6 +90,9 @@ class ChatModel(BaseModel): meta: dict = {} folder_id: Optional[str] = None + tasks: Optional[list] = None + summary: Optional[str] = None + class ChatFile(Base): __tablename__ = 'chat_file' @@ -161,6 +167,9 @@ class ChatResponse(BaseModel): meta: dict = {} folder_id: Optional[str] = None + tasks: Optional[list] = None + summary: Optional[str] = None + class ChatTitleIdResponse(BaseModel): id: str @@ -1552,5 +1561,27 @@ class ChatTable: return [ChatModel.model_validate(chat) for chat in all_chats] + def update_chat_tasks_by_id(self, id: str, tasks: list[dict]) -> Optional[ChatModel]: + """Update the tasks list on a chat.""" + try: + with get_db_context() as db: + chat = db.get(Chat, id) + if chat is None: + return None + chat.tasks = tasks + db.commit() + db.refresh(chat) + return ChatModel.model_validate(chat) + except Exception: + return None + + def get_chat_tasks_by_id(self, id: str) -> list[dict]: + """Read the tasks list from a chat (lightweight column query).""" + with get_db_context() as db: + result = db.query(Chat.tasks).filter_by(id=id).first() + if result is None or result[0] is None: + return [] + return result[0] + Chats = ChatTable() diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index f02a082c42..d9c93eb93c 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2324,3 +2324,169 @@ async def view_skill( except Exception as e: log.exception(f'view_skill error: {e}') return json.dumps({'error': str(e)}) + + +# ============================================================================= +# TASK MANAGEMENT TOOLS +# ============================================================================= + +from pydantic import BaseModel, Field +from typing import Literal + +VALID_TASK_STATUSES = {'pending', 'in_progress', 'completed', 'cancelled'} + + +class TaskItem(BaseModel): + id: Optional[str] = Field(None, description="Unique identifier for the task. Auto-generated if omitted.") + content: Optional[str] = Field(None, description="Task description. Aliases: title, name, description.") + status: Literal['pending', 'in_progress', 'completed', 'cancelled'] = Field('pending', description="Task status.") + + +async def update_tasks( + tasks: list[TaskItem], + overwrite: bool = True, + __chat_id__: str = None, + __message_id__: str = None, + __event_emitter__: callable = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Create or update tasks for the current chat. By default replaces the + entire task list. Set overwrite=false to update individual tasks by id + while preserving the rest. + + Only ONE task should be in_progress at a time. Mark tasks completed + immediately when done. + + :param tasks: List of task items. Each must have: id (string, unique identifier), content (string, task description — required for new tasks), status (one of: pending, in_progress, completed, cancelled). + :param overwrite: If true (default), replaces the entire task list. If false, updates/adds tasks by id while keeping existing ones. + :return: JSON with the full task list and summary counts + """ + if __chat_id__ is None: + return json.dumps({'error': 'Chat context not available'}) + + try: + def _to_dict(task) -> dict: + """Convert TaskItem or dict to plain dict.""" + if hasattr(task, 'model_dump'): + d = task.model_dump(exclude_none=True) + # Include any extra fields the model sent + if hasattr(task, 'model_extra') and task.model_extra: + d.update(task.model_extra) + return d + return dict(task) if not isinstance(task, dict) else task + + def _resolve_content(d: dict) -> str: + """Accept content, title, name, or description as the task text.""" + for key in ('content', 'title', 'name', 'description'): + val = str(d.get(key, '')).strip() + if val: + return val + return '' + + def _resolve_id(d: dict, idx: int) -> str: + """Use provided id, or auto-generate from index.""" + item_id = str(d.get('id', '') or '').strip() + return item_id if item_id else str(idx + 1) + + if overwrite: + # Full replacement — validate and write + all_tasks = [] + for idx, task in enumerate(tasks): + d = _to_dict(task) + item_id = _resolve_id(d, idx) + content = _resolve_content(d) + if not content: + continue + + status = str(d.get('status', 'pending')).strip().lower() + if status not in VALID_TASK_STATUSES: + status = 'pending' + + all_tasks.append({ + 'id': item_id, + 'content': content, + 'status': status, + }) + else: + # Partial update — merge by id + existing_tasks = Chats.get_chat_tasks_by_id(__chat_id__) + existing_by_id = {t['id']: t for t in existing_tasks} + + seen_ids = set() + for idx, task in enumerate(tasks): + d = _to_dict(task) + item_id = _resolve_id(d, len(existing_tasks) + idx) + + seen_ids.add(item_id) + + if item_id in existing_by_id: + resolved = _resolve_content(d) + if resolved: + existing_by_id[item_id]['content'] = resolved + status = str(d.get('status', '')).strip().lower() + if status and status in VALID_TASK_STATUSES: + existing_by_id[item_id]['status'] = status + else: + content = _resolve_content(d) + if not content: + continue + + status = str(d.get('status', 'pending')).strip().lower() + if status not in VALID_TASK_STATUSES: + status = 'pending' + + existing_by_id[item_id] = { + 'id': item_id, + 'content': content, + 'status': status, + } + + # Preserve order of existing, append new + all_tasks = [] + for t in existing_tasks: + if t['id'] in existing_by_id: + all_tasks.append(existing_by_id[t['id']]) + for item_id in seen_ids: + if not any(t['id'] == item_id for t in existing_tasks): + all_tasks.append(existing_by_id[item_id]) + + # Persist to DB + Chats.update_chat_tasks_by_id(__chat_id__, all_tasks) + + # Emit to frontend for real-time UI update + if __event_emitter__: + await __event_emitter__( + { + 'type': 'chat:message:tasks', + 'data': { + 'tasks': all_tasks, + }, + } + ) + + # Build summary counts + pending = sum(1 for t in all_tasks if t['status'] == 'pending') + in_progress = sum(1 for t in all_tasks if t['status'] == 'in_progress') + completed = sum(1 for t in all_tasks if t['status'] == 'completed') + cancelled = sum(1 for t in all_tasks if t['status'] == 'cancelled') + + return json.dumps( + { + 'tasks': all_tasks, + 'summary': { + 'total': len(all_tasks), + 'pending': pending, + 'in_progress': in_progress, + 'completed': completed, + 'cancelled': cancelled, + }, + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f'update_tasks error: {e}') + return json.dumps({'error': str(e)}) + + diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 226830a1fa..391c45dcbf 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -85,6 +85,7 @@ from open_webui.tools.builtin import ( view_file, view_knowledge_file, view_skill, + update_tasks, ) import copy @@ -503,6 +504,10 @@ def get_builtin_tools( if extra_params.get('__skill_ids__'): builtin_functions.append(view_skill) + # Task management - break down complex work into trackable steps + if is_builtin_tool_enabled('tasks'): + builtin_functions.append(update_tasks) + for func in builtin_functions: callable = get_async_tool_function_and_apply_extra_params( func, diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 45c2e01e2b..19dae7cd3e 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -159,6 +159,8 @@ let chat = null; let tags = []; + let chatTasks = []; + let history = { messages: {}, currentId: null @@ -449,6 +451,8 @@ message.content = data.content; } else if (type === 'chat:message:files' || type === 'files') { message.files = data.files; + } else if (type === 'chat:message:tasks') { + chatTasks = data.tasks; } else if (type === 'chat:message:embeds' || type === 'embeds') { message.embeds = data.embeds; @@ -1156,6 +1160,7 @@ chatFiles = []; params = {}; taskIds = null; + chatTasks = []; if ($page.url.searchParams.get('youtube')) { await uploadWeb(`https://www.youtube.com/watch?v=${$page.url.searchParams.get('youtube')}`); @@ -1268,6 +1273,9 @@ params = chatContent?.params ?? {}; chatFiles = chatContent?.files ?? []; + // Load tasks from chat-level DB field + chatTasks = chat?.tasks ?? []; + autoScroll = true; await tick(); @@ -2863,6 +2871,7 @@ {createMessagePair} {onUpload} messageQueue={$chatRequestQueues[$chatId] ?? []} + {chatTasks} onQueueSendNow={async (id) => { const queue = $chatRequestQueues[$chatId] ?? []; const item = queue.find((m) => m.id === id); diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 602200deed..2768cb481e 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -99,6 +99,7 @@ import InputModal from '../common/InputModal.svelte'; import Expand from '../icons/Expand.svelte'; import QueuedMessageItem from './MessageInput/QueuedMessageItem.svelte'; + import TaskList from './Messages/ResponseMessage/TaskList.svelte'; const i18n = getContext('i18n'); @@ -140,6 +141,8 @@ export let onQueueEdit: (id: string) => void = () => {}; export let onQueueDelete: (id: string) => void = () => {}; + export let chatTasks = []; + let inputContent = null; let showInputVariablesModal = false; @@ -1217,6 +1220,13 @@ on:click={() => createMessagePair(prompt)} /> + + {#if chatTasks.length > 0} +
+ +
+ {/if} + {#if messageQueue.length > 0}
+ import { getContext } from 'svelte'; + import { slide } from 'svelte/transition'; + import TaskListIcon from '$lib/components/icons/TaskList.svelte'; + import ChevronDown from '$lib/components/icons/ChevronDown.svelte'; + import ChevronUp from '$lib/components/icons/ChevronUp.svelte'; + + const i18n = getContext('i18n'); + + export let tasks: Array<{ id: string; content: string; status: string }> = []; + + let collapsed = false; + + $: completedCount = tasks.filter((t) => t.status === 'completed').length; + $: totalCount = tasks.length; + $: hasActive = tasks.some((t) => t.status === 'pending' || t.status === 'in_progress'); + + +{#if tasks.length > 0 && hasActive} +
+ +
+
+ + + {completedCount} {$i18n.t('out of')} {totalCount} {$i18n.t('tasks completed')} + +
+ + +
+ + + {#if !collapsed} +
+ {#each tasks as task, idx (task.id)} +
+ + {#if task.status === 'completed'} + + + + {:else if task.status === 'in_progress'} + + + + {:else if task.status === 'cancelled'} + + + + {:else} + + + + {/if} + + + {idx + 1}. {task.content} + +
+ {/each} +
+ {/if} +
+{/if} diff --git a/src/lib/components/icons/Collapse.svelte b/src/lib/components/icons/Collapse.svelte new file mode 100644 index 0000000000..05ce616dad --- /dev/null +++ b/src/lib/components/icons/Collapse.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/icons/Expand.svelte b/src/lib/components/icons/Expand.svelte index e11230aa37..a645436dcd 100644 --- a/src/lib/components/icons/Expand.svelte +++ b/src/lib/components/icons/Expand.svelte @@ -1,21 +1,17 @@ + + + + + diff --git a/src/lib/components/icons/TaskList.svelte b/src/lib/components/icons/TaskList.svelte new file mode 100644 index 0000000000..850660c1df --- /dev/null +++ b/src/lib/components/icons/TaskList.svelte @@ -0,0 +1,18 @@ + + + + + + + + + + diff --git a/src/lib/components/workspace/Models/BuiltinTools.svelte b/src/lib/components/workspace/Models/BuiltinTools.svelte index b1f925302b..cc94cddb33 100644 --- a/src/lib/components/workspace/Models/BuiltinTools.svelte +++ b/src/lib/components/workspace/Models/BuiltinTools.svelte @@ -42,6 +42,10 @@ code_interpreter: { label: $i18n.t('Code Interpreter'), description: $i18n.t('Execute code') + }, + tasks: { + label: $i18n.t('Task Management'), + description: $i18n.t('Break down complex requests into trackable steps') } }; From 2388dd7dc3530b5dd5419c5d0bb1bcdcb7544099 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 18:40:09 -0500 Subject: [PATCH 002/404] refac --- .../Messages/ResponseMessage/TaskList.svelte | 39 +++++++++++++--- .../chat/ModelSelector/ModelItem.svelte | 2 + .../chat/ModelSelector/ModelItemMenu.svelte | 32 +++++++++++++ .../chat/ModelSelector/Selector.svelte | 46 +++++++++++++++++++ 4 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte b/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte index b8541a3ffa..79a9f42d5d 100644 --- a/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte @@ -18,7 +18,7 @@ {#if tasks.length > 0 && hasActive}
@@ -26,7 +26,10 @@
- {completedCount} {$i18n.t('out of')} {totalCount} {$i18n.t('tasks completed')} + {completedCount} + {$i18n.t('out of')} + {totalCount} + {$i18n.t('tasks completed')}
@@ -50,19 +53,43 @@
{#if task.status === 'completed'} - + {:else if task.status === 'in_progress'} - + {:else if task.status === 'cancelled'} - + {:else} - + {/if} diff --git a/src/lib/components/chat/ModelSelector/ModelItem.svelte b/src/lib/components/chat/ModelSelector/ModelItem.svelte index b5a29ffe96..cd5fe453c3 100644 --- a/src/lib/components/chat/ModelSelector/ModelItem.svelte +++ b/src/lib/components/chat/ModelSelector/ModelItem.svelte @@ -26,6 +26,7 @@ export let unloadModelHandler: (modelValue: string) => void = () => {}; export let pinModelHandler: (modelId: string) => void = () => {}; + export let deleteModelHandler: (model: any) => void = () => {}; export let onClick: () => void = () => {}; @@ -255,6 +256,7 @@ bind:show={showMenu} model={item.model} {pinModelHandler} + {deleteModelHandler} copyLinkHandler={() => { copyLinkHandler(item.model); }} diff --git a/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte b/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte index 65d90bf2a3..d0f46b2624 100644 --- a/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte +++ b/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte @@ -18,6 +18,7 @@ export let pinModelHandler: (modelId: string) => void = () => {}; export let copyLinkHandler: Function = () => {}; + export let deleteModelHandler: Function = () => {}; export let onClose: Function = () => {}; @@ -66,6 +67,37 @@
{$i18n.t('Edit')}
+ {#if $user?.role === 'admin' && model?.owned_by === 'ollama'} + + {/if} +
{/if} diff --git a/src/lib/components/chat/ModelSelector/Selector.svelte b/src/lib/components/chat/ModelSelector/Selector.svelte index 1a7a3dfc97..3d316562d5 100644 --- a/src/lib/components/chat/ModelSelector/Selector.svelte +++ b/src/lib/components/chat/ModelSelector/Selector.svelte @@ -8,6 +8,7 @@ dayjs.extend(relativeTime); import Spinner from '$lib/components/common/Spinner.svelte'; + import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; import { flyAndScale } from '$lib/utils/transitions'; import { createEventDispatcher, onMount, getContext, tick } from 'svelte'; @@ -375,6 +376,41 @@ } }; + let showDeleteConfirm = false; + let deleteModelTarget: any = null; + + const deleteModelHandler = async (model: any) => { + deleteModelTarget = model; + showDeleteConfirm = true; + }; + + const confirmDeleteModel = async () => { + const model = deleteModelTarget; + if (!model) return; + + const res = await deleteModel(localStorage.token, model.id).catch((error) => { + toast.error($i18n.t('Error deleting model: {{error}}', { error })); + }); + + if (res) { + toast.success($i18n.t('Model {{modelName}} deleted successfully', { modelName: model.name ?? model.id })); + + // If the deleted model was selected, clear the selection + if (value === model.id) { + value = ''; + } + + models.set( + await getModels( + localStorage.token, + $config?.features?.enable_direct_connections && ($settings?.directConnections ?? null) + ) + ); + } + + deleteModelTarget = null; + }; + const ITEM_HEIGHT = 42; const OVERSCAN = 10; @@ -388,6 +424,15 @@ ); + { + confirmDeleteModel(); + }} +/> + { @@ -646,6 +691,7 @@ {value} {pinModelHandler} {unloadModelHandler} + {deleteModelHandler} onClick={() => { value = item.value; selectedModelIdx = index; From 2040095050056d01c61aa597c5010445449a42c7 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 19:01:50 -0500 Subject: [PATCH 003/404] enh: shortcode emojis --- .../components/channel/MessageInput.svelte | 19 ++++ src/lib/components/chat/MessageInput.svelte | 21 +++- .../MessageInput/CommandSuggestionList.svelte | 17 ++++ .../chat/MessageInput/Commands/Emojis.svelte | 99 +++++++++++++++++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 src/lib/components/chat/MessageInput/Commands/Emojis.svelte diff --git a/src/lib/components/channel/MessageInput.svelte b/src/lib/components/channel/MessageInput.svelte index 0a7478b89d..ec00a944d0 100644 --- a/src/lib/components/channel/MessageInput.svelte +++ b/src/lib/components/channel/MessageInput.svelte @@ -622,6 +622,25 @@ } } }) + }, + { + char: ':', + allowSpaces: false, + command: ({ editor, range, props }) => { + // Convert the Unicode hex codepoint (e.g. "1F44B") to the actual emoji character (👋) + const codepoint = props.id; + const emoji = String.fromCodePoint(parseInt(codepoint, 16)); + editor.chain().focus().deleteRange(range).insertContent(emoji).run(); + }, + render: getSuggestionRenderer(CommandSuggestionList, { + i18n, + onSelect: (e) => { + document.getElementById('chat-input')?.focus(); + }, + + insertTextHandler: insertTextAtCursor, + onUpload: () => {} + }) } ]; loaded = true; diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 2768cb481e..e826f1c68f 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -407,7 +407,7 @@ let command = ''; export let showCommands = false; $: showCommands = - ['/', '#', '@', '$'].includes(command?.charAt(0)) || '\\#' === command?.slice(0, 2); + ['/', '#', '@', '$', ':'].includes(command?.charAt(0)) || '\\#' === command?.slice(0, 2); let suggestions = null; let showTools = false; @@ -1030,6 +1030,25 @@ document.getElementById('chat-input')?.focus(); }, + insertTextHandler: insertTextAtCursor, + onUpload: () => {} + }) + }, + { + char: ':', + allowSpaces: false, + command: ({ editor, range, props }) => { + // Convert the Unicode hex codepoint (e.g. "1F44B") to the actual emoji character (👋) + const codepoint = props.id; + const emoji = String.fromCodePoint(parseInt(codepoint, 16)); + editor.chain().focus().deleteRange(range).insertContent(emoji).run(); + }, + render: getSuggestionRenderer(CommandSuggestionList, { + i18n, + onSelect: (e) => { + document.getElementById('chat-input')?.focus(); + }, + insertTextHandler: insertTextAtCursor, onUpload: () => {} }) diff --git a/src/lib/components/chat/MessageInput/CommandSuggestionList.svelte b/src/lib/components/chat/MessageInput/CommandSuggestionList.svelte index 5308d4797f..3032ad1916 100644 --- a/src/lib/components/chat/MessageInput/CommandSuggestionList.svelte +++ b/src/lib/components/chat/MessageInput/CommandSuggestionList.svelte @@ -3,6 +3,7 @@ import Knowledge from './Commands/Knowledge.svelte'; import Models from './Commands/Models.svelte'; import Skills from './Commands/Skills.svelte'; + import Emojis from './Commands/Emojis.svelte'; export let char = ''; export let query = ''; @@ -135,6 +136,22 @@ } }} /> + {:else if char === ':'} + { + const { type, data } = e; + + if (type === 'emoji') { + command({ + id: data.name, + label: data.shortCodes[0] + }); + } + }} + /> {/if}
diff --git a/src/lib/components/chat/MessageInput/Commands/Emojis.svelte b/src/lib/components/chat/MessageInput/Commands/Emojis.svelte new file mode 100644 index 0000000000..fd06bf8c6a --- /dev/null +++ b/src/lib/components/chat/MessageInput/Commands/Emojis.svelte @@ -0,0 +1,99 @@ + + +{#if filteredItems.length > 0} +
+ {$i18n.t('Emojis')} +
+ + {#each filteredItems as emoji, emojiIdx} + + {/each} +{/if} From 6c2b2f2c3e5f4c86273c408b901b5af9b3c7d6d6 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 19:01:53 -0500 Subject: [PATCH 004/404] refac --- src/lib/components/common/RichTextInput/suggestions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/common/RichTextInput/suggestions.ts b/src/lib/components/common/RichTextInput/suggestions.ts index 7793b99337..4fc8132b72 100644 --- a/src/lib/components/common/RichTextInput/suggestions.ts +++ b/src/lib/components/common/RichTextInput/suggestions.ts @@ -109,7 +109,7 @@ export function getSuggestionRenderer(Component: any, ComponentProps = {}) { popup = null; try { - component.$destroy(); + component?.$destroy(); } catch (e) { console.error('Error unmounting component:', e); } From 012ce95f27d57bea8911bd63bfb923443c5797ae Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 19:09:13 -0500 Subject: [PATCH 005/404] enh: swipe to reply --- .../channel/Messages/Message.svelte | 151 ++++++++++++++++-- src/lib/components/channel/Navbar.svelte | 60 +++---- 2 files changed, 170 insertions(+), 41 deletions(-) diff --git a/src/lib/components/channel/Messages/Message.svelte b/src/lib/components/channel/Messages/Message.svelte index c1d1414f43..3923f9fb0d 100644 --- a/src/lib/components/channel/Messages/Message.svelte +++ b/src/lib/components/channel/Messages/Message.svelte @@ -65,6 +65,67 @@ let editedContent = null; let showDeleteConfirmDialog = false; + // Swipe-to-reply state + let swipeStartX = 0; + let swipeStartY = 0; + let swipeOffsetX = 0; + let isSwiping = false; + let swipeLocked = false; // locked to horizontal once determined + let swipeMessageEl: HTMLElement | null = null; + + const SWIPE_THRESHOLD = 60; + const SWIPE_MAX = 100; + const SWIPE_DEAD_ZONE = 10; + + const handleTouchStart = (e: TouchEvent) => { + if (disabled || edit || !onReply) return; + const touch = e.touches[0]; + swipeStartX = touch.clientX; + swipeStartY = touch.clientY; + swipeOffsetX = 0; + isSwiping = false; + swipeLocked = false; + }; + + const handleTouchMove = (e: TouchEvent) => { + if (disabled || edit || !onReply) return; + const touch = e.touches[0]; + const deltaX = touch.clientX - swipeStartX; + const deltaY = touch.clientY - swipeStartY; + + // Determine swipe direction from dead zone + if (!swipeLocked && (Math.abs(deltaX) > SWIPE_DEAD_ZONE || Math.abs(deltaY) > SWIPE_DEAD_ZONE)) { + if (Math.abs(deltaY) > Math.abs(deltaX)) { + // Vertical scroll — abort swipe tracking + isSwiping = false; + swipeLocked = true; + return; + } + // Horizontal swipe — lock in + swipeLocked = true; + isSwiping = true; + } + + if (!isSwiping) return; + + // Only allow right swipe + const clampedX = Math.max(0, deltaX); + // Dampen the motion beyond threshold for a rubber-band feel + swipeOffsetX = clampedX <= SWIPE_THRESHOLD + ? clampedX + : SWIPE_THRESHOLD + (clampedX - SWIPE_THRESHOLD) * 0.3; + swipeOffsetX = Math.min(swipeOffsetX, SWIPE_MAX); + }; + + const handleTouchEnd = () => { + if (isSwiping && swipeOffsetX >= SWIPE_THRESHOLD && onReply) { + onReply(message); + } + swipeOffsetX = 0; + isSwiping = false; + swipeLocked = false; + }; + const loadMessageData = async () => { if (message && message?.data === true) { const res = await getMessageData(localStorage.token, channel?.id, message.id); @@ -92,20 +153,39 @@ {#if message}
+ + {#if swipeOffsetX > 0} +
+
= SWIPE_THRESHOLD}> + +
+
+ {/if} + +
{#if !edit && !disabled}
+
{/if} @@ -561,4 +642,48 @@ background-color: transparent; } } + + /* Swipe-to-reply styles */ + .swipe-reply-wrapper { + touch-action: pan-y; + } + + .swipe-reply-indicator { + position: absolute; + left: 8px; + top: 0; + bottom: 0; + display: flex; + align-items: center; + justify-content: center; + z-index: 5; + pointer-events: none; + } + + .swipe-reply-icon { + display: flex; + align-items: center; + justify-content: center; + width: 32px; + height: 32px; + border-radius: 50%; + background-color: rgba(128, 128, 128, 0.15); + color: rgba(128, 128, 128, 0.8); + transition: background-color 0.15s, color 0.15s; + } + + .swipe-reply-icon--active { + background-color: rgba(59, 130, 246, 0.2); + color: rgb(59, 130, 246); + } + + :global(.dark) .swipe-reply-icon { + background-color: rgba(200, 200, 200, 0.1); + color: rgba(200, 200, 200, 0.6); + } + + :global(.dark) .swipe-reply-icon--active { + background-color: rgba(96, 165, 250, 0.2); + color: rgb(96, 165, 250); + } diff --git a/src/lib/components/channel/Navbar.svelte b/src/lib/components/channel/Navbar.svelte index a9c8043600..660b2175cc 100644 --- a/src/lib/components/channel/Navbar.svelte +++ b/src/lib/components/channel/Navbar.svelte @@ -153,7 +153,9 @@ {/if}
-
+
{#if channel} @@ -173,17 +175,17 @@ {#if channel?.user_count !== undefined} - + + +
{/if}
From 64da99a32218171d41b3af5acc14783de8dbdf49 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 19:17:12 -0500 Subject: [PATCH 006/404] refac --- src/lib/components/common/EmojiPicker.svelte | 49 +++++++++++++++++++- src/lib/stores/index.ts | 1 + 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/lib/components/common/EmojiPicker.svelte b/src/lib/components/common/EmojiPicker.svelte index aa3df2e584..de8ba54acf 100644 --- a/src/lib/components/common/EmojiPicker.svelte +++ b/src/lib/components/common/EmojiPicker.svelte @@ -11,6 +11,9 @@ import emojiGroups from '$lib/emoji-groups.json'; import emojiShortCodes from '$lib/emoji-shortcodes.json'; + import { settings } from '$lib/stores'; + import { updateUserSettings } from '$lib/apis/users'; + const i18n = getContext('i18n'); export let onClose = () => {}; @@ -20,12 +23,37 @@ export let user = null; export let selected = null; + const MAX_RECENT = 30; + let show = false; let emojis = emojiShortCodes; let search = ''; let flattenedEmojis = []; let emojiRows = []; + let saveDebounceTimer: ReturnType | null = null; + + $: recentEmojiNames = ($settings?.recentEmojis ?? []) + .filter((name) => emojiShortCodes[name]) + .slice(0, MAX_RECENT); + + function saveRecentEmoji(emojiName: string) { + // Remove if already present, then prepend + const updated = [emojiName, ...recentEmojiNames.filter((n) => n !== emojiName)].slice( + 0, + MAX_RECENT + ); + + // Update store immediately (reactive UI) + settings.set({ ...$settings, recentEmojis: updated }); + + // Debounce backend save (avoid API spam on rapid picks) + if (saveDebounceTimer) clearTimeout(saveDebounceTimer); + saveDebounceTimer = setTimeout(async () => { + await updateUserSettings(localStorage.token, { ui: { ...$settings, recentEmojis: updated } }); + }, 1000); + } + // Reactive statement to filter the emojis based on search query $: { if (search) { @@ -55,6 +83,22 @@ // Flatten emoji groups and group them into rows of 8 for virtual scrolling $: { flattenedEmojis = []; + + // Add "Recently Used" group first (only when not searching) + if (!search && recentEmojiNames.length > 0) { + flattenedEmojis.push({ type: 'group', label: $i18n.t('Recently Used') }); + flattenedEmojis.push( + ...recentEmojiNames.map((emoji) => ({ + type: 'emoji', + name: emoji, + shortCodes: + typeof emojiShortCodes[emoji] === 'string' + ? [emojiShortCodes[emoji]] + : emojiShortCodes[emoji] + })) + ); + } + Object.keys(emojiGroups).forEach((group) => { const groupEmojis = emojiGroups[group].filter((emoji) => emojis[emoji]); if (groupEmojis.length > 0) { @@ -97,6 +141,7 @@ // Handle emoji selection function selectEmoji(emoji) { const selectedCode = emoji.shortCodes[0]; + saveRecentEmoji(emoji.name); if (selected === selectedCode) { onSubmit(null); } else { @@ -140,10 +185,10 @@ {:else}
-
+
{#if item.length === 1 && item[0].type === 'group'} -
+
{item[0].label}
{:else} diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index a6697f082d..5cd7f0d632 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -219,6 +219,7 @@ type Settings = { chatDirection?: 'LTR' | 'RTL' | 'auto'; ctrlEnterToSend?: boolean; renderMarkdownInPreviews?: boolean; + recentEmojis?: string[]; system?: string; seed?: number; From edb8971c7dbd974322c3207c4655ff66479c3ee2 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 19:30:38 -0500 Subject: [PATCH 007/404] refac --- .../chat/MessageInput/InputMenu.svelte | 52 ++++++++ .../chat/MessageInput/InputMenu/Files.svelte | 120 ++++++++++++++++++ .../components/chat/Messages/CodeBlock.svelte | 10 +- 3 files changed, 177 insertions(+), 5 deletions(-) create mode 100644 src/lib/components/chat/MessageInput/InputMenu/Files.svelte diff --git a/src/lib/components/chat/MessageInput/InputMenu.svelte b/src/lib/components/chat/MessageInput/InputMenu.svelte index 1b4f980256..e32435d3ae 100644 --- a/src/lib/components/chat/MessageInput/InputMenu.svelte +++ b/src/lib/components/chat/MessageInput/InputMenu.svelte @@ -22,6 +22,7 @@ import ChevronLeft from '$lib/components/icons/ChevronLeft.svelte'; import PageEdit from '$lib/components/icons/PageEdit.svelte'; import Chats from './InputMenu/Chats.svelte'; + import Files from './InputMenu/Files.svelte'; import Notes from './InputMenu/Notes.svelte'; import Knowledge from './InputMenu/Knowledge.svelte'; import AttachWebpageModal from './AttachWebpageModal.svelte'; @@ -204,6 +205,38 @@ + + + + {#if $config?.features?.enable_notes ?? false}
+ {:else if tab === 'files'} +
+ + + +
{:else if tab === 'chats'}
+ {/each} + + {#if !allItemsLoaded} + { + if (!itemsLoading) { + loadMoreItems(); + } + }} + > +
+ +
{$i18n.t('Loading...')}
+
+
+ {/if} +
+ {/if} +{:else} +
+ +
+{/if} diff --git a/src/lib/components/chat/Messages/CodeBlock.svelte b/src/lib/components/chat/Messages/CodeBlock.svelte index 1be70cdeb5..308b15aa9c 100644 --- a/src/lib/components/chat/Messages/CodeBlock.svelte +++ b/src/lib/components/chat/Messages/CodeBlock.svelte @@ -469,7 +469,7 @@ {/if} {:else}
@@ -599,17 +599,17 @@ {#if executing || stdout || stderr || result || files}
{#if executing}
-
{$i18n.t('STDOUT/STDERR')}
+
{$i18n.t('STDOUT/STDERR')}
{$i18n.t('Running...')}
{:else} {#if stdout || stderr}
-
{$i18n.t('STDOUT/STDERR')}
+
{$i18n.t('STDOUT/STDERR')}
-
{$i18n.t('RESULT')}
+
{$i18n.t('RESULT')}
{#if result}
{`${JSON.stringify(result)}`}
{/if} From 1b1d85fe2e3a5505e371848105bf70c140d77f5e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 19:42:10 -0500 Subject: [PATCH 008/404] refac --- backend/open_webui/tools/builtin.py | 48 +++++++++++++++++------------ backend/open_webui/utils/tools.py | 4 +-- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index d9c93eb93c..2c79be9074 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -393,7 +393,8 @@ async def execute_code( if CODE_INTERPRETER_BLOCKED_MODULES: import textwrap - blocking_code = textwrap.dedent(f""" + blocking_code = textwrap.dedent( + f""" import builtins BLOCKED_MODULES = {CODE_INTERPRETER_BLOCKED_MODULES} @@ -409,7 +410,8 @@ async def execute_code( return _real_import(name, globals, locals, fromlist, level) builtins.__import__ = restricted_import - """) + """ + ) code = blocking_code + '\n' + code engine = getattr(__request__.app.state.config, 'CODE_INTERPRETER_ENGINE', 'pyodide') @@ -2342,7 +2344,7 @@ class TaskItem(BaseModel): status: Literal['pending', 'in_progress', 'completed', 'cancelled'] = Field('pending', description="Task status.") -async def update_tasks( +async def tasks( tasks: list[TaskItem], overwrite: bool = True, __chat_id__: str = None, @@ -2352,14 +2354,21 @@ async def update_tasks( __user__: dict = None, ) -> str: """ - Create or update tasks for the current chat. By default replaces the - entire task list. Set overwrite=false to update individual tasks by id - while preserving the rest. + Create or update a checklist of tasks tied to this chat. + Useful whenever a request involves multiple pieces of work that + should be tracked individually. - Only ONE task should be in_progress at a time. Mark tasks completed - immediately when done. + By default the entire list is replaced (overwrite=true). Set + overwrite=false to patch specific items by id without discarding + the rest. - :param tasks: List of task items. Each must have: id (string, unique identifier), content (string, task description — required for new tasks), status (one of: pending, in_progress, completed, cancelled). + Each item carries an id, content string, and a status field + (pending, in_progress, completed, or cancelled). Order reflects + priority. Only one item should be in_progress at a time; mark + it completed before moving on, or cancel and replace it if the + approach changes. + + :param tasks: List of task items. Each must have: id (string, unique identifier), content (string, task description, required for new tasks), status (one of: pending, in_progress, completed, cancelled). :param overwrite: If true (default), replaces the entire task list. If false, updates/adds tasks by id while keeping existing ones. :return: JSON with the full task list and summary counts """ @@ -2367,6 +2376,7 @@ async def update_tasks( return json.dumps({'error': 'Chat context not available'}) try: + def _to_dict(task) -> dict: """Convert TaskItem or dict to plain dict.""" if hasattr(task, 'model_dump'): @@ -2391,7 +2401,7 @@ async def update_tasks( return item_id if item_id else str(idx + 1) if overwrite: - # Full replacement — validate and write + # Full replacement - validate and write all_tasks = [] for idx, task in enumerate(tasks): d = _to_dict(task) @@ -2404,13 +2414,15 @@ async def update_tasks( if status not in VALID_TASK_STATUSES: status = 'pending' - all_tasks.append({ - 'id': item_id, - 'content': content, - 'status': status, - }) + all_tasks.append( + { + 'id': item_id, + 'content': content, + 'status': status, + } + ) else: - # Partial update — merge by id + # Partial update - merge by id existing_tasks = Chats.get_chat_tasks_by_id(__chat_id__) existing_by_id = {t['id']: t for t in existing_tasks} @@ -2486,7 +2498,5 @@ async def update_tasks( ensure_ascii=False, ) except Exception as e: - log.exception(f'update_tasks error: {e}') + log.exception(f'tasks error: {e}') return json.dumps({'error': str(e)}) - - diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 391c45dcbf..e266e9d9c8 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -85,7 +85,7 @@ from open_webui.tools.builtin import ( view_file, view_knowledge_file, view_skill, - update_tasks, + tasks, ) import copy @@ -506,7 +506,7 @@ def get_builtin_tools( # Task management - break down complex work into trackable steps if is_builtin_tool_enabled('tasks'): - builtin_functions.append(update_tasks) + builtin_functions.append(tasks) for func in builtin_functions: callable = get_async_tool_function_and_apply_extra_params( From 4777f4fa3256a04d837338797327653273ffa94a Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 19:48:23 -0500 Subject: [PATCH 009/404] refac --- backend/open_webui/tools/builtin.py | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 2c79be9074..252d1c6c48 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2345,7 +2345,7 @@ class TaskItem(BaseModel): async def tasks( - tasks: list[TaskItem], + tasks: Optional[list[TaskItem]] = None, overwrite: bool = True, __chat_id__: str = None, __message_id__: str = None, @@ -2356,7 +2356,8 @@ async def tasks( """ Create or update a checklist of tasks tied to this chat. Useful whenever a request involves multiple pieces of work that - should be tracked individually. + should be tracked individually. Call without arguments to retrieve + the existing list. By default the entire list is replaced (overwrite=true). Set overwrite=false to patch specific items by id without discarding @@ -2368,7 +2369,7 @@ async def tasks( it completed before moving on, or cancel and replace it if the approach changes. - :param tasks: List of task items. Each must have: id (string, unique identifier), content (string, task description, required for new tasks), status (one of: pending, in_progress, completed, cancelled). + :param tasks: Optional list of task items. Each item: id (string), content (string, required for new tasks), status (pending|in_progress|completed|cancelled). Leave empty to fetch without modifying. :param overwrite: If true (default), replaces the entire task list. If false, updates/adds tasks by id while keeping existing ones. :return: JSON with the full task list and summary counts """ @@ -2400,7 +2401,10 @@ async def tasks( item_id = str(d.get('id', '') or '').strip() return item_id if item_id else str(idx + 1) - if overwrite: + if tasks is None: + # Read-only - return current list + all_tasks = Chats.get_chat_tasks_by_id(__chat_id__) + elif overwrite: # Full replacement - validate and write all_tasks = [] for idx, task in enumerate(tasks): @@ -2464,19 +2468,19 @@ async def tasks( if not any(t['id'] == item_id for t in existing_tasks): all_tasks.append(existing_by_id[item_id]) - # Persist to DB - Chats.update_chat_tasks_by_id(__chat_id__, all_tasks) + # Persist to DB and emit (skip for read-only) + if tasks is not None: + Chats.update_chat_tasks_by_id(__chat_id__, all_tasks) - # Emit to frontend for real-time UI update - if __event_emitter__: - await __event_emitter__( - { - 'type': 'chat:message:tasks', - 'data': { - 'tasks': all_tasks, - }, - } - ) + if __event_emitter__: + await __event_emitter__( + { + 'type': 'chat:message:tasks', + 'data': { + 'tasks': all_tasks, + }, + } + ) # Build summary counts pending = sum(1 for t in all_tasks if t['status'] == 'pending') From a06685a47b89fb19dd6124fbe391ff78b54f451d Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 21:01:10 -0500 Subject: [PATCH 010/404] refac --- backend/open_webui/routers/terminals.py | 4 ++ backend/open_webui/utils/tools.py | 7 +++ src/lib/apis/index.ts | 4 +- src/lib/apis/terminal/index.ts | 21 ++++--- src/lib/components/chat/ChatControls.svelte | 4 +- src/lib/components/chat/FileNav.svelte | 66 +++++++++++++++------ src/lib/components/chat/XTerminal.svelte | 9 ++- src/routes/+layout.svelte | 7 ++- 8 files changed, 86 insertions(+), 36 deletions(-) diff --git a/backend/open_webui/routers/terminals.py b/backend/open_webui/routers/terminals.py index 59f1f3ab48..34d5eb96d6 100644 --- a/backend/open_webui/routers/terminals.py +++ b/backend/open_webui/routers/terminals.py @@ -105,6 +105,10 @@ async def proxy_terminal( target_url += f'?{request.query_params}' headers = {'X-User-Id': user.id} + # Forward per-session cwd tracking header + session_id = request.headers.get('x-session-id') + if session_id: + headers['X-Session-Id'] = session_id cookies = {} auth_type = connection.get('auth_type', 'bearer') diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index e266e9d9c8..377a81d749 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -1009,6 +1009,13 @@ async def get_terminal_tools( # auth_type == "none": no Authorization header system_prompt = server_data.get('system_prompt') + + # Use chat_id as the per-session key for cwd tracking + metadata = extra_params.get('__metadata__', {}) + session_id = metadata.get('chat_id') + if session_id: + headers['X-Session-Id'] = session_id + terminal_cwd = await get_terminal_cwd(connection.get('url', ''), headers, cookies) tools_dict = {} diff --git a/src/lib/apis/index.ts b/src/lib/apis/index.ts index b07d524cba..c46c86b801 100644 --- a/src/lib/apis/index.ts +++ b/src/lib/apis/index.ts @@ -454,7 +454,8 @@ export const executeToolServer = async ( url: string, name: string, params: Record, - serverData: { openapi: any; info: any; specs: any } + serverData: { openapi: any; info: any; specs: any }, + sessionId?: string ) => { let error = null; @@ -531,6 +532,7 @@ export const executeToolServer = async ( 'Content-Type': 'application/json', ...(token && { authorization: `Bearer ${token}` }) }; + if (sessionId) headers['X-Session-Id'] = sessionId; const requestOptions: RequestInit = { method: httpMethod.toUpperCase(), diff --git a/src/lib/apis/terminal/index.ts b/src/lib/apis/terminal/index.ts index 23567baf8e..a01ffa5125 100644 --- a/src/lib/apis/terminal/index.ts +++ b/src/lib/apis/terminal/index.ts @@ -45,11 +45,11 @@ export const getTerminalConfig = async ( return res.json().catch(() => null); }; -export const getCwd = async (baseUrl: string, apiKey: string): Promise => { +export const getCwd = async (baseUrl: string, apiKey: string, sessionId?: string): Promise => { const url = `${baseUrl.replace(/\/$/, '')}/files/cwd`; - const res = await fetch(url, { - headers: { Authorization: `Bearer ${apiKey}` } - }).catch(() => null); + const headers: Record = { Authorization: `Bearer ${apiKey}` }; + if (sessionId) headers['X-Session-Id'] = sessionId; + const res = await fetch(url, { headers }).catch(() => null); if (!res || !res.ok) return null; const json = await res.json().catch(() => null); return json?.cwd ?? null; @@ -218,15 +218,18 @@ export const deleteEntry = async ( export const setCwd = async ( baseUrl: string, apiKey: string, - path: string + path: string, + sessionId?: string ): Promise<{ cwd: string } | null> => { const url = `${baseUrl.replace(/\/$/, '')}/files/cwd`; + const headers: Record = { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json' + }; + if (sessionId) headers['X-Session-Id'] = sessionId; const res = await fetch(url, { method: 'POST', - headers: { - Authorization: `Bearer ${apiKey}`, - 'Content-Type': 'application/json' - }, + headers, body: JSON.stringify({ path }) }) .then(async (res) => { diff --git a/src/lib/components/chat/ChatControls.svelte b/src/lib/components/chat/ChatControls.svelte index f27a307fea..3cbcc7ed87 100644 --- a/src/lib/components/chat/ChatControls.svelte +++ b/src/lib/components/chat/ChatControls.svelte @@ -362,7 +362,7 @@ onClose={() => showControls.set(false)} /> {:else if activeTab === 'files' && $selectedTerminalId} - + {:else if activeTab === 'files' && codeInterpreterEnabled} {:else} @@ -513,7 +513,7 @@ onClose={() => showControls.set(false)} /> {:else if activeTab === 'files' && $selectedTerminalId} - + {:else if activeTab === 'files' && codeInterpreterEnabled} {:else} diff --git a/src/lib/components/chat/FileNav.svelte b/src/lib/components/chat/FileNav.svelte index 99549aec6b..ef2db742aa 100644 --- a/src/lib/components/chat/FileNav.svelte +++ b/src/lib/components/chat/FileNav.svelte @@ -49,6 +49,7 @@ export let onAttach: ((blob: Blob, name: string, contentType: string) => void) | null = null; export let overlay = false; + export let chatId: string | null = null; // ── Terminal panel state ──────────────────────────────────────────── let terminalExpanded = false; @@ -215,30 +216,48 @@ return url ? { url, key } : null; }; - // Detect terminal changes — the explicit store references ensure + // Detect terminal or chat changes — the explicit store references ensure // Svelte re-runs this block when any of them update. + // The `mounted` flag prevents the initial run from racing with onMount. let prevTerminalUrl = ''; + let prevChatId = chatId; + let mounted = false; $: { ($selectedTerminalId, $terminalServers, $settings); const terminal = getTerminal(); selectedTerminal = terminal; - if (terminal && terminal.url !== prevTerminalUrl) { - prevTerminalUrl = terminal.url; - loading = true; - error = null; - entries = []; - (async () => { - // Discover server features (terminal enabled/disabled) - const config = await getTerminalConfig(terminal.url, terminal.key); - terminalEnabled = config?.features?.terminal !== false; + const chatChanged = chatId !== prevChatId; + const oldChatId = prevChatId; + if (chatChanged) prevChatId = chatId; - const rawCwd = await getCwd(terminal.url, terminal.key); - const cwd = rawCwd ? normalizePath(rawCwd) : null; - const dir = cwd ? (cwd.endsWith('/') ? cwd : cwd + '/') : '/'; - savedPath = dir; - loadDir(dir); - })(); + const terminalChanged = terminal && terminal.url !== prevTerminalUrl; + if (terminalChanged) prevTerminalUrl = terminal.url; + + if (mounted && terminal) { + if (chatChanged && chatId && !oldChatId) { + // Chat just got created (null → real ID): persist the current + // browsed path as the new session's cwd — don't re-fetch. + setCwd(terminal.url, terminal.key, savedPath, chatId); + } else if (terminalChanged || chatChanged) { + // Terminal switched, new chat started, or switched between + // existing chats — re-fetch the session cwd. + loading = true; + error = null; + entries = []; + (async () => { + if (terminalChanged) { + const config = await getTerminalConfig(terminal.url, terminal.key); + terminalEnabled = config?.features?.terminal !== false; + } + + const rawCwd = await getCwd(terminal.url, terminal.key, chatId ?? undefined); + const cwd = rawCwd ? normalizePath(rawCwd) : null; + const dir = cwd ? (cwd.endsWith('/') ? cwd : cwd + '/') : '/'; + savedPath = dir; + loadDir(dir); + })(); + } } } @@ -316,7 +335,7 @@ loading = false; // Set working directory on the terminal server (fire-and-forget) - setCwd(terminal.url, terminal.key, path); + setCwd(terminal.url, terminal.key, path, chatId ?? undefined); if (result === null) { error = @@ -736,14 +755,22 @@ if (!handledDisplayFile) { loading = true; - if (savedPath === '/') { - const rawCwd = await getCwd(terminal.url, terminal.key); + + // Discover server features on initial mount + const config = await getTerminalConfig(terminal.url, terminal.key); + terminalEnabled = config?.features?.terminal !== false; + + if (chatId || savedPath === '/') { + // Fetch session-specific cwd from the server (or global default for new chats) + const rawCwd = await getCwd(terminal.url, terminal.key, chatId ?? undefined); const cwd = rawCwd ? normalizePath(rawCwd) : null; if (cwd) savedPath = cwd.endsWith('/') ? cwd : cwd + '/'; } loadDir(savedPath); } + mounted = true; + const onKeyDown = (e: KeyboardEvent) => { if (e.key === 'Shift') shiftKey = true; }; @@ -1368,6 +1395,7 @@ overlay={overlay || isDraggingHandle} bind:connected={terminalConnected} bind:connecting={terminalConnecting} + {chatId} />
{/if} diff --git a/src/lib/components/chat/XTerminal.svelte b/src/lib/components/chat/XTerminal.svelte index eb74a7e1a5..e16beef978 100644 --- a/src/lib/components/chat/XTerminal.svelte +++ b/src/lib/components/chat/XTerminal.svelte @@ -12,6 +12,7 @@ const i18n = getContext('i18n'); export let overlay = false; + export let chatId: string | null = null; let terminalEl: HTMLDivElement; let term: Terminal | null = null; @@ -67,9 +68,11 @@ authToken = apiKey; // Create session + const createHeaders: Record = { Authorization: `Bearer ${apiKey}` }; + if (chatId) createHeaders['X-Session-Id'] = chatId; const res = await fetch(`${base}/api/terminals`, { method: 'POST', - headers: { Authorization: `Bearer ${apiKey}` } + headers: createHeaders }); if (!res.ok) throw new Error(`Failed to create session: ${res.status}`); const session = await res.json(); @@ -83,9 +86,11 @@ authToken = token; // Create session via proxy + const proxyHeaders: Record = { Authorization: `Bearer ${token}` }; + if (chatId) proxyHeaders['X-Session-Id'] = chatId; const res = await fetch(`${base}/terminals/${info.serverId}/api/terminals`, { method: 'POST', - headers: { Authorization: `Bearer ${token}` } + headers: proxyHeaders }); if (!res.ok) throw new Error(`Failed to create session: ${res.status}`); const session = await res.json(); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 920e56f96b..b40c9c558b 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -375,7 +375,7 @@ return { toolServer, toolServerData, token }; }; - const executeTool = async (data, cb) => { + const executeTool = async (data, cb, chatId) => { const { toolServer, toolServerData, token } = resolveToolServer(data.server?.url); console.log('executeTool', data, toolServer); @@ -386,7 +386,8 @@ toolServer.url, data?.name, data?.params, - toolServerData + toolServerData, + chatId ); console.log('executeToolServer', res); @@ -485,7 +486,7 @@ executePythonAsWorker(data.id, data.code, cb, data.files || []); } else if (type === 'execute:tool') { console.log('execute:tool', data); - executeTool(data, cb); + executeTool(data, cb, event.chat_id); } else if (type === 'request:chat:completion') { console.log(data, $socket.id); const { session_id, channel, form_data, model } = data; From b794d6162650fec17c3923671e5c2cfb0033cb3a Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 21:15:20 -0500 Subject: [PATCH 011/404] refac --- backend/open_webui/tools/builtin.py | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 252d1c6c48..261dba0c69 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2354,20 +2354,12 @@ async def tasks( __user__: dict = None, ) -> str: """ - Create or update a checklist of tasks tied to this chat. - Useful whenever a request involves multiple pieces of work that - should be tracked individually. Call without arguments to retrieve - the existing list. - - By default the entire list is replaced (overwrite=true). Set - overwrite=false to patch specific items by id without discarding - the rest. - - Each item carries an id, content string, and a status field - (pending, in_progress, completed, or cancelled). Order reflects - priority. Only one item should be in_progress at a time; mark - it completed before moving on, or cancel and replace it if the - approach changes. + Track progress on multi-step work by maintaining a task checklist. + Use this whenever a request involves multiple steps or could take + significant effort. Call to set the full list, then call again + with overwrite=false after completing each task to mark it + completed. Each task has an id, content, and status (pending, + in_progress, completed, cancelled). :param tasks: Optional list of task items. Each item: id (string), content (string, required for new tasks), status (pending|in_progress|completed|cancelled). Leave empty to fetch without modifying. :param overwrite: If true (default), replaces the entire task list. If false, updates/adds tasks by id while keeping existing ones. From b1e8c7d2aafd41e2fcde5dc4ce3d0c454535daff Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 21:25:39 -0500 Subject: [PATCH 012/404] refac --- backend/open_webui/tools/builtin.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 261dba0c69..088319f2e6 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2358,8 +2358,9 @@ async def tasks( Use this whenever a request involves multiple steps or could take significant effort. Call to set the full list, then call again with overwrite=false after completing each task to mark it - completed. Each task has an id, content, and status (pending, - in_progress, completed, cancelled). + completed. Do not leave tasks in_progress when the work is done. + Each task has an id, content, and status (pending, in_progress, + completed, cancelled). :param tasks: Optional list of task items. Each item: id (string), content (string, required for new tasks), status (pending|in_progress|completed|cancelled). Leave empty to fetch without modifying. :param overwrite: If true (default), replaces the entire task list. If false, updates/adds tasks by id while keeping existing ones. From 0ad397c0482004173d4a8bf4722100acc43db454 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 21:29:00 -0500 Subject: [PATCH 013/404] refac --- src/lib/components/chat/MessageInput.svelte | 2 +- .../chat/Messages/ResponseMessage/TaskList.svelte | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index e826f1c68f..853bd9824f 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1242,7 +1242,7 @@ {#if chatTasks.length > 0}
- +
{/if} diff --git a/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte b/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte index 79a9f42d5d..a295380eb3 100644 --- a/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage/TaskList.svelte @@ -8,12 +8,21 @@ const i18n = getContext('i18n'); export let tasks: Array<{ id: string; content: string; status: string }> = []; + export let done = false; let collapsed = false; $: completedCount = tasks.filter((t) => t.status === 'completed').length; $: totalCount = tasks.length; - $: hasActive = tasks.some((t) => t.status === 'pending' || t.status === 'in_progress'); + $: inProgressCount = tasks.filter((t) => t.status === 'in_progress').length; + $: pendingCount = tasks.filter((t) => t.status === 'pending').length; + + // Hide once all work is effectively done: + // - no active tasks at all, OR + // - message is done and the only remaining active tasks are in_progress (no pending) + $: hasActive = + tasks.some((t) => t.status === 'pending' || t.status === 'in_progress') && + !(done && pendingCount === 0 && inProgressCount > 0); {#if tasks.length > 0 && hasActive} From 6512e085c4e56897dd49e56aff5d616820a962f3 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 21:50:54 -0500 Subject: [PATCH 014/404] refac --- src/lib/apis/terminal/index.ts | 80 ++++++++++++++++---------- src/lib/components/chat/FileNav.svelte | 30 +++++----- 2 files changed, 64 insertions(+), 46 deletions(-) diff --git a/src/lib/apis/terminal/index.ts b/src/lib/apis/terminal/index.ts index a01ffa5125..de2e2fd5a6 100644 --- a/src/lib/apis/terminal/index.ts +++ b/src/lib/apis/terminal/index.ts @@ -58,13 +58,14 @@ export const getCwd = async (baseUrl: string, apiKey: string, sessionId?: string export const listFiles = async ( baseUrl: string, apiKey: string, - path: string = '/' + path: string = '/', + sessionId?: string ): Promise => { // The endpoint uses `directory` as the query param name const url = `${baseUrl.replace(/\/$/, '')}/files/list?directory=${encodeURIComponent(path)}`; - const res = await fetch(url, { - headers: { Authorization: `Bearer ${apiKey}` } - }) + const headers: Record = { Authorization: `Bearer ${apiKey}` }; + if (sessionId) headers['X-Session-Id'] = sessionId; + const res = await fetch(url, { headers }) .then(async (res) => { if (!res.ok) throw await res.json(); return res.json(); @@ -79,12 +80,13 @@ export const listFiles = async ( export const readFile = async ( baseUrl: string, apiKey: string, - path: string + path: string, + sessionId?: string ): Promise => { const url = `${baseUrl.replace(/\/$/, '')}/files/read?path=${encodeURIComponent(path)}`; - const res = await fetch(url, { - headers: { Authorization: `Bearer ${apiKey}` } - }).catch((err) => { + const headers: Record = { Authorization: `Bearer ${apiKey}` }; + if (sessionId) headers['X-Session-Id'] = sessionId; + const res = await fetch(url, { headers }).catch((err) => { console.error('open-terminal readFile error:', err); return null; }); @@ -106,12 +108,13 @@ export const readFile = async ( export const downloadFileBlob = async ( baseUrl: string, apiKey: string, - path: string + path: string, + sessionId?: string ): Promise<{ blob: Blob; filename: string } | null> => { const url = `${baseUrl.replace(/\/$/, '')}/files/view?path=${encodeURIComponent(path)}`; - const res = await fetch(url, { - headers: { Authorization: `Bearer ${apiKey}` } - }).catch(() => null); + const headers: Record = { Authorization: `Bearer ${apiKey}` }; + if (sessionId) headers['X-Session-Id'] = sessionId; + const res = await fetch(url, { headers }).catch(() => null); if (!res || !res.ok) return null; @@ -123,15 +126,18 @@ export const downloadFileBlob = async ( export const archiveFromTerminal = async ( baseUrl: string, apiKey: string, - paths: string[] + paths: string[], + sessionId?: string ): Promise<{ blob: Blob; filename: string } | null> => { const url = `${baseUrl.replace(/\/$/, '')}/files/archive`; + const headers: Record = { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json' + }; + if (sessionId) headers['X-Session-Id'] = sessionId; const res = await fetch(url, { method: 'POST', - headers: { - Authorization: `Bearer ${apiKey}`, - 'Content-Type': 'application/json' - }, + headers, body: JSON.stringify({ paths }) }).catch(() => null); @@ -148,14 +154,17 @@ export const uploadToTerminal = async ( baseUrl: string, apiKey: string, directory: string, - file: File + file: File, + sessionId?: string ): Promise<{ path: string; size: number } | null> => { const url = `${baseUrl.replace(/\/$/, '')}/files/upload?directory=${encodeURIComponent(directory)}`; const body = new FormData(); body.append('file', file); + const headers: Record = { Authorization: `Bearer ${apiKey}` }; + if (sessionId) headers['X-Session-Id'] = sessionId; const res = await fetch(url, { method: 'POST', - headers: { Authorization: `Bearer ${apiKey}` }, + headers, body }) .then(async (res) => { @@ -172,15 +181,18 @@ export const uploadToTerminal = async ( export const createDirectory = async ( baseUrl: string, apiKey: string, - path: string + path: string, + sessionId?: string ): Promise<{ path: string } | null> => { const url = `${baseUrl.replace(/\/$/, '')}/files/mkdir`; + const headers: Record = { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json' + }; + if (sessionId) headers['X-Session-Id'] = sessionId; const res = await fetch(url, { method: 'POST', - headers: { - Authorization: `Bearer ${apiKey}`, - 'Content-Type': 'application/json' - }, + headers, body: JSON.stringify({ path }) }) .then(async (res) => { @@ -197,12 +209,15 @@ export const createDirectory = async ( export const deleteEntry = async ( baseUrl: string, apiKey: string, - path: string + path: string, + sessionId?: string ): Promise<{ path: string; type: string } | null> => { const url = `${baseUrl.replace(/\/$/, '')}/files/delete?path=${encodeURIComponent(path)}`; + const headers: Record = { Authorization: `Bearer ${apiKey}` }; + if (sessionId) headers['X-Session-Id'] = sessionId; const res = await fetch(url, { method: 'DELETE', - headers: { Authorization: `Bearer ${apiKey}` } + headers }) .then(async (res) => { if (!res.ok) throw await res.json(); @@ -247,15 +262,18 @@ export const moveEntry = async ( baseUrl: string, apiKey: string, source: string, - destination: string + destination: string, + sessionId?: string ): Promise<{ source: string; destination: string } | { error: string }> => { const url = `${baseUrl.replace(/\/$/, '')}/files/move`; + const headers: Record = { + Authorization: `Bearer ${apiKey}`, + 'Content-Type': 'application/json' + }; + if (sessionId) headers['X-Session-Id'] = sessionId; const res = await fetch(url, { method: 'POST', - headers: { - Authorization: `Bearer ${apiKey}`, - 'Content-Type': 'application/json' - }, + headers, body: JSON.stringify({ source, destination }) }) .then(async (res) => { diff --git a/src/lib/components/chat/FileNav.svelte b/src/lib/components/chat/FileNav.svelte index ef2db742aa..988c92669c 100644 --- a/src/lib/components/chat/FileNav.svelte +++ b/src/lib/components/chat/FileNav.svelte @@ -331,7 +331,7 @@ savedPath = path; pushNavHistory(path); - const result = await listFiles(terminal.url, terminal.key, path); + const result = await listFiles(terminal.url, terminal.key, path, chatId ?? undefined); loading = false; // Set working directory on the terminal server (fire-and-forget) @@ -366,22 +366,22 @@ clearFilePreview(); if (isImage(filePath)) { - const result = await downloadFileBlob(terminal.url, terminal.key, filePath); + const result = await downloadFileBlob(terminal.url, terminal.key, filePath, chatId ?? undefined); if (result) fileImageUrl = URL.createObjectURL(result.blob); } else if (isVideo(filePath)) { - const result = await downloadFileBlob(terminal.url, terminal.key, filePath); + const result = await downloadFileBlob(terminal.url, terminal.key, filePath, chatId ?? undefined); if (result) fileVideoUrl = URL.createObjectURL(result.blob); } else if (isAudio(filePath)) { - const result = await downloadFileBlob(terminal.url, terminal.key, filePath); + const result = await downloadFileBlob(terminal.url, terminal.key, filePath, chatId ?? undefined); if (result) fileAudioUrl = URL.createObjectURL(result.blob); } else if (isPdf(filePath)) { - const result = await downloadFileBlob(terminal.url, terminal.key, filePath); + const result = await downloadFileBlob(terminal.url, terminal.key, filePath, chatId ?? undefined); if (result) filePdfData = await result.blob.arrayBuffer(); } else if (isSqlite(filePath)) { - const result = await downloadFileBlob(terminal.url, terminal.key, filePath); + const result = await downloadFileBlob(terminal.url, terminal.key, filePath, chatId ?? undefined); if (result) fileSqliteData = await result.blob.arrayBuffer(); } else if (isOffice(filePath)) { - const result = await downloadFileBlob(terminal.url, terminal.key, filePath); + const result = await downloadFileBlob(terminal.url, terminal.key, filePath, chatId ?? undefined); if (result) { const ext = getFileExt(filePath); const arrayBuffer = await result.blob.arrayBuffer(); @@ -414,7 +414,7 @@ } } } else { - fileContent = await readFile(terminal.url, terminal.key, filePath); + fileContent = await readFile(terminal.url, terminal.key, filePath, chatId ?? undefined); } fileLoading = false; }; @@ -427,7 +427,7 @@ const isDir = path.endsWith('/'); const result = isDir ? await archiveFromTerminal(terminal.url, terminal.key, [path.replace(/\/$/, '')]) - : await downloadFileBlob(terminal.url, terminal.key, path); + : await downloadFileBlob(terminal.url, terminal.key, path, chatId ?? undefined); if (!result) return; const url = URL.createObjectURL(result.blob); const a = document.createElement('a'); @@ -459,7 +459,7 @@ uploading = true; for (const file of droppedFiles) { - await uploadToTerminal(terminal.url, terminal.key, currentPath, file); + await uploadToTerminal(terminal.url, terminal.key, currentPath, file, chatId ?? undefined); } uploading = false; await loadDir(currentPath); @@ -471,7 +471,7 @@ uploading = true; for (const file of files) { - await uploadToTerminal(terminal.url, terminal.key, currentPath, file); + await uploadToTerminal(terminal.url, terminal.key, currentPath, file, chatId ?? undefined); } uploading = false; await loadDir(currentPath); @@ -494,7 +494,7 @@ const terminal = selectedTerminal; if (!terminal) return; - const result = await createDirectory(terminal.url, terminal.key, `${currentPath}${name}`); + const result = await createDirectory(terminal.url, terminal.key, `${currentPath}${name}`, chatId ?? undefined); toast[result ? 'success' : 'error']( $i18n.t(result ? 'Folder created' : 'Failed to create folder') ); @@ -529,7 +529,7 @@ const terminal = selectedTerminal; if (!terminal) return; - const result = await deleteEntry(terminal.url, terminal.key, path); + const result = await deleteEntry(terminal.url, terminal.key, path, chatId ?? undefined); toast[result ? 'success' : 'error']( $i18n.t(result ? '{{name}} deleted' : 'Failed to delete {{name}}', { name }) ); @@ -555,7 +555,7 @@ const sourceDir = source.endsWith('/') ? source : source + '/'; if (destFolder.startsWith(sourceDir)) return; - const result = await moveEntry(terminal.url, terminal.key, source, destination); + const result = await moveEntry(terminal.url, terminal.key, source, destination, chatId ?? undefined); if ('error' in result) { toast.error(result.error); } else { @@ -574,7 +574,7 @@ if (oldPath === destination) return; - const result = await moveEntry(terminal.url, terminal.key, oldPath, destination); + const result = await moveEntry(terminal.url, terminal.key, oldPath, destination, chatId ?? undefined); if ('error' in result) { toast.error(result.error); } else { From 4b35d70078a2d7a322566699a43594b3c10b2dda Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 29 Mar 2026 21:59:51 -0500 Subject: [PATCH 015/404] refac --- src/lib/components/chat/MessageInput.svelte | 8 +++++--- .../chat/Messages/ResponseMessage/TaskList.svelte | 11 +---------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 853bd9824f..f853b59a1c 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -122,6 +122,8 @@ export let history; export let taskIds = null; + $: isActive = (taskIds && taskIds.length > 0) || (history.currentId && history.messages[history.currentId]?.done != true) || generating; + export let prompt = ''; export let files = []; @@ -1240,9 +1242,9 @@ /> - {#if chatTasks.length > 0} + {#if isActive && chatTasks.length > 0}
- +
{/if} @@ -1857,7 +1859,7 @@
- {#if (taskIds && taskIds.length > 0) || (history.currentId && history.messages[history.currentId]?.done != true) || generating} + {#if isActive}
-
+ {item?.name -
+
{:else if selectedTab === ''} {#if item?.file?.data} diff --git a/src/lib/components/common/ImagePreview.svelte b/src/lib/components/common/ImagePreview.svelte index 17d9a93a1e..9cb36dc160 100644 --- a/src/lib/components/common/ImagePreview.svelte +++ b/src/lib/components/common/ImagePreview.svelte @@ -1,10 +1,10 @@ @@ -181,14 +160,13 @@
-
+ -
+
{/if} diff --git a/src/lib/components/common/PanzoomContainer.svelte b/src/lib/components/common/PanzoomContainer.svelte new file mode 100644 index 0000000000..50aec0709d --- /dev/null +++ b/src/lib/components/common/PanzoomContainer.svelte @@ -0,0 +1,33 @@ + + +
+ +
diff --git a/src/lib/components/common/SVGPanZoom.svelte b/src/lib/components/common/SVGPanZoom.svelte index aaeb26dac9..307ddda21e 100644 --- a/src/lib/components/common/SVGPanZoom.svelte +++ b/src/lib/components/common/SVGPanZoom.svelte @@ -4,15 +4,14 @@ import { toast } from 'svelte-sonner'; - import panzoom, { type PanZoom } from 'panzoom'; import DOMPurify from 'dompurify'; - import { onMount, getContext } from 'svelte'; + import { getContext } from 'svelte'; const i18n = getContext('i18n'); import { copyToClipboard } from '$lib/utils'; - import DocumentDuplicate from '../icons/DocumentDuplicate.svelte'; + import PanzoomContainer from './PanzoomContainer.svelte'; import Tooltip from './Tooltip.svelte'; import Clipboard from '../icons/Clipboard.svelte'; import Reset from '../icons/Reset.svelte'; @@ -22,23 +21,9 @@ export let svg = ''; export let content = ''; - let instance: PanZoom; - - let sceneParentElement: HTMLElement; - let sceneElement: HTMLElement; - - $: if (sceneElement) { - instance = panzoom(sceneElement, { - bounds: true, - boundsPadding: 0.1, - - zoomSpeed: 0.065 - }); - } + let panzoomRef: PanzoomContainer; const resetPanZoomViewport = () => { - instance.moveTo(0, 0); - instance.zoomAbs(0, 0, 1); - console.log(instance.getTransform()); + panzoomRef?.reset(); }; const downloadAsSVG = () => { @@ -47,8 +32,11 @@ }; -
-
+
+ {@html DOMPurify.sanitize(svg, { USE_PROFILES: { svg: true, svgFilters: true }, // allow , , , etc. WHOLE_DOCUMENT: false, @@ -88,7 +76,7 @@ ], SANITIZE_DOM: true })} -
+ {#if content}
From b10c70cfcf1ece2d6d9959716ec2ed66e21f602a Mon Sep 17 00:00:00 2001 From: Shirasawa <764798966@qq.com> Date: Tue, 31 Mar 2026 17:11:47 +0800 Subject: [PATCH 021/404] feat: Save error messages to the database (#23231) --- backend/open_webui/utils/middleware.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index b64febd673..398d693cd5 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -3632,6 +3632,16 @@ async def streaming_chat_response_handler(response, ctx): if not choices: error = data.get('error', {}) if error: + try: + Chats.upsert_message_to_chat_by_id_and_message_id( + metadata["chat_id"], + metadata["message_id"], + { + "error": {"content": error}, + }, + ) + except Exception: + pass await event_emitter( { 'type': 'chat:completion', From 5fd9db873900f96e9822a5c5e7e368ae368c1749 Mon Sep 17 00:00:00 2001 From: Algorithm5838 <108630393+Algorithm5838@users.noreply.github.com> Date: Wed, 1 Apr 2026 01:19:47 +0300 Subject: [PATCH 022/404] perf: replace JS transition with CSS animation in CodespanToken (#23258) --- .../MarkdownInlineTokens/CodespanToken.svelte | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/CodespanToken.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/CodespanToken.svelte index c0b1ec327c..1de3f13f6e 100644 --- a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/CodespanToken.svelte +++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens/CodespanToken.svelte @@ -1,7 +1,6 @@ + + +
+ +
+ + +
+ + +
+
{$i18n.t('Instructions')}
+ +
+
+ + +
+
+ {#if event && !event.meta?.automation_id} + + {/if} +
+ +
+ + +
+
+
+ diff --git a/src/lib/components/calendar/CalendarSidebar.svelte b/src/lib/components/calendar/CalendarSidebar.svelte new file mode 100644 index 0000000000..09e604a281 --- /dev/null +++ b/src/lib/components/calendar/CalendarSidebar.svelte @@ -0,0 +1,174 @@ + + +
+ +
+
+
{miniMonthNames[miniMonth]} {miniYear}
+
+ + +
+
+ +
+ {#each ['S', 'M', 'T', 'W', 'T', 'F', 'S'] as d} +
{d}
+ {/each} +
+ +
+ {#each miniDays as day} + + {/each} +
+
+ + +
+
+
+ {$i18n.t('Calendars')} +
+
+ + {#each calendars as cal (cal.id)} + + {/each} +
+
diff --git a/src/lib/components/calendar/CalendarView.svelte b/src/lib/components/calendar/CalendarView.svelte new file mode 100644 index 0000000000..0b67d7de98 --- /dev/null +++ b/src/lib/components/calendar/CalendarView.svelte @@ -0,0 +1,380 @@ + + +
+ + + + + {#if view === 'month'} +
+
+ {#each DAY_NAMES as day} +
{$i18n.t(day)}
+ {/each} +
+ +
+ {#each monthDays as day, i} + {@const dayKey = new Date(day.getFullYear(), day.getMonth(), day.getDate()).getTime().toString()} + {@const dayEvents = eventsByDay[dayKey] || []} + {@const col = i % 7} + {@const row = Math.floor(i / 7)} + + {/each} +
+
+ + + {:else if view === 'week'} +
+
+
+
+
+
+ {#each weekDays as day} +
+
{DAY_NAMES[day.getDay()]}
+
+ {day.getDate()} +
+
+ {/each} +
+ +
+ {#each hours as hour} +
+
{hour > 0 ? formatHour(hour) : ''}
+ {#each weekDays as day} + {@const hourEvents = getEventsForHour(day, hour, filteredEvents)} + + {/each} +
+ {/each} +
+
+
+
+
+ + + {:else} +
+
+ {#each hours as hour} + {@const hourEvents = getEventsForHour(currentDate, hour, filteredEvents)} +
+
{hour > 0 ? formatHour(hour) : ''}
+ +
+ {/each} +
+
+ {/if} +
diff --git a/src/lib/components/layout/Sidebar/UserMenu.svelte b/src/lib/components/layout/Sidebar/UserMenu.svelte index 1a1681a844..30c29962b4 100644 --- a/src/lib/components/layout/Sidebar/UserMenu.svelte +++ b/src/lib/components/layout/Sidebar/UserMenu.svelte @@ -250,6 +250,38 @@ {/if} + {#if $user?.role === 'admin' || $user?.permissions?.features?.calendar} + { + if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; + e.preventDefault(); + show = false; + goto('/calendar'); + }} + > +
+ + + +
+
{$i18n.t('Calendar')}
+
+ {/if} + {#if role === 'admin'} + import { onMount, getContext, tick } from 'svelte'; + import { toast } from 'svelte-sonner'; + import { goto } from '$app/navigation'; + import { WEBUI_NAME, mobile, showSidebar, user } from '$lib/stores'; + import { + getCalendars, + getCalendarEvents, + type CalendarModel, + type CalendarEventModel + } from '$lib/apis/calendar'; + import CalendarView from '$lib/components/calendar/CalendarView.svelte'; + import CalendarSidebar from '$lib/components/calendar/CalendarSidebar.svelte'; + import CalendarEventModal from '$lib/components/calendar/CalendarEventModal.svelte'; + import Spinner from '$lib/components/common/Spinner.svelte'; + import Plus from '$lib/components/icons/Plus.svelte'; + + const i18n = getContext('i18n'); + + let loaded = false; + let calendars: CalendarModel[] = []; + let events: CalendarEventModel[] = []; + let visibleCalendarIds: Set = new Set(); + + let view: 'month' | 'week' | 'day' = 'month'; + let currentDate = new Date(); + + let showEventModal = false; + let editEvent: CalendarEventModel | null = null; + let defaultStartAt: number | null = null; + + function getVisibleRange(): { start: string; end: string } { + const d = new Date(currentDate); + let start: Date; + let end: Date; + + if (view === 'month') { + start = new Date(d.getFullYear(), d.getMonth(), 1); + start.setDate(start.getDate() - start.getDay()); + end = new Date(start); + end.setDate(end.getDate() + 42); + } else if (view === 'week') { + start = new Date(d); + start.setDate(start.getDate() - start.getDay()); + start.setHours(0, 0, 0, 0); + end = new Date(start); + end.setDate(end.getDate() + 7); + } else { + start = new Date(d.getFullYear(), d.getMonth(), d.getDate()); + end = new Date(start); + end.setDate(end.getDate() + 1); + } + + return { + start: start.toISOString(), + end: end.toISOString() + }; + } + + async function loadCalendars() { + try { + calendars = (await getCalendars(localStorage.token)) ?? []; + visibleCalendarIds = new Set(calendars.map((c) => c.id)); + } catch (err) { + console.error('loadCalendars', err); + calendars = []; + } + } + + async function loadEvents() { + try { + const { start, end } = getVisibleRange(); + events = await getCalendarEvents(localStorage.token, start, end); + } catch (err) { + toast.error(`${err}`); + } + } + + async function refresh() { + await loadEvents(); + } + + function toggleCalendar(id: string) { + const next = new Set(visibleCalendarIds); + if (next.has(id)) { + next.delete(id); + } else { + next.add(id); + } + visibleCalendarIds = next; + } + + function handleCreateEvent(e: CustomEvent<{ start_at: number }>) { + editEvent = null; + defaultStartAt = e.detail.start_at; + showEventModal = true; + } + + function handleEventClick(e: CustomEvent) { + const evt = e.detail; + if (evt.meta?.automation_id) { + if (evt.meta?.chat_id) { + goto(`/c/${evt.meta.chat_id}`); + } else { + goto(`/automations/${evt.meta.automation_id}`); + } + return; + } + editEvent = evt; + defaultStartAt = null; + showEventModal = true; + } + + async function handleNavigate() { + await tick(); + refresh(); + } + + async function handleDateSelect(date: Date) { + currentDate = date; + await tick(); + refresh(); + } + + function handleNewEvent() { + editEvent = null; + defaultStartAt = null; + showEventModal = true; + } + + $: defaultCalendarId = calendars.find((c) => !c.is_system || c.name === 'Personal')?.id || calendars[0]?.id || ''; + + onMount(async () => { + await loadCalendars(); + await refresh(); + loaded = true; + }); + + + + {$i18n.t('Calendar')} • {$WEBUI_NAME} + + + refresh()} + on:delete={() => refresh()} +/> + +
+ {#if loaded} +
+ + + + +
+ +
+
+ {:else} +
+ +
+ {/if} +
From 4a5401b4174edbef8d102ac2917944ae1d2cdc00 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 19 Apr 2026 21:48:27 +0900 Subject: [PATCH 292/404] refac --- .../56359461a091_add_calendar_tables.py | 2 +- backend/open_webui/models/calendar.py | 40 ++++++++++++++----- backend/open_webui/routers/calendar.py | 10 ++++- src/lib/apis/calendar/index.ts | 33 ++++++++++++++- src/routes/(app)/calendar/+page.svelte | 2 +- 5 files changed, 73 insertions(+), 14 deletions(-) diff --git a/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py index 8277daa738..a0812578c8 100644 --- a/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py +++ b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py @@ -24,7 +24,7 @@ def upgrade() -> None: sa.Column('user_id', sa.Text(), nullable=False), sa.Column('name', sa.Text(), nullable=False), sa.Column('color', sa.Text(), nullable=True), - sa.Column('is_system', sa.Boolean(), nullable=False), + sa.Column('is_default', sa.Boolean(), nullable=False), sa.Column('data', sa.JSON(), nullable=True), sa.Column('meta', sa.JSON(), nullable=True), sa.Column('created_at', sa.BigInteger(), nullable=False), diff --git a/backend/open_webui/models/calendar.py b/backend/open_webui/models/calendar.py index e055c87f90..859632c494 100644 --- a/backend/open_webui/models/calendar.py +++ b/backend/open_webui/models/calendar.py @@ -17,6 +17,7 @@ from sqlalchemy import ( exists, func, delete, + update, ) from sqlalchemy.ext.asyncio import AsyncSession @@ -40,7 +41,7 @@ class Calendar(Base): user_id = Column(Text, nullable=False) name = Column(Text, nullable=False) color = Column(Text, nullable=True) - is_system = Column(Boolean, nullable=False, default=False) + is_default = Column(Boolean, nullable=False, default=False) data = Column(JSON, nullable=True) meta = Column(JSON, nullable=True) @@ -107,7 +108,8 @@ class CalendarModel(BaseModel): user_id: str name: str color: Optional[str] = None - is_system: bool = False + is_default: bool = False + data: Optional[dict] = None meta: Optional[dict] = None @@ -269,7 +271,7 @@ class CalendarTable: user_id=user_id, name='Personal', color='#3b82f6', - is_system=True, + is_default=True, created_at=now, updated_at=now, ), @@ -278,7 +280,6 @@ class CalendarTable: user_id=user_id, name='Scheduled Tasks', color='#8b5cf6', - is_system=True, created_at=now + 1, updated_at=now + 1, ), @@ -338,7 +339,6 @@ class CalendarTable: select(Calendar).filter( Calendar.user_id == user_id, Calendar.name == 'Scheduled Tasks', - Calendar.is_system == True, ) ) cal = result.scalars().first() @@ -349,7 +349,6 @@ class CalendarTable: select(Calendar).filter( Calendar.user_id == user_id, Calendar.name == 'Scheduled Tasks', - Calendar.is_system == True, ) ) cal = result.scalars().first() @@ -366,7 +365,7 @@ class CalendarTable: user_id=user_id, name=form_data.name, color=form_data.color, - is_system=False, + is_default=False, data=form_data.data, meta=form_data.meta, created_at=now, @@ -403,13 +402,36 @@ class CalendarTable: await db.commit() return await self._to_calendar_model(cal, db=db) + async def set_default_calendar( + self, user_id: str, calendar_id: str, db: Optional[AsyncSession] = None + ) -> Optional[CalendarModel]: + """Set a calendar as the user's default, clearing all others.""" + async with get_async_db_context(db) as db: + # Clear all defaults for this user + await db.execute( + update(Calendar) + .where(Calendar.user_id == user_id, Calendar.is_default == True) + .values(is_default=False) + ) + # Set the new default + result = await db.execute( + select(Calendar).filter(Calendar.id == calendar_id, Calendar.user_id == user_id) + ) + cal = result.scalars().first() + if not cal: + return None + cal.is_default = True + cal.updated_at = int(time.time_ns()) + await db.commit() + return await self._to_calendar_model(cal, db=db) + async def delete_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool: - """Delete a non-system calendar. Cascades to events, attendees, and grants.""" + """Delete a non-default calendar. Cascades to events, attendees, and grants.""" try: async with get_async_db_context(db) as db: result = await db.execute(select(Calendar).filter(Calendar.id == id)) cal = result.scalars().first() - if not cal or cal.is_system: + if not cal or cal.is_default: return False # Delete attendees for all events in this calendar diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py index 4b052bd754..220edf853c 100644 --- a/backend/open_webui/routers/calendar.py +++ b/backend/open_webui/routers/calendar.py @@ -310,10 +310,16 @@ async def delete_calendar(calendar_id: str, user: UserModel = Depends(get_verifi if cal.user_id != user.id and user.role != 'admin': raise HTTPException(status_code=403, detail='Only owner can delete calendar') - if cal.is_system: - raise HTTPException(status_code=400, detail='Cannot delete system calendar') result = await Calendars.delete_calendar_by_id(calendar_id) if not result: raise HTTPException(status_code=500, detail='Failed to delete') return {'status': True} + + +@router.post('/{calendar_id}/default') +async def set_default_calendar(calendar_id: str, user: UserModel = Depends(get_verified_user)): + cal = await Calendars.set_default_calendar(user.id, calendar_id) + if not cal: + raise HTTPException(status_code=404, detail='Calendar not found') + return cal diff --git a/src/lib/apis/calendar/index.ts b/src/lib/apis/calendar/index.ts index 39540bb890..fa75f9a6a7 100644 --- a/src/lib/apis/calendar/index.ts +++ b/src/lib/apis/calendar/index.ts @@ -5,7 +5,7 @@ export type CalendarModel = { user_id: string; name: string; color: string | null; - is_system: boolean; + is_default: boolean; data: Record | null; meta: Record | null; access_grants: any[]; @@ -188,6 +188,37 @@ export const deleteCalendar = async (token: string, calendarId: string): Promise return res?.status ?? false; }; +export const setDefaultCalendar = async ( + token: string, + calendarId: string +): Promise => { + let error = null; + + const res = await fetch(`${WEBUI_API_BASE_URL}/calendars/${calendarId}/default`, { + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + authorization: `Bearer ${token}` + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + error = err.detail; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + // ── Events ───────────────────────────────── export const getCalendarEvents = async ( diff --git a/src/routes/(app)/calendar/+page.svelte b/src/routes/(app)/calendar/+page.svelte index 89940ef23b..25671fc791 100644 --- a/src/routes/(app)/calendar/+page.svelte +++ b/src/routes/(app)/calendar/+page.svelte @@ -128,7 +128,7 @@ showEventModal = true; } - $: defaultCalendarId = calendars.find((c) => !c.is_system || c.name === 'Personal')?.id || calendars[0]?.id || ''; + $: defaultCalendarId = calendars.find((c) => c.is_default)?.id || calendars[0]?.id || ''; onMount(async () => { await loadCalendars(); From f0ec5ee08ff6978131b3d657c8a8bc98c8533d05 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 19 Apr 2026 21:49:48 +0900 Subject: [PATCH 293/404] refac --- src/lib/components/calendar/CalendarSidebar.svelte | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/components/calendar/CalendarSidebar.svelte b/src/lib/components/calendar/CalendarSidebar.svelte index 09e604a281..8ed0df4727 100644 --- a/src/lib/components/calendar/CalendarSidebar.svelte +++ b/src/lib/components/calendar/CalendarSidebar.svelte @@ -72,7 +72,7 @@
-
{miniMonthNames[miniMonth]} {miniYear}
+
{miniMonthNames[miniMonth]} {miniYear}
-
+
{#each ['S', 'M', 'T', 'W', 'T', 'F', 'S'] as d}
{d}
{/each}
-
+
{#each miniDays as day}
+ + diff --git a/src/lib/components/workspace/Models/BuiltinTools.svelte b/src/lib/components/workspace/Models/BuiltinTools.svelte index b900d004b3..fe99005688 100644 --- a/src/lib/components/workspace/Models/BuiltinTools.svelte +++ b/src/lib/components/workspace/Models/BuiltinTools.svelte @@ -50,6 +50,10 @@ automations: { label: $i18n.t('Automations'), description: $i18n.t('Create and manage scheduled automations') + }, + calendar: { + label: $i18n.t('Calendar'), + description: $i18n.t('List calendars, search, create, update, and delete calendar events') } }; From f45d0f130ef9c3d3958f54320b987f2e2eacc421 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 19 Apr 2026 22:22:15 +0900 Subject: [PATCH 295/404] refac --- backend/open_webui/config.py | 6 +++ backend/open_webui/main.py | 3 ++ backend/open_webui/routers/auths.py | 4 ++ backend/open_webui/routers/calendar.py | 49 ++++++++++++++----- backend/open_webui/utils/tools.py | 5 +- .../components/admin/Settings/General.svelte | 8 +++ .../components/layout/Sidebar/UserMenu.svelte | 2 +- 7 files changed, 63 insertions(+), 14 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index a68720a7c0..1ee107a6ac 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1624,6 +1624,12 @@ ENABLE_CHANNELS = PersistentConfig( os.environ.get('ENABLE_CHANNELS', 'False').lower() == 'true', ) +ENABLE_CALENDAR = PersistentConfig( + 'ENABLE_CALENDAR', + 'calendar.enable', + os.environ.get('ENABLE_CALENDAR', 'True').lower() == 'true', +) + AUTOMATION_MAX_COUNT = PersistentConfig( 'AUTOMATION_MAX_COUNT', 'automations.max_count', diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index c13250c587..23379a7750 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -396,6 +396,7 @@ from open_webui.config import ( AUTOMATION_MAX_COUNT, AUTOMATION_MIN_INTERVAL, ENABLE_CHANNELS, + ENABLE_CALENDAR, ENABLE_NOTES, ENABLE_USER_STATUS, ENABLE_COMMUNITY_SHARING, @@ -902,6 +903,7 @@ app.state.config.FOLDER_MAX_FILE_COUNT = FOLDER_MAX_FILE_COUNT app.state.config.AUTOMATION_MAX_COUNT = AUTOMATION_MAX_COUNT app.state.config.AUTOMATION_MIN_INTERVAL = AUTOMATION_MIN_INTERVAL app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS +app.state.config.ENABLE_CALENDAR = ENABLE_CALENDAR app.state.config.ENABLE_NOTES = ENABLE_NOTES app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING @@ -2218,6 +2220,7 @@ async def get_app_config(request: Request): 'enable_folders': app.state.config.ENABLE_FOLDERS, 'folder_max_file_count': app.state.config.FOLDER_MAX_FILE_COUNT, 'enable_channels': app.state.config.ENABLE_CHANNELS, + 'enable_calendar': app.state.config.ENABLE_CALENDAR, 'enable_notes': app.state.config.ENABLE_NOTES, 'enable_web_search': app.state.config.ENABLE_WEB_SEARCH, 'enable_code_execution': app.state.config.ENABLE_CODE_EXECUTION, diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 651e123b64..c8daa4957a 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -972,6 +972,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)): 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, + 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, 'ENABLE_NOTES': request.app.state.config.ENABLE_NOTES, 'ENABLE_USER_WEBHOOKS': request.app.state.config.ENABLE_USER_WEBHOOKS, @@ -1000,6 +1001,7 @@ class AdminConfig(BaseModel): AUTOMATION_MAX_COUNT: Optional[int | str] = None AUTOMATION_MIN_INTERVAL: Optional[int | str] = None ENABLE_CHANNELS: bool + ENABLE_CALENDAR: bool ENABLE_MEMORIES: bool ENABLE_NOTES: bool ENABLE_USER_WEBHOOKS: bool @@ -1031,6 +1033,7 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep int(form_data.AUTOMATION_MIN_INTERVAL) if form_data.AUTOMATION_MIN_INTERVAL else '' ) request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS + request.app.state.config.ENABLE_CALENDAR = form_data.ENABLE_CALENDAR request.app.state.config.ENABLE_MEMORIES = form_data.ENABLE_MEMORIES request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES @@ -1074,6 +1077,7 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, + 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, 'ENABLE_NOTES': request.app.state.config.ENABLE_NOTES, 'ENABLE_USER_WEBHOOKS': request.app.state.config.ENABLE_USER_WEBHOOKS, diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py index 220edf853c..f92f5b8943 100644 --- a/backend/open_webui/routers/calendar.py +++ b/backend/open_webui/routers/calendar.py @@ -2,7 +2,7 @@ import logging import time from typing import Optional -from fastapi import APIRouter, Depends, HTTPException +from fastapi import APIRouter, Depends, HTTPException, Request from pydantic import BaseModel from open_webui.models.calendar import ( @@ -24,12 +24,22 @@ from open_webui.models.groups import Groups from open_webui.models.users import UserModel from open_webui.utils.auth import get_verified_user from open_webui.utils.calendar import expand_recurring_event +from open_webui.constants import ERROR_MESSAGES log = logging.getLogger(__name__) router = APIRouter() +async def check_calendar_enabled(request: Request): + """Dependency to ensure calendar feature is globally enabled.""" + if not request.app.state.config.ENABLE_CALENDAR: + raise HTTPException( + status_code=403, + detail=ERROR_MESSAGES.FEATURE_DISABLED('Calendar'), + ) + + async def _check_calendar_access( calendar_id: str, user: UserModel, permission: str = 'write' ) -> CalendarModel: @@ -58,14 +68,16 @@ async def _check_calendar_access( @router.get('/', response_model=list[CalendarModel]) -async def get_calendars(user: UserModel = Depends(get_verified_user)): +async def get_calendars(request: Request, user: UserModel = Depends(get_verified_user)): """List user's calendars (owned + shared). Auto-creates defaults on first call.""" + await check_calendar_enabled(request) return await Calendars.get_calendars_by_user(user.id) @router.post('/create', response_model=CalendarModel) -async def create_calendar(form_data: CalendarForm, user: UserModel = Depends(get_verified_user)): +async def create_calendar(request: Request, form_data: CalendarForm, user: UserModel = Depends(get_verified_user)): """Create a new user calendar.""" + await check_calendar_enabled(request) return await Calendars.insert_new_calendar(user.id, form_data) @@ -76,6 +88,7 @@ async def create_calendar(form_data: CalendarForm, user: UserModel = Depends(get @router.get('/events') async def get_events( + request: Request, start: str, end: str, calendar_ids: Optional[str] = None, @@ -92,6 +105,7 @@ async def get_events( - Stored events from the database - Virtual events computed from active automation RRULEs (Scheduled Tasks calendar) """ + await check_calendar_enabled(request) from datetime import datetime try: @@ -203,25 +217,29 @@ async def get_events( @router.post('/events/create', response_model=CalendarEventModel) -async def create_event(form_data: CalendarEventForm, user: UserModel = Depends(get_verified_user)): +async def create_event(request: Request, form_data: CalendarEventForm, user: UserModel = Depends(get_verified_user)): + await check_calendar_enabled(request) await _check_calendar_access(form_data.calendar_id, user, 'write') return await CalendarEvents.insert_new_event(user.id, form_data) @router.get('/events/search', response_model=CalendarEventListResponse) async def search_events( + request: Request, query: Optional[str] = None, skip: int = 0, limit: int = 30, user: UserModel = Depends(get_verified_user), ): + await check_calendar_enabled(request) return await CalendarEvents.search_events( user_id=user.id, query=query, skip=skip, limit=limit ) @router.get('/events/{event_id}', response_model=CalendarEventModel) -async def get_event(event_id: str, user: UserModel = Depends(get_verified_user)): +async def get_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_enabled(request) event = await CalendarEvents.get_event_by_id(event_id) if not event: raise HTTPException(status_code=404, detail='Event not found') @@ -233,8 +251,9 @@ async def get_event(event_id: str, user: UserModel = Depends(get_verified_user)) @router.post('/events/{event_id}/update', response_model=CalendarEventModel) async def update_event( - event_id: str, form_data: CalendarEventUpdateForm, user: UserModel = Depends(get_verified_user) + request: Request, event_id: str, form_data: CalendarEventUpdateForm, user: UserModel = Depends(get_verified_user) ): + await check_calendar_enabled(request) event = await CalendarEvents.get_event_by_id(event_id) if not event: raise HTTPException(status_code=404, detail='Event not found') @@ -248,7 +267,8 @@ async def update_event( @router.delete('/events/{event_id}/delete') -async def delete_event(event_id: str, user: UserModel = Depends(get_verified_user)): +async def delete_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_enabled(request) event = await CalendarEvents.get_event_by_id(event_id) if not event: raise HTTPException(status_code=404, detail='Event not found') @@ -263,9 +283,10 @@ async def delete_event(event_id: str, user: UserModel = Depends(get_verified_use @router.post('/events/{event_id}/rsvp', response_model=dict) async def rsvp_event( - event_id: str, form_data: RSVPForm, user: UserModel = Depends(get_verified_user) + request: Request, event_id: str, form_data: RSVPForm, user: UserModel = Depends(get_verified_user) ): """Update own RSVP status for an event.""" + await check_calendar_enabled(request) if form_data.status not in ('accepted', 'declined', 'tentative', 'pending'): raise HTTPException(status_code=400, detail='Invalid status') @@ -281,15 +302,17 @@ async def rsvp_event( @router.get('/{calendar_id}', response_model=CalendarModel) -async def get_calendar_by_id(calendar_id: str, user: UserModel = Depends(get_verified_user)): +async def get_calendar_by_id(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_enabled(request) cal = await _check_calendar_access(calendar_id, user, 'read') return cal @router.post('/{calendar_id}/update', response_model=CalendarModel) async def update_calendar( - calendar_id: str, form_data: CalendarUpdateForm, user: UserModel = Depends(get_verified_user) + request: Request, calendar_id: str, form_data: CalendarUpdateForm, user: UserModel = Depends(get_verified_user) ): + await check_calendar_enabled(request) cal = await _check_calendar_access(calendar_id, user, 'write') # Only owner/admin can change access grants @@ -303,7 +326,8 @@ async def update_calendar( @router.delete('/{calendar_id}/delete') -async def delete_calendar(calendar_id: str, user: UserModel = Depends(get_verified_user)): +async def delete_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_enabled(request) cal = await _check_calendar_access(calendar_id, user, 'write') # Only owner/admin can delete @@ -318,7 +342,8 @@ async def delete_calendar(calendar_id: str, user: UserModel = Depends(get_verifi @router.post('/{calendar_id}/default') -async def set_default_calendar(calendar_id: str, user: UserModel = Depends(get_verified_user)): +async def set_default_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): + await check_calendar_enabled(request) cal = await Calendars.set_default_calendar(user.id, calendar_id) if not cal: raise HTTPException(status_code=404, detail='Calendar not found') diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 52a8868391..e0791a35ff 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -557,7 +557,10 @@ async def get_builtin_tools( ) # Calendar tools - search/create/update/delete events - if is_builtin_tool_enabled('calendar'): + if ( + is_builtin_tool_enabled('calendar') + and getattr(request.app.state.config, 'ENABLE_CALENDAR', False) + ): builtin_functions.extend( [search_calendar_events, create_calendar_event, update_calendar_event, delete_calendar_event] ) diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index f2ba4a3ee1..f535bd68ee 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -756,6 +756,14 @@
+
+
+ {$i18n.t('Calendar')} ({$i18n.t('Beta')}) +
+ + +
+
{$i18n.t('Memories')} ({$i18n.t('Beta')}) diff --git a/src/lib/components/layout/Sidebar/UserMenu.svelte b/src/lib/components/layout/Sidebar/UserMenu.svelte index 30c29962b4..b159a0dd61 100644 --- a/src/lib/components/layout/Sidebar/UserMenu.svelte +++ b/src/lib/components/layout/Sidebar/UserMenu.svelte @@ -250,7 +250,7 @@ {/if} - {#if $user?.role === 'admin' || $user?.permissions?.features?.calendar} + {#if $config?.features?.enable_calendar && ($user?.role === 'admin' || $user?.permissions?.features?.calendar)} Date: Sun, 19 Apr 2026 22:33:32 +0900 Subject: [PATCH 296/404] refac --- backend/open_webui/config.py | 6 ++++++ backend/open_webui/main.py | 3 +++ backend/open_webui/routers/auths.py | 4 ++++ backend/open_webui/routers/automations.py | 5 +++++ backend/open_webui/utils/automations.py | 4 ++++ backend/open_webui/utils/tools.py | 6 +++++- src/lib/components/admin/Settings/General.svelte | 14 +++++++++++--- src/lib/components/layout/Sidebar/UserMenu.svelte | 2 +- src/routes/(app)/automations/+page.svelte | 2 +- src/routes/(app)/automations/[id]/+page.svelte | 4 ++-- 10 files changed, 42 insertions(+), 8 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 1ee107a6ac..53de67387f 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1630,6 +1630,12 @@ ENABLE_CALENDAR = PersistentConfig( os.environ.get('ENABLE_CALENDAR', 'True').lower() == 'true', ) +ENABLE_AUTOMATIONS = PersistentConfig( + 'ENABLE_AUTOMATIONS', + 'automations.enable', + os.environ.get('ENABLE_AUTOMATIONS', 'True').lower() == 'true', +) + AUTOMATION_MAX_COUNT = PersistentConfig( 'AUTOMATION_MAX_COUNT', 'automations.max_count', diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 23379a7750..f9b21e6592 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -393,6 +393,7 @@ from open_webui.config import ( API_KEYS_ALLOWED_ENDPOINTS, ENABLE_FOLDERS, FOLDER_MAX_FILE_COUNT, + ENABLE_AUTOMATIONS, AUTOMATION_MAX_COUNT, AUTOMATION_MIN_INTERVAL, ENABLE_CHANNELS, @@ -900,6 +901,7 @@ app.state.config.BANNERS = WEBUI_BANNERS app.state.config.ENABLE_FOLDERS = ENABLE_FOLDERS app.state.config.FOLDER_MAX_FILE_COUNT = FOLDER_MAX_FILE_COUNT +app.state.config.ENABLE_AUTOMATIONS = ENABLE_AUTOMATIONS app.state.config.AUTOMATION_MAX_COUNT = AUTOMATION_MAX_COUNT app.state.config.AUTOMATION_MIN_INTERVAL = AUTOMATION_MIN_INTERVAL app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS @@ -2221,6 +2223,7 @@ async def get_app_config(request: Request): 'folder_max_file_count': app.state.config.FOLDER_MAX_FILE_COUNT, 'enable_channels': app.state.config.ENABLE_CHANNELS, 'enable_calendar': app.state.config.ENABLE_CALENDAR, + 'enable_automations': app.state.config.ENABLE_AUTOMATIONS, 'enable_notes': app.state.config.ENABLE_NOTES, 'enable_web_search': app.state.config.ENABLE_WEB_SEARCH, 'enable_code_execution': app.state.config.ENABLE_CODE_EXECUTION, diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index c8daa4957a..d3337d8109 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -971,6 +971,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)): 'FOLDER_MAX_FILE_COUNT': request.app.state.config.FOLDER_MAX_FILE_COUNT, 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, + 'ENABLE_AUTOMATIONS': request.app.state.config.ENABLE_AUTOMATIONS, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, @@ -1000,6 +1001,7 @@ class AdminConfig(BaseModel): FOLDER_MAX_FILE_COUNT: Optional[int | str] = None AUTOMATION_MAX_COUNT: Optional[int | str] = None AUTOMATION_MIN_INTERVAL: Optional[int | str] = None + ENABLE_AUTOMATIONS: bool ENABLE_CHANNELS: bool ENABLE_CALENDAR: bool ENABLE_MEMORIES: bool @@ -1032,6 +1034,7 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep request.app.state.config.AUTOMATION_MIN_INTERVAL = ( int(form_data.AUTOMATION_MIN_INTERVAL) if form_data.AUTOMATION_MIN_INTERVAL else '' ) + request.app.state.config.ENABLE_AUTOMATIONS = form_data.ENABLE_AUTOMATIONS request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS request.app.state.config.ENABLE_CALENDAR = form_data.ENABLE_CALENDAR request.app.state.config.ENABLE_MEMORIES = form_data.ENABLE_MEMORIES @@ -1076,6 +1079,7 @@ async def update_admin_config(request: Request, form_data: AdminConfig, user=Dep 'FOLDER_MAX_FILE_COUNT': request.app.state.config.FOLDER_MAX_FILE_COUNT, 'AUTOMATION_MAX_COUNT': request.app.state.config.AUTOMATION_MAX_COUNT, 'AUTOMATION_MIN_INTERVAL': request.app.state.config.AUTOMATION_MIN_INTERVAL, + 'ENABLE_AUTOMATIONS': request.app.state.config.ENABLE_AUTOMATIONS, 'ENABLE_CHANNELS': request.app.state.config.ENABLE_CHANNELS, 'ENABLE_CALENDAR': request.app.state.config.ENABLE_CALENDAR, 'ENABLE_MEMORIES': request.app.state.config.ENABLE_MEMORIES, diff --git a/backend/open_webui/routers/automations.py b/backend/open_webui/routers/automations.py index d68bd8e2c6..ed33c4e8cb 100644 --- a/backend/open_webui/routers/automations.py +++ b/backend/open_webui/routers/automations.py @@ -39,6 +39,11 @@ PAGE_ITEM_COUNT = 30 async def check_automations_permission(request, user): + if not request.app.state.config.ENABLE_AUTOMATIONS: + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) if user.role != 'admin' and not await has_permission( user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS ): diff --git a/backend/open_webui/utils/automations.py b/backend/open_webui/utils/automations.py index 3866eb865a..ac1f4df699 100644 --- a/backend/open_webui/utils/automations.py +++ b/backend/open_webui/utils/automations.py @@ -126,6 +126,10 @@ async def automation_worker_loop(app) -> None: log.info(f'Automation worker started (poll interval: {AUTOMATION_POLL_INTERVAL}s)') while True: try: + if not getattr(app.state.config, 'ENABLE_AUTOMATIONS', False): + await asyncio.sleep(AUTOMATION_POLL_INTERVAL) + continue + async with get_async_db() as db: batch = await Automations.claim_due(int(time.time_ns()), limit=10, db=db) if batch: diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index e0791a35ff..1c47fc75a6 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -551,7 +551,11 @@ async def get_builtin_tools( builtin_functions.extend([create_tasks, update_task]) # Automation tools - create and manage scheduled automations from chat - if is_builtin_tool_enabled('automations') and await has_user_permission('automations'): + if ( + is_builtin_tool_enabled('automations') + and getattr(request.app.state.config, 'ENABLE_AUTOMATIONS', False) + and await has_user_permission('automations') + ): builtin_functions.extend( [create_automation, update_automation, list_automations, toggle_automation, delete_automation] ) diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index f535bd68ee..ddb81e844b 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -740,6 +740,14 @@
{/if} +
+
+ {$i18n.t('Memories')} ({$i18n.t('Beta')}) +
+ + +
+
{$i18n.t('Notes')} ({$i18n.t('Beta')}) @@ -758,7 +766,7 @@
- {$i18n.t('Calendar')} ({$i18n.t('Beta')}) + {$i18n.t('Calendar')}
@@ -766,10 +774,10 @@
- {$i18n.t('Memories')} ({$i18n.t('Beta')}) + {$i18n.t('Automations')}
- +
diff --git a/src/lib/components/layout/Sidebar/UserMenu.svelte b/src/lib/components/layout/Sidebar/UserMenu.svelte index b159a0dd61..dddcf42550 100644 --- a/src/lib/components/layout/Sidebar/UserMenu.svelte +++ b/src/lib/components/layout/Sidebar/UserMenu.svelte @@ -214,7 +214,7 @@
{$i18n.t('Settings')}
- {#if $user?.role === 'admin' || $user?.permissions?.features?.automations} + {#if $config?.features?.enable_automations && ($user?.role === 'admin' || $user?.permissions?.features?.automations)}
{ - if ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) { + if (!$config?.features?.enable_automations || ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false))) { goto('/'); return; } diff --git a/src/routes/(app)/automations/[id]/+page.svelte b/src/routes/(app)/automations/[id]/+page.svelte index 51745fa01e..9d7cf6bbed 100644 --- a/src/routes/(app)/automations/[id]/+page.svelte +++ b/src/routes/(app)/automations/[id]/+page.svelte @@ -4,7 +4,7 @@ import { onMount, getContext } from 'svelte'; import { page } from '$app/stores'; - import { user, showSidebar } from '$lib/stores'; + import { user, showSidebar, config } from '$lib/stores'; import { getAutomationById } from '$lib/apis/automations'; import AutomationEditor from '$lib/components/automations/AutomationEditor.svelte'; @@ -18,7 +18,7 @@ $: automationId = $page.params.id; onMount(async () => { - if ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false)) { + if (!$config?.features?.enable_automations || ($user?.role !== 'admin' && !($user?.permissions?.features?.automations ?? false))) { goto('/'); return; } From 5afc258c5b13f456be528420513ade546c5e86f9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 19 Apr 2026 22:37:10 +0900 Subject: [PATCH 297/404] refac --- backend/open_webui/config.py | 5 ++ backend/open_webui/routers/calendar.py | 45 ++++++++++-------- backend/open_webui/utils/tools.py | 1 + .../admin/Users/Groups/Permissions.svelte | 16 +++++++ static/favicon.png | Bin 10655 -> 21666 bytes static/static/favicon.png | Bin 10655 -> 21666 bytes 6 files changed, 48 insertions(+), 19 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 53de67387f..c43ead1d79 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1524,6 +1524,10 @@ USER_PERMISSIONS_FEATURES_AUTOMATIONS = ( os.environ.get('USER_PERMISSIONS_FEATURES_AUTOMATIONS', 'False').lower() == 'true' ) +USER_PERMISSIONS_FEATURES_CALENDAR = ( + os.environ.get('USER_PERMISSIONS_FEATURES_CALENDAR', 'True').lower() == 'true' +) + USER_PERMISSIONS_SETTINGS_INTERFACE = os.environ.get('USER_PERMISSIONS_SETTINGS_INTERFACE', 'True').lower() == 'true' @@ -1594,6 +1598,7 @@ DEFAULT_USER_PERMISSIONS = { 'code_interpreter': USER_PERMISSIONS_FEATURES_CODE_INTERPRETER, 'memories': USER_PERMISSIONS_FEATURES_MEMORIES, 'automations': USER_PERMISSIONS_FEATURES_AUTOMATIONS, + 'calendar': USER_PERMISSIONS_FEATURES_CALENDAR, }, 'settings': { 'interface': USER_PERMISSIONS_SETTINGS_INTERFACE, diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py index f92f5b8943..5fb7cb6f9d 100644 --- a/backend/open_webui/routers/calendar.py +++ b/backend/open_webui/routers/calendar.py @@ -2,8 +2,7 @@ import logging import time from typing import Optional -from fastapi import APIRouter, Depends, HTTPException, Request -from pydantic import BaseModel +from fastapi import APIRouter, Depends, HTTPException, Request, status from open_webui.models.calendar import ( Calendars, @@ -23,6 +22,7 @@ from open_webui.models.access_grants import AccessGrants from open_webui.models.groups import Groups from open_webui.models.users import UserModel from open_webui.utils.auth import get_verified_user +from open_webui.utils.access_control import has_permission from open_webui.utils.calendar import expand_recurring_event from open_webui.constants import ERROR_MESSAGES @@ -31,12 +31,19 @@ log = logging.getLogger(__name__) router = APIRouter() -async def check_calendar_enabled(request: Request): - """Dependency to ensure calendar feature is globally enabled.""" +async def check_calendar_permission(request: Request, user): + """Check global feature flag AND per-user permission for calendar access.""" if not request.app.state.config.ENABLE_CALENDAR: raise HTTPException( - status_code=403, - detail=ERROR_MESSAGES.FEATURE_DISABLED('Calendar'), + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) + if user.role != 'admin' and not await has_permission( + user.id, 'features.calendar', request.app.state.config.USER_PERMISSIONS + ): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.UNAUTHORIZED, ) @@ -70,14 +77,14 @@ async def _check_calendar_access( @router.get('/', response_model=list[CalendarModel]) async def get_calendars(request: Request, user: UserModel = Depends(get_verified_user)): """List user's calendars (owned + shared). Auto-creates defaults on first call.""" - await check_calendar_enabled(request) + await check_calendar_permission(request, user) return await Calendars.get_calendars_by_user(user.id) @router.post('/create', response_model=CalendarModel) async def create_calendar(request: Request, form_data: CalendarForm, user: UserModel = Depends(get_verified_user)): """Create a new user calendar.""" - await check_calendar_enabled(request) + await check_calendar_permission(request, user) return await Calendars.insert_new_calendar(user.id, form_data) @@ -105,7 +112,7 @@ async def get_events( - Stored events from the database - Virtual events computed from active automation RRULEs (Scheduled Tasks calendar) """ - await check_calendar_enabled(request) + await check_calendar_permission(request, user) from datetime import datetime try: @@ -218,7 +225,7 @@ async def get_events( @router.post('/events/create', response_model=CalendarEventModel) async def create_event(request: Request, form_data: CalendarEventForm, user: UserModel = Depends(get_verified_user)): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) await _check_calendar_access(form_data.calendar_id, user, 'write') return await CalendarEvents.insert_new_event(user.id, form_data) @@ -231,7 +238,7 @@ async def search_events( limit: int = 30, user: UserModel = Depends(get_verified_user), ): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) return await CalendarEvents.search_events( user_id=user.id, query=query, skip=skip, limit=limit ) @@ -239,7 +246,7 @@ async def search_events( @router.get('/events/{event_id}', response_model=CalendarEventModel) async def get_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) event = await CalendarEvents.get_event_by_id(event_id) if not event: raise HTTPException(status_code=404, detail='Event not found') @@ -253,7 +260,7 @@ async def get_event(request: Request, event_id: str, user: UserModel = Depends(g async def update_event( request: Request, event_id: str, form_data: CalendarEventUpdateForm, user: UserModel = Depends(get_verified_user) ): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) event = await CalendarEvents.get_event_by_id(event_id) if not event: raise HTTPException(status_code=404, detail='Event not found') @@ -268,7 +275,7 @@ async def update_event( @router.delete('/events/{event_id}/delete') async def delete_event(request: Request, event_id: str, user: UserModel = Depends(get_verified_user)): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) event = await CalendarEvents.get_event_by_id(event_id) if not event: raise HTTPException(status_code=404, detail='Event not found') @@ -286,7 +293,7 @@ async def rsvp_event( request: Request, event_id: str, form_data: RSVPForm, user: UserModel = Depends(get_verified_user) ): """Update own RSVP status for an event.""" - await check_calendar_enabled(request) + await check_calendar_permission(request, user) if form_data.status not in ('accepted', 'declined', 'tentative', 'pending'): raise HTTPException(status_code=400, detail='Invalid status') @@ -303,7 +310,7 @@ async def rsvp_event( @router.get('/{calendar_id}', response_model=CalendarModel) async def get_calendar_by_id(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) cal = await _check_calendar_access(calendar_id, user, 'read') return cal @@ -312,7 +319,7 @@ async def get_calendar_by_id(request: Request, calendar_id: str, user: UserModel async def update_calendar( request: Request, calendar_id: str, form_data: CalendarUpdateForm, user: UserModel = Depends(get_verified_user) ): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) cal = await _check_calendar_access(calendar_id, user, 'write') # Only owner/admin can change access grants @@ -327,7 +334,7 @@ async def update_calendar( @router.delete('/{calendar_id}/delete') async def delete_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) cal = await _check_calendar_access(calendar_id, user, 'write') # Only owner/admin can delete @@ -343,7 +350,7 @@ async def delete_calendar(request: Request, calendar_id: str, user: UserModel = @router.post('/{calendar_id}/default') async def set_default_calendar(request: Request, calendar_id: str, user: UserModel = Depends(get_verified_user)): - await check_calendar_enabled(request) + await check_calendar_permission(request, user) cal = await Calendars.set_default_calendar(user.id, calendar_id) if not cal: raise HTTPException(status_code=404, detail='Calendar not found') diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 1c47fc75a6..471ec8540d 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -564,6 +564,7 @@ async def get_builtin_tools( if ( is_builtin_tool_enabled('calendar') and getattr(request.app.state.config, 'ENABLE_CALENDAR', False) + and await has_user_permission('calendar') ): builtin_functions.extend( [search_calendar_events, create_calendar_event, update_calendar_event, delete_calendar_event] diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index 7bd8fd00e0..cbfcb67b0a 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -916,6 +916,22 @@
{/if}
+ +
+
+
+ {$i18n.t('Calendar')} +
+ +
+ {#if defaultPermissions?.features?.calendar && !permissions.features.calendar} +
+
+ {$i18n.t('This is a default user permission and will remain enabled.')} +
+
+ {/if} +

diff --git a/static/favicon.png b/static/favicon.png index 63735ad4616fa452325af0fe351139dca01ca0ab..10c84f440ced21353ee824440758cbd080c7bf55 100644 GIT binary patch literal 21666 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 literal 10655 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 literal 10655 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 Date: Sun, 19 Apr 2026 22:40:59 +0900 Subject: [PATCH 298/404] refac --- static/static/favicon.ico | Bin 15086 -> 4286 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/static/static/favicon.ico b/static/static/favicon.ico index 14c5f9c6d437ed109a8579031cf181ee52bdf30e..b819d42f96d1b745d1d815521c0997d588f451ef 100644 GIT binary patch literal 4286 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 bfagL*MEiZNd%>mb_i9fBsuCLy9d!Q>dBe1} From 37eba1c5a66b3145c122a6b40e5c29707526d121 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 19 Apr 2026 22:45:54 +0900 Subject: [PATCH 299/404] chore: format --- backend/open_webui/config.py | 4 +- .../56359461a091_add_calendar_tables.py | 82 ++++----- backend/open_webui/models/automations.py | 13 +- backend/open_webui/models/calendar.py | 98 ++++------- backend/open_webui/routers/calendar.py | 67 ++++--- backend/open_webui/routers/knowledge.py | 4 +- backend/open_webui/static/favicon.ico | Bin 15086 -> 4286 bytes backend/open_webui/static/favicon.png | Bin 10655 -> 21666 bytes backend/open_webui/tools/builtin.py | 13 +- backend/open_webui/utils/middleware.py | 30 +++- src/lib/apis/calendar/index.ts | 1 - .../calendar/CalendarEventChip.svelte | 6 +- .../calendar/CalendarEventModal.svelte | 6 +- .../components/calendar/CalendarView.svelte | 165 +++++++++++++++--- src/lib/components/chat/Chat.svelte | 2 +- .../chat/Messages/ResponseMessage.svelte | 2 +- src/lib/i18n/locales/ar-BH/translation.json | 16 ++ src/lib/i18n/locales/ar/translation.json | 16 ++ src/lib/i18n/locales/az-AZ/translation.json | 16 ++ src/lib/i18n/locales/bg-BG/translation.json | 16 ++ src/lib/i18n/locales/bn-BD/translation.json | 16 ++ src/lib/i18n/locales/bo-TB/translation.json | 16 ++ src/lib/i18n/locales/bs-BA/translation.json | 16 ++ src/lib/i18n/locales/ca-ES/translation.json | 16 ++ src/lib/i18n/locales/ceb-PH/translation.json | 16 ++ src/lib/i18n/locales/cs-CZ/translation.json | 16 ++ src/lib/i18n/locales/da-DK/translation.json | 16 ++ src/lib/i18n/locales/de-DE/translation.json | 16 ++ src/lib/i18n/locales/dg-DG/translation.json | 16 ++ src/lib/i18n/locales/el-GR/translation.json | 16 ++ src/lib/i18n/locales/en-GB/translation.json | 16 ++ src/lib/i18n/locales/en-US/translation.json | 16 ++ src/lib/i18n/locales/es-ES/translation.json | 16 ++ src/lib/i18n/locales/et-EE/translation.json | 16 ++ src/lib/i18n/locales/eu-ES/translation.json | 16 ++ src/lib/i18n/locales/fa-IR/translation.json | 16 ++ src/lib/i18n/locales/fi-FI/translation.json | 16 ++ src/lib/i18n/locales/fr-CA/translation.json | 16 ++ src/lib/i18n/locales/fr-FR/translation.json | 16 ++ src/lib/i18n/locales/gl-ES/translation.json | 16 ++ src/lib/i18n/locales/he-IL/translation.json | 16 ++ src/lib/i18n/locales/hi-IN/translation.json | 16 ++ src/lib/i18n/locales/hr-HR/translation.json | 16 ++ src/lib/i18n/locales/hu-HU/translation.json | 16 ++ src/lib/i18n/locales/id-ID/translation.json | 16 ++ src/lib/i18n/locales/ie-GA/translation.json | 16 ++ src/lib/i18n/locales/it-IT/translation.json | 16 ++ src/lib/i18n/locales/ja-JP/translation.json | 16 ++ src/lib/i18n/locales/ka-GE/translation.json | 16 ++ src/lib/i18n/locales/kab-DZ/translation.json | 16 ++ src/lib/i18n/locales/ko-KR/translation.json | 16 ++ src/lib/i18n/locales/lt-LT/translation.json | 16 ++ src/lib/i18n/locales/lv-LV/translation.json | 16 ++ src/lib/i18n/locales/ms-MY/translation.json | 16 ++ src/lib/i18n/locales/nb-NO/translation.json | 16 ++ src/lib/i18n/locales/nl-NL/translation.json | 16 ++ src/lib/i18n/locales/pa-IN/translation.json | 16 ++ src/lib/i18n/locales/pl-PL/translation.json | 16 ++ src/lib/i18n/locales/pt-BR/translation.json | 16 ++ src/lib/i18n/locales/pt-PT/translation.json | 16 ++ src/lib/i18n/locales/ro-RO/translation.json | 16 ++ src/lib/i18n/locales/ru-RU/translation.json | 16 ++ src/lib/i18n/locales/sk-SK/translation.json | 16 ++ src/lib/i18n/locales/sr-RS/translation.json | 16 ++ src/lib/i18n/locales/sv-SE/translation.json | 16 ++ src/lib/i18n/locales/ta-IN/translation.json | 16 ++ src/lib/i18n/locales/th-TH/translation.json | 16 ++ src/lib/i18n/locales/tk-TM/translation.json | 16 ++ src/lib/i18n/locales/tr-TR/translation.json | 16 ++ src/lib/i18n/locales/ug-CN/translation.json | 16 ++ src/lib/i18n/locales/uk-UA/translation.json | 16 ++ src/lib/i18n/locales/ur-PK/translation.json | 16 ++ .../i18n/locales/uz-Cyrl-UZ/translation.json | 16 ++ .../i18n/locales/uz-Latn-Uz/translation.json | 16 ++ src/lib/i18n/locales/vi-VN/translation.json | 16 ++ src/lib/i18n/locales/zh-CN/translation.json | 16 ++ src/lib/i18n/locales/zh-TW/translation.json | 16 ++ src/routes/(app)/automations/+page.svelte | 5 +- .../(app)/automations/[id]/+page.svelte | 5 +- 79 files changed, 1272 insertions(+), 207 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index c43ead1d79..d2c88cb2fb 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1524,9 +1524,7 @@ USER_PERMISSIONS_FEATURES_AUTOMATIONS = ( os.environ.get('USER_PERMISSIONS_FEATURES_AUTOMATIONS', 'False').lower() == 'true' ) -USER_PERMISSIONS_FEATURES_CALENDAR = ( - os.environ.get('USER_PERMISSIONS_FEATURES_CALENDAR', 'True').lower() == 'true' -) +USER_PERMISSIONS_FEATURES_CALENDAR = os.environ.get('USER_PERMISSIONS_FEATURES_CALENDAR', 'True').lower() == 'true' USER_PERMISSIONS_SETTINGS_INTERFACE = os.environ.get('USER_PERMISSIONS_SETTINGS_INTERFACE', 'True').lower() == 'true' diff --git a/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py index a0812578c8..e556440f56 100644 --- a/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py +++ b/backend/open_webui/migrations/versions/56359461a091_add_calendar_tables.py @@ -5,6 +5,7 @@ Revises: c1d2e3f4a5b6 Create Date: 2026-04-19 16:20:58.162045 """ + from typing import Sequence, Union from alembic import op @@ -19,52 +20,55 @@ depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: - op.create_table('calendar', - sa.Column('id', sa.Text(), nullable=False), - sa.Column('user_id', sa.Text(), nullable=False), - sa.Column('name', sa.Text(), nullable=False), - sa.Column('color', sa.Text(), nullable=True), - sa.Column('is_default', sa.Boolean(), nullable=False), - sa.Column('data', sa.JSON(), nullable=True), - sa.Column('meta', sa.JSON(), nullable=True), - sa.Column('created_at', sa.BigInteger(), nullable=False), - sa.Column('updated_at', sa.BigInteger(), nullable=False), - sa.PrimaryKeyConstraint('id') + op.create_table( + 'calendar', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('name', sa.Text(), nullable=False), + sa.Column('color', sa.Text(), nullable=True), + sa.Column('is_default', sa.Boolean(), nullable=False), + sa.Column('data', sa.JSON(), nullable=True), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), ) op.create_index('ix_calendar_user', 'calendar', ['user_id'], unique=False) - op.create_table('calendar_event', - sa.Column('id', sa.Text(), nullable=False), - sa.Column('calendar_id', sa.Text(), nullable=False), - sa.Column('user_id', sa.Text(), nullable=False), - sa.Column('title', sa.Text(), nullable=False), - sa.Column('description', sa.Text(), nullable=True), - sa.Column('start_at', sa.BigInteger(), nullable=False), - sa.Column('end_at', sa.BigInteger(), nullable=True), - sa.Column('all_day', sa.Boolean(), nullable=False), - sa.Column('rrule', sa.Text(), nullable=True), - sa.Column('color', sa.Text(), nullable=True), - sa.Column('location', sa.Text(), nullable=True), - sa.Column('data', sa.JSON(), nullable=True), - sa.Column('meta', sa.JSON(), nullable=True), - sa.Column('is_cancelled', sa.Boolean(), nullable=False), - sa.Column('created_at', sa.BigInteger(), nullable=False), - sa.Column('updated_at', sa.BigInteger(), nullable=False), - sa.PrimaryKeyConstraint('id') + op.create_table( + 'calendar_event', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('calendar_id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('title', sa.Text(), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('start_at', sa.BigInteger(), nullable=False), + sa.Column('end_at', sa.BigInteger(), nullable=True), + sa.Column('all_day', sa.Boolean(), nullable=False), + sa.Column('rrule', sa.Text(), nullable=True), + sa.Column('color', sa.Text(), nullable=True), + sa.Column('location', sa.Text(), nullable=True), + sa.Column('data', sa.JSON(), nullable=True), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('is_cancelled', sa.Boolean(), nullable=False), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), ) op.create_index('ix_calendar_event_calendar', 'calendar_event', ['calendar_id', 'start_at'], unique=False) op.create_index('ix_calendar_event_user_date', 'calendar_event', ['user_id', 'start_at'], unique=False) - op.create_table('calendar_event_attendee', - sa.Column('id', sa.Text(), nullable=False), - sa.Column('event_id', sa.Text(), nullable=False), - sa.Column('user_id', sa.Text(), nullable=False), - sa.Column('status', sa.Text(), nullable=False), - sa.Column('meta', sa.JSON(), nullable=True), - sa.Column('created_at', sa.BigInteger(), nullable=False), - sa.Column('updated_at', sa.BigInteger(), nullable=False), - sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('event_id', 'user_id', name='uq_event_attendee') + op.create_table( + 'calendar_event_attendee', + sa.Column('id', sa.Text(), nullable=False), + sa.Column('event_id', sa.Text(), nullable=False), + sa.Column('user_id', sa.Text(), nullable=False), + sa.Column('status', sa.Text(), nullable=False), + sa.Column('meta', sa.JSON(), nullable=True), + sa.Column('created_at', sa.BigInteger(), nullable=False), + sa.Column('updated_at', sa.BigInteger(), nullable=False), + sa.PrimaryKeyConstraint('id'), + sa.UniqueConstraint('event_id', 'user_id', name='uq_event_attendee'), ) op.create_index('ix_calendar_event_attendee_user', 'calendar_event_attendee', ['user_id', 'status'], unique=False) diff --git a/backend/open_webui/models/automations.py b/backend/open_webui/models/automations.py index c7c78a7c8e..05f449ad13 100644 --- a/backend/open_webui/models/automations.py +++ b/backend/open_webui/models/automations.py @@ -153,15 +153,11 @@ class AutomationTable: row = await db.get(Automation, id) return AutomationModel.model_validate(row) if row else None - async def get_active_by_user( - self, user_id: str, db: Optional[AsyncSession] = None - ) -> list[AutomationModel]: + async def get_active_by_user(self, user_id: str, db: Optional[AsyncSession] = None) -> list[AutomationModel]: """Get active automations for a user (for calendar RRULE expansion).""" async with get_async_db_context(db) as db: result = await db.execute( - select(Automation) - .filter_by(user_id=user_id, is_active=True) - .order_by(Automation.created_at.desc()) + select(Automation).filter_by(user_id=user_id, is_active=True).order_by(Automation.created_at.desc()) ) return [AutomationModel.model_validate(r) for r in result.scalars().all()] @@ -291,9 +287,8 @@ class AutomationTable: timezone_by_user_id: dict[str, Optional[str]] = {} if user_ids: from open_webui.models.users import User - tz_result = await db.execute( - select(User.id, User.timezone).where(User.id.in_(user_ids)) - ) + + tz_result = await db.execute(select(User.id, User.timezone).where(User.id.in_(user_ids))) timezone_by_user_id = {uid: tz for uid, tz in tz_result.all()} for row in rows: diff --git a/backend/open_webui/models/calendar.py b/backend/open_webui/models/calendar.py index 859632c494..9d2d71a45b 100644 --- a/backend/open_webui/models/calendar.py +++ b/backend/open_webui/models/calendar.py @@ -232,9 +232,7 @@ class CalendarEventListResponse(BaseModel): class CalendarTable: - async def _get_access_grants( - self, calendar_id: str, db: Optional[AsyncSession] = None - ) -> list[AccessGrantModel]: + async def _get_access_grants(self, calendar_id: str, db: Optional[AsyncSession] = None) -> list[AccessGrantModel]: return await AccessGrants.get_grants_by_resource('calendar', calendar_id, db=db) async def _to_calendar_model( @@ -245,15 +243,11 @@ class CalendarTable: ) -> CalendarModel: cal_data = CalendarModel.model_validate(cal).model_dump(exclude={'access_grants'}) cal_data['access_grants'] = ( - access_grants - if access_grants is not None - else await self._get_access_grants(cal_data['id'], db=db) + access_grants if access_grants is not None else await self._get_access_grants(cal_data['id'], db=db) ) return CalendarModel.model_validate(cal_data) - async def get_or_create_defaults( - self, user_id: str, db: Optional[AsyncSession] = None - ) -> list[CalendarModel]: + async def get_or_create_defaults(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: """Return user's calendars, creating 'Personal' and 'Scheduled Tasks' if none exist.""" async with get_async_db_context(db) as db: result = await db.execute( @@ -289,9 +283,7 @@ class CalendarTable: await db.commit() return [CalendarModel.model_validate(c) for c in defaults] - async def get_calendars_by_user( - self, user_id: str, db: Optional[AsyncSession] = None - ) -> list[CalendarModel]: + async def get_calendars_by_user(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: """Owned + shared calendars.""" async with get_async_db_context(db) as db: user_groups = await Groups.get_groups_by_member_id(user_id, db=db) @@ -317,14 +309,9 @@ class CalendarTable: cal_ids = [c.id for c in calendars] grants_map = await AccessGrants.get_grants_by_resources('calendar', cal_ids, db=db) - return [ - await self._to_calendar_model(c, access_grants=grants_map.get(c.id, []), db=db) - for c in calendars - ] + return [await self._to_calendar_model(c, access_grants=grants_map.get(c.id, []), db=db) for c in calendars] - async def get_calendar_by_id( - self, id: str, db: Optional[AsyncSession] = None - ) -> Optional[CalendarModel]: + async def get_calendar_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[CalendarModel]: async with get_async_db_context(db) as db: result = await db.execute(select(Calendar).filter(Calendar.id == id)) cal = result.scalars().first() @@ -414,9 +401,7 @@ class CalendarTable: .values(is_default=False) ) # Set the new default - result = await db.execute( - select(Calendar).filter(Calendar.id == calendar_id, Calendar.user_id == user_id) - ) + result = await db.execute(select(Calendar).filter(Calendar.id == calendar_id, Calendar.user_id == user_id)) cal = result.scalars().first() if not cal: return None @@ -435,15 +420,11 @@ class CalendarTable: return False # Delete attendees for all events in this calendar - event_ids_result = await db.execute( - select(CalendarEvent.id).filter(CalendarEvent.calendar_id == id) - ) + event_ids_result = await db.execute(select(CalendarEvent.id).filter(CalendarEvent.calendar_id == id)) event_ids = [r[0] for r in event_ids_result.all()] if event_ids: await db.execute( - delete(CalendarEventAttendee).filter( - CalendarEventAttendee.event_id.in_(event_ids) - ) + delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) ) # Delete events @@ -465,9 +446,7 @@ class CalendarEventTable: self, event_id: str, db: Optional[AsyncSession] = None ) -> list[CalendarEventAttendeeModel]: async with get_async_db_context(db) as db: - result = await db.execute( - select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id) - ) + result = await db.execute(select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) rows = result.scalars().all() return [CalendarEventAttendeeModel.model_validate(r) for r in rows] @@ -515,9 +494,7 @@ class CalendarEventTable: return await self._to_event_model(event, db=db) - async def get_event_by_id( - self, id: str, db: Optional[AsyncSession] = None - ) -> Optional[CalendarEventModel]: + async def get_event_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[CalendarEventModel]: async with get_async_db_context(db) as db: result = await db.execute(select(CalendarEvent).filter(CalendarEvent.id == id)) event = result.scalars().first() @@ -559,9 +536,7 @@ class CalendarEventTable: # Also get event IDs where user is an attendee attendee_event_ids_result = await db.execute( - select(CalendarEventAttendee.event_id).filter( - CalendarEventAttendee.user_id == user_id - ) + select(CalendarEventAttendee.event_id).filter(CalendarEventAttendee.user_id == user_id) ) attendee_event_ids = [r[0] for r in attendee_event_ids_result.all()] @@ -608,16 +583,12 @@ class CalendarEventTable: # Batch-load attendees for all events in one query (avoid N+1) event_ids = [event.id for event, _user in items] att_result = await db.execute( - select(CalendarEventAttendee).filter( - CalendarEventAttendee.event_id.in_(event_ids) - ) + select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) ) att_rows = att_result.scalars().all() att_map: dict[str, list[CalendarEventAttendeeModel]] = {} for a in att_rows: - att_map.setdefault(a.event_id, []).append( - CalendarEventAttendeeModel.model_validate(a) - ) + att_map.setdefault(a.event_id, []).append(CalendarEventAttendeeModel.model_validate(a)) events = [] for event, user in items: @@ -697,16 +668,12 @@ class CalendarEventTable: # Batch-load attendees event_ids = [event.id for event, _user in items] att_result = await db.execute( - select(CalendarEventAttendee).filter( - CalendarEventAttendee.event_id.in_(event_ids) - ) + select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id.in_(event_ids)) ) att_rows = att_result.scalars().all() att_map: dict[str, list[CalendarEventAttendeeModel]] = {} for a in att_rows: - att_map.setdefault(a.event_id, []).append( - CalendarEventAttendeeModel.model_validate(a) - ) + att_map.setdefault(a.event_id, []).append(CalendarEventAttendeeModel.model_validate(a)) events = [] for event, user in items: @@ -732,8 +699,16 @@ class CalendarEventTable: update_data = form_data.model_dump(exclude_unset=True) for field in [ - 'calendar_id', 'title', 'description', 'start_at', 'end_at', - 'all_day', 'rrule', 'color', 'location', 'is_cancelled', + 'calendar_id', + 'title', + 'description', + 'start_at', + 'end_at', + 'all_day', + 'rrule', + 'color', + 'location', + 'is_cancelled', ]: if field in update_data: setattr(event, field, update_data[field]) @@ -750,13 +725,10 @@ class CalendarEventTable: await db.commit() return await self._to_event_model(event, db=db) - async def delete_event_by_id(self, id: str, db: Optional[AsyncSession] = None) -> bool: try: async with get_async_db_context(db) as db: - await db.execute( - delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == id) - ) + await db.execute(delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == id)) await db.execute(delete(CalendarEvent).filter(CalendarEvent.id == id)) await db.commit() return True @@ -774,9 +746,7 @@ class CalendarEventAttendeeTable: """ async with get_async_db_context(db) as db: # Remove existing - await db.execute( - delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id) - ) + await db.execute(delete(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) now = int(time.time_ns()) models = [] @@ -819,20 +789,14 @@ class CalendarEventAttendeeTable: self, event_id: str, db: Optional[AsyncSession] = None ) -> list[CalendarEventAttendeeModel]: async with get_async_db_context(db) as db: - result = await db.execute( - select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id) - ) + result = await db.execute(select(CalendarEventAttendee).filter(CalendarEventAttendee.event_id == event_id)) return [CalendarEventAttendeeModel.model_validate(r) for r in result.scalars().all()] - async def get_events_by_attendee( - self, user_id: str, db: Optional[AsyncSession] = None - ) -> list[str]: + async def get_events_by_attendee(self, user_id: str, db: Optional[AsyncSession] = None) -> list[str]: """Return event IDs where user is an attendee.""" async with get_async_db_context(db) as db: result = await db.execute( - select(CalendarEventAttendee.event_id).filter( - CalendarEventAttendee.user_id == user_id - ) + select(CalendarEventAttendee.event_id).filter(CalendarEventAttendee.user_id == user_id) ) return [r[0] for r in result.all()] diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py index 5fb7cb6f9d..47093ca788 100644 --- a/backend/open_webui/routers/calendar.py +++ b/backend/open_webui/routers/calendar.py @@ -47,9 +47,7 @@ async def check_calendar_permission(request: Request, user): ) -async def _check_calendar_access( - calendar_id: str, user: UserModel, permission: str = 'write' -) -> CalendarModel: +async def _check_calendar_access(calendar_id: str, user: UserModel, permission: str = 'write') -> CalendarModel: """Verify user has access to a calendar. Returns the calendar or raises 403/404.""" cal = await Calendars.get_calendar_by_id(calendar_id) if not cal: @@ -139,9 +137,7 @@ async def get_events( for event in events: event_dict = event.model_dump() if event_dict.get('rrule'): - instances = expand_recurring_event( - event_dict, start_ns, end_ns, tz=user.timezone - ) + instances = expand_recurring_event(event_dict, start_ns, end_ns, tz=user.timezone) for inst in instances: expanded.append(CalendarEventUserResponse(**{**inst, 'user': event.user})) else: @@ -189,34 +185,34 @@ async def get_events( expanded.append(CalendarEventUserResponse(**inst)) # Past runs: single range query joined with automation - runs_with_auto = await AutomationRuns.get_runs_by_user_range( - user.id, start_ns, end_ns - ) + runs_with_auto = await AutomationRuns.get_runs_by_user_range(user.id, start_ns, end_ns) for run, auto in runs_with_auto: - expanded.append(CalendarEventUserResponse( - id=f'run_{run.id}', - calendar_id=scheduled_cal.id, - user_id=user.id, - title=auto.name, - description=run.error if run.status == 'error' else '', - start_at=run.created_at, - end_at=None, - all_day=False, - color=None, - location=None, - data=None, - meta={ - 'automation_id': auto.id, - 'run_id': run.id, - 'chat_id': run.chat_id, - 'status': run.status, - }, - is_cancelled=False, - attendees=[], - created_at=run.created_at, - updated_at=run.created_at, - user=None, - )) + expanded.append( + CalendarEventUserResponse( + id=f'run_{run.id}', + calendar_id=scheduled_cal.id, + user_id=user.id, + title=auto.name, + description=run.error if run.status == 'error' else '', + start_at=run.created_at, + end_at=None, + all_day=False, + color=None, + location=None, + data=None, + meta={ + 'automation_id': auto.id, + 'run_id': run.id, + 'chat_id': run.chat_id, + 'status': run.status, + }, + is_cancelled=False, + attendees=[], + created_at=run.created_at, + updated_at=run.created_at, + user=None, + ) + ) except Exception as e: log.warning(f'Failed to compute automation events: {e}', exc_info=True) @@ -239,9 +235,7 @@ async def search_events( user: UserModel = Depends(get_verified_user), ): await check_calendar_permission(request, user) - return await CalendarEvents.search_events( - user_id=user.id, query=query, skip=skip, limit=limit - ) + return await CalendarEvents.search_events(user_id=user.id, query=query, skip=skip, limit=limit) @router.get('/events/{event_id}', response_model=CalendarEventModel) @@ -341,7 +335,6 @@ async def delete_calendar(request: Request, calendar_id: str, user: UserModel = if cal.user_id != user.id and user.role != 'admin': raise HTTPException(status_code=403, detail='Only owner can delete calendar') - result = await Calendars.delete_calendar_by_id(calendar_id) if not result: raise HTTPException(status_code=500, detail='Failed to delete') diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index d8d92b2428..f503169fc0 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -539,9 +539,7 @@ async def update_knowledge_access_by_id( 'sharing.public_knowledge', ) - knowledge.access_grants = await AccessGrants.set_access_grants( - 'knowledge', id, form_data.access_grants, db=db - ) + knowledge.access_grants = await AccessGrants.set_access_grants('knowledge', id, form_data.access_grants, db=db) return KnowledgeFilesResponse( **knowledge.model_dump(), diff --git a/backend/open_webui/static/favicon.ico b/backend/open_webui/static/favicon.ico index 14c5f9c6d437ed109a8579031cf181ee52bdf30e..b819d42f96d1b745d1d815521c0997d588f451ef 100644 GIT binary patch literal 4286 zcmeHJ%S)6|6u;vrp+z%U447HcLfS-#2u0qH`)ow`v`laeqb zaa{Q*a>xf^O^#0j!MBL-7d{%b)9+m8`}i8C8Fju|d57Q3opbIvzjMz$-}$Z(27DqT z1%HcoW+5y>hwpC&d<-c6c-oYDlIL&eHN6Il-w#P zD6k|XB!qy&;EhMonM@`@M53yy>gM3!;ERQY1?&3yx_xtVb8KsC>&IEZHn9B;AFV?} zLwPkdHR0^rY(^1y7~$dJlDn&`>;CHM>c^v_qeHCMWw5WcwY5(+o9zJ{qE;hMM9|aI zBih>9ZXoV7xzP>;BBO)T?-WL}avk>cn2UA@{oQI{QrRQ)aqN1YI z7%D3(MN(2y!0ztu8(oOJIN96Vdz+V+XRNQUSNZLByKp!hAx@{$=EYPO)xp6*_wexW z71X!NKQS>OCMPFNhlhv#x{!Er0uKB1^z=3Gsr*w@Q(|Uj#>_e|rn;!WF)%wj8wx&^ zAMr5%HDCPm^Yc_!S4TKMLSLfB#ztCMSyAI!US5`R^d8#Z-&f_@2{;_?{2U8p%>P}x zRy*(Q?WNe*STYz45(u7*Mk6IBC)3#2m|Ti;q_D6sii?Y*?d@%?xjH`&Kk`E{F)RdC)%*>RzZf`%?8qwEfY(+&y#CbYJ{s-pf=0b7aYW=y+pZD*T zzoVl=6V>swwzgLC7Zw)&Gybx&GRcvXlSAl{Y7BT!5uZKRq19^rXZc5epy=pmS$|ns zS(2-%sfp6l(`Ef}4Qy;|oVNaC{yFE$@RfhwaCdjNdjcL$tP!K5qiX(n0y*O1s>)X~oT_<&_QdK!xU5otLr_R}HuYa#S4~~=J zWIEluI~wLW|LNp7|8yKDFE8{v$8m1!yBrPqKB=bTEYJx5&^W5%{Hoynw-6D@R5Vny zQ4CZpR~%H_RJ>GFgupZJ__jq)1fIL62RR_Pr{j(y~0tdLn zRSp`D`cAo}((h{CBXEIJmF+>}&~8#u-_>kPfm5$obxFU|N7DBHt^&8HeXD+>@BJQq zWU~H&+i!klpzj%1zvbAJEa%F4aP*AR`a46x_?<3NqD0;Kl0GwkDpMpRZ{NO^YuB#H z@#Dv3TNkY15_|%$_}4?%ur{4~H_1 z^b_?+L*~HD0TY^wUAlBhCQh6vZQ8VvtgI{{DT^94YDi8_jtm<%Otx;_DxW|54(&BK%Q;$DuUyIi?sJu@>?YS*qUwQAM!%@bu+xg4s=AI@+esEA7r zA3iLtTD9`&a0QKLp?d_XAx{&25| zNg(tQyWw^D_3PL1sF^aFIdi6~OB>j+V~5cVfIr;Roqt^QhyF0!|7B%maryt%t5-5) z$PibTay)qOU{L;tdtB{zK#pwU; z+_~fFKijr#E9cIgi>{zwDk>_ZYuBzWck+!NtOQX1;m#OPr7(W=@891ue)aC%+th`R zA3u8Z;eGY$RT(^Zu!lQyi(|+BTHXb~pRqTt`2&4D^|nQe79LJbnlv#!U9ez*Y~Q|J zii(P4{P^+GxpQYvUhzHi>u?ExKiu0W9)+hH?V0)8vSrJB=WjJ@)->Z3{bP7Lx6h+S zjS}?3rJDTV40qj>6Dtmjyh+I_JKeFpR+cCF2N)vlXZdsOTGjC^q% zc9-P6WtBb z{QNt~EXaiME9JNHE+-7jPv!htKUlxm(E82wqxGxxvqr@4+|$Za{96&kJuR&d%@z5I zBE_GI$BNGi7Qa06j&H>{+@SyBhE7gIzJ~%LUn&o{I1}D ziG2Fm)Yra3Ty)SSjUN)>q4DX1E-B~(6S1q&J%TQ2kd`@Dtcr)m>!Y}@fPYXzTBO-0 zmVNzBzKKUU1}&sX+P;3!_mnq&3NqiCoJU9-8xi$E-%(G37&kSUn1YSp!^=T`)5fT) z)v0T$9+zMPTW;IbXWD8^zdw8SOm5t`Av<^Olx^F#$;FEo(D{5i*@9Jo`FfPHLY+qdjF1Lh1K`=zC&5qAVE;memVo4t4LdQ6xw zAyNCZ1K)O6**<3ve!@N{d(MeQ)G{l8|-8smTJ;Fc|063suh z|5QZOKkfi^@7~?yi+Zqc-#&A$Ykff5#7AAabTMT_$XR{@)b_{yBW%}>_kWoIQJ19zA*#(Jm7mf3$rw2BmcT4RJ`>{3B#PrSq>4hm_4f zv5#n7=%Yx<{QD~d!vQ~}Wc?Awf%=e=^_S&9s2uG2lm3D}i+GE(MsS z+Xui&P^?~QD4lXmleDpcEo@?&eTp1Ko+6Qb3eDp$ibBOT1#23>bD`oFP0m;JTdv{{ z#Y+YLqs*+>^5YwEa>Enhx8i?__X@u{ps$VajX1=0)6i$qQ4PndZG_a7KX&zw19?r4x^NYKHj z*A&KAoMUtEi8;sl^XJW3e7A1h%>6O=a2JI6b4buZ_k(@GJrM3b*}DhKGscY@C;j^M zGx@2cj~coj{h>pLy86t;NV9L>zOnS-;Niby$r5v)yQHK<;Lkmk82k%W-}ukY`|%(5 zjoRy7%*Bfrn>APr|3#D^KBla=3u))q(aJAW2a>KoA^mFA->@{2YCq^(QD53RNx4wA bfagL*MEiZNd%>mb_i9fBsuCLy9d!Q>dBe1} diff --git a/backend/open_webui/static/favicon.png b/backend/open_webui/static/favicon.png index 63735ad4616fa452325af0fe351139dca01ca0ab..10c84f440ced21353ee824440758cbd080c7bf55 100644 GIT binary patch literal 21666 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 literal 10655 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 dict: } - - - async def search_calendar_events( query: Optional[str] = None, start: Optional[str] = None, @@ -2915,7 +2912,11 @@ async def search_calendar_events( return json.dumps({'error': f'Invalid start datetime: {e}'}) try: - end_ns = _dt_to_ns(end, tz) if end else int(time.time() * 1_000) * 1_000_000 + 365 * 86400 * 1_000_000_000_000 + end_ns = ( + _dt_to_ns(end, tz) + if end + else int(time.time() * 1_000) * 1_000_000 + 365 * 86400 * 1_000_000_000_000 + ) except (ValueError, TypeError) as e: return json.dumps({'error': f'Invalid end datetime: {e}'}) @@ -2929,7 +2930,8 @@ async def search_calendar_events( if query: q = query.lower() items = [ - e for e in items + e + for e in items if q in (e.title or '').lower() or q in (e.description or '').lower() or q in (e.location or '').lower() @@ -3229,4 +3231,3 @@ async def delete_calendar_event( except Exception as e: log.exception(f'delete_calendar_event error: {e}') return json.dumps({'error': str(e)}) - diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index d44112b4ec..036dc9bf39 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -427,7 +427,11 @@ def _render_openai_tool_call_handler(item: dict, done: bool) -> str: if atype == 'search': queries = action.get('queries') or [] query = action.get('query', '') - summary = f'Search: {", ".join(str(q) for q in queries)}' if queries else (f'Search: {query}' if query else '') + summary = ( + f'Search: {", ".join(str(q) for q in queries)}' + if queries + else (f'Search: {query}' if query else '') + ) elif atype == 'open_page': summary = f'Open page: {action.get("url", "")}' if action.get('url') else '' elif atype == 'find_in_page': @@ -490,9 +494,13 @@ def serialize_output(output: list) -> str: files = result_item.get('files') embeds = result_item.get('embeds', '') - parts.append(f'
\nTool Executed\n{html.escape(json.dumps(result_text, ensure_ascii=False))}\n
') + parts.append( + f'
\nTool Executed\n{html.escape(json.dumps(result_text, ensure_ascii=False))}\n
' + ) else: - parts.append(f'
\nExecuting...\n
') + parts.append( + f'
\nExecuting...\n
' + ) elif item_type == 'function_call_output': # Already handled inline with function_call above @@ -529,9 +537,13 @@ def serialize_output(output: list) -> str: ) if status == 'completed' or duration is not None or not is_last_item: - parts.append(f'
\nThought for {duration or 0} seconds\n{display}\n
') + parts.append( + f'
\nThought for {duration or 0} seconds\n{display}\n
' + ) else: - parts.append(f'
\nThinking…\n{display}\n
') + parts.append( + f'
\nThinking…\n{display}\n
' + ) elif item_type == 'open_webui:code_interpreter': # Code interpreter needs to inspect/mutate prior accumulated content @@ -570,9 +582,13 @@ def serialize_output(output: list) -> str: output_attr = f' output="{html.escape(output_json)}"' if status == 'completed' or duration is not None or not is_last_item: - parts.append(f'
\nAnalyzed\n{display}\n
') + parts.append( + f'
\nAnalyzed\n{display}\n
' + ) else: - parts.append(f'
\nAnalyzing…\n{display}\n
') + parts.append( + f'
\nAnalyzing…\n{display}\n
' + ) return '\n'.join(parts).strip() diff --git a/src/lib/apis/calendar/index.ts b/src/lib/apis/calendar/index.ts index fa75f9a6a7..b496a42bc2 100644 --- a/src/lib/apis/calendar/index.ts +++ b/src/lib/apis/calendar/index.ts @@ -418,7 +418,6 @@ export const rsvpCalendarEvent = async ( return res; }; - export const searchCalendarEvents = async ( token: string, query: string | null, diff --git a/src/lib/components/calendar/CalendarEventChip.svelte b/src/lib/components/calendar/CalendarEventChip.svelte index c63eac1063..b1c3552e6c 100644 --- a/src/lib/components/calendar/CalendarEventChip.svelte +++ b/src/lib/components/calendar/CalendarEventChip.svelte @@ -21,7 +21,11 @@ style="background-color: {event.color || calendarColor || '#3b82f6'};" > - {#if !event.all_day}{new Date(event.start_at / 1_000_000).toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' }).replace(' ', '')}{/if} + {#if !event.all_day}{new Date(event.start_at / 1_000_000) + .toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' }) + .replace(' ', '')}{/if} {event.title} diff --git a/src/lib/components/calendar/CalendarEventModal.svelte b/src/lib/components/calendar/CalendarEventModal.svelte index 5540bda2fe..020a89f923 100644 --- a/src/lib/components/calendar/CalendarEventModal.svelte +++ b/src/lib/components/calendar/CalendarEventModal.svelte @@ -8,7 +8,11 @@ import Spinner from '$lib/components/common/Spinner.svelte'; import type { CalendarModel, CalendarEventModel, CalendarEventForm } from '$lib/apis/calendar'; - import { createCalendarEvent, updateCalendarEvent, deleteCalendarEvent } from '$lib/apis/calendar'; + import { + createCalendarEvent, + updateCalendarEvent, + deleteCalendarEvent + } from '$lib/apis/calendar'; const i18n = getContext('i18n'); const dispatch = createEventDispatcher(); diff --git a/src/lib/components/calendar/CalendarView.svelte b/src/lib/components/calendar/CalendarView.svelte index 0b67d7de98..5100a58b94 100644 --- a/src/lib/components/calendar/CalendarView.svelte +++ b/src/lib/components/calendar/CalendarView.svelte @@ -21,11 +21,24 @@ const NS = 1_000_000; const DAY_NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; const MONTH_NAMES = [ - 'January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December' + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' ]; - $: calColorMap = calendars.reduce((acc, c) => ({ ...acc, [c.id]: c.color }), {} as Record); + $: calColorMap = calendars.reduce( + (acc, c) => ({ ...acc, [c.id]: c.color }), + {} as Record + ); $: filteredEvents = events.filter((e) => visibleCalendarIds.has(e.calendar_id)); // Pre-group events by day key so the template reactively updates when events change @@ -102,7 +115,11 @@ }); } - function getEventsForHour(day: Date, hour: number, eventsList: CalendarEventModel[] = filteredEvents): CalendarEventModel[] { + function getEventsForHour( + day: Date, + hour: number, + eventsList: CalendarEventModel[] = filteredEvents + ): CalendarEventModel[] { const hourStartMs = new Date(day.getFullYear(), day.getMonth(), day.getDate(), hour).getTime(); const hourEndMs = hourStartMs + 3_600_000; return eventsList.filter((e) => { @@ -157,9 +174,10 @@ dispatch('eventClick', event); } - $: headerText = view === 'day' - ? `${DAY_NAMES[currentDate.getDay()]}, ${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getDate()}, ${currentDate.getFullYear()}` - : `${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getFullYear()}`; + $: headerText = + view === 'day' + ? `${DAY_NAMES[currentDate.getDay()]}, ${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getDate()}, ${currentDate.getFullYear()}` + : `${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getFullYear()}`;
@@ -168,7 +186,10 @@
{#if $mobile}
- + -
@@ -232,7 +285,19 @@ class="md:hidden px-2 py-1.5 rounded-xl bg-black text-white dark:bg-white dark:text-black transition text-sm flex items-center" on:click={() => dispatch('newEvent')} > - +
@@ -244,13 +309,19 @@
{#each DAY_NAMES as day} -
{$i18n.t(day)}
+
+ {$i18n.t(day)} +
{/each}
-
+
{#each monthDays as day, i} - {@const dayKey = new Date(day.getFullYear(), day.getMonth(), day.getDate()).getTime().toString()} + {@const dayKey = new Date(day.getFullYear(), day.getMonth(), day.getDate()) + .getTime() + .toString()} {@const dayEvents = eventsByDay[dayKey] || []} {@const col = i % 7} {@const row = Math.floor(i / 7)} @@ -293,18 +364,34 @@
- + {:else if view === 'week'}
-
+
-
+
{#each weekDays as day} -
-
{DAY_NAMES[day.getDay()]}
-
+
+
+ {DAY_NAMES[day.getDay()]} +
+
{day.getDate()}
@@ -313,12 +400,22 @@
{#each hours as hour} -
-
{hour > 0 ? formatHour(hour) : ''}
+
+
+ {hour > 0 ? formatHour(hour) : ''} +
{#each weekDays as day} {@const hourEvents = getEventsForHour(day, hour, filteredEvents)}
- + {:else}
-
+
{#each hours as hour} {@const hourEvents = getEventsForHour(currentDate, hour, filteredEvents)} -
-
{hour > 0 ? formatHour(hour) : ''}
+
+
+ {hour > 0 ? formatHour(hour) : ''} +
+ + {/if}
-
{$i18n.t('Settings')}
- + {/if} + + {#if $user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools} +
+ {/if} {#if $config?.features?.enable_automations && ($user?.role === 'admin' || $user?.permissions?.features?.automations)} - { - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; - e.preventDefault(); - show = false; - goto('/automations'); - if ($mobile) { - await tick(); - showSidebar.set(false); - } - }} - > - -
{$i18n.t('Automations')}
- + + + {/if} +
{/if} {#if $config?.features?.enable_calendar && ($user?.role === 'admin' || $user?.permissions?.features?.calendar)} - { - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; - e.preventDefault(); - show = false; - goto('/calendar'); - }} - > - -
{$i18n.t('Calendar')}
- + + + {/if} +
{/if} {#if role === 'admin'} - { - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) { - return; - } - e.preventDefault(); - show = false; - goto('/playground'); - if ($mobile) { - await tick(); - showSidebar.set(false); - } - }} - > -
- -
-
{$i18n.t('Playground')}
-
+ {/if} +
+
+ + {#if role === 'admin'} Date: Sun, 19 Apr 2026 23:17:25 +0900 Subject: [PATCH 302/404] refac --- src/routes/(app)/calendar/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/(app)/calendar/+page.svelte b/src/routes/(app)/calendar/+page.svelte index 25671fc791..6e7296efb3 100644 --- a/src/routes/(app)/calendar/+page.svelte +++ b/src/routes/(app)/calendar/+page.svelte @@ -159,7 +159,7 @@ {#if loaded}
- -
{#if ($models ?? []).length > 0 && (($settings?.pinnedModels ?? []).length > 0 || $config?.default_pinned_models)} Date: Sun, 19 Apr 2026 23:46:32 +0900 Subject: [PATCH 306/404] refac --- .../components/layout/Sidebar/UserMenu.svelte | 130 +++++++++--------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/src/lib/components/layout/Sidebar/UserMenu.svelte b/src/lib/components/layout/Sidebar/UserMenu.svelte index 05668e25d5..ec86a11a9d 100644 --- a/src/lib/components/layout/Sidebar/UserMenu.svelte +++ b/src/lib/components/layout/Sidebar/UserMenu.svelte @@ -234,50 +234,6 @@
{/if} - {#if ($config?.features?.enable_notes ?? false) && ($user?.role === 'admin' || ($user?.permissions?.features?.notes ?? true))} - - {/if} - {#if $user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools}
{/if} - {#if $config?.features?.enable_automations && ($user?.role === 'admin' || $user?.permissions?.features?.automations)} + {#if ($config?.features?.enable_notes ?? false) && ($user?.role === 'admin' || ($user?.permissions?.features?.notes ?? true))}
{ if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) return; e.preventDefault(); show = false; - goto('/automations'); + goto('/notes'); if ($mobile) { await tick(); showSidebar.set(false); @@ -353,35 +309,22 @@ }} >
- - - +
-
{$i18n.t('Automations')}
+
{$i18n.t('Notes')}
{#if shiftKey}
{/if} + {#if $config?.features?.enable_automations && ($user?.role === 'admin' || $user?.permissions?.features?.automations)} + + {/if} + {#if role === 'admin'} - {#if pinnedItems.includes('notes') && ($config?.features?.enable_notes ?? false) && ($user?.role === 'admin' || ($user?.permissions?.features?.notes ?? true))} - - {/if} - - {#if pinnedItems.includes('workspace') && ($user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools)} - - {/if} - - {#if pinnedItems.includes('automations') && $config?.features?.enable_automations && ($user?.role === 'admin' || $user?.permissions?.features?.automations)} - - {/if} - - {#if pinnedItems.includes('calendar') && $config?.features?.enable_calendar && ($user?.role === 'admin' || $user?.permissions?.features?.calendar)} - - {/if} - - {#if pinnedItems.includes('playground') && $user?.role === 'admin'} - - {/if} + {#each pinnedItems as itemId (itemId)} + {@const meta = getMenuItemMeta(itemId)} + {#if meta && isMenuItemVisible(itemId)} + + {/if} + {/each}
From eb16ae92a5b8f93fe3fde9fba709bcfd85792f6d Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 19 Apr 2026 23:49:45 +0900 Subject: [PATCH 308/404] chore: format --- src/lib/components/layout/Sidebar.svelte | 47 ++++++++++++++++++++---- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index 10243df067..fcea714f02 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -856,7 +856,7 @@
- {#each pinnedItems as itemId (itemId)} + {#each pinnedItems as itemId (itemId)} {@const meta = getMenuItemMeta(itemId)} {#if meta && isMenuItemVisible(itemId)}
@@ -877,16 +877,49 @@ {#if itemId === 'notes'} {:else if itemId === 'workspace'} - - + + {:else if itemId === 'automations'} - - + + {:else if itemId === 'calendar'} - - + + {:else if itemId === 'playground'} From f6d1969067269ce3ff12a21ff090f73ddf88b793 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 19 Apr 2026 23:55:17 +0900 Subject: [PATCH 309/404] refac --- .../components/layout/Sidebar/UserMenu.svelte | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/src/lib/components/layout/Sidebar/UserMenu.svelte b/src/lib/components/layout/Sidebar/UserMenu.svelte index ec86a11a9d..d7b79752c6 100644 --- a/src/lib/components/layout/Sidebar/UserMenu.svelte +++ b/src/lib/components/layout/Sidebar/UserMenu.svelte @@ -234,6 +234,74 @@
{/if} + + + {#if role === 'admin'} + { + if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) { + return; + } + e.preventDefault(); + show = false; + goto('/admin'); + if ($mobile) { + await tick(); + showSidebar.set(false); + } + }} + > +
+ +
+
{$i18n.t('Admin Panel')}
+
+ {/if} + + + +
+ {#if $user?.role === 'admin' || $user?.permissions?.workspace?.models || $user?.permissions?.workspace?.knowledge || $user?.permissions?.workspace?.prompts || $user?.permissions?.workspace?.tools}
{/if} -
- - - - - - {#if role === 'admin'} -
{ - if (e.metaKey || e.ctrlKey || e.shiftKey || e.button === 1) { - return; - } - e.preventDefault(); - show = false; - goto('/admin'); - if ($mobile) { - await tick(); - showSidebar.set(false); - } - }} - > -
- -
-
{$i18n.t('Admin Panel')}
-
- {/if} - {#if help}
From 1d501cfa3f96b3a9a5f4f7ce996947671fd09f29 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 20 Apr 2026 00:07:34 +0900 Subject: [PATCH 310/404] refac --- backend/open_webui/models/calendar.py | 60 ++++++--------------------- 1 file changed, 13 insertions(+), 47 deletions(-) diff --git a/backend/open_webui/models/calendar.py b/backend/open_webui/models/calendar.py index 9afa7c15e2..4841e7b2dd 100644 --- a/backend/open_webui/models/calendar.py +++ b/backend/open_webui/models/calendar.py @@ -248,7 +248,7 @@ class CalendarTable: return CalendarModel.model_validate(cal_data) async def get_or_create_defaults(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: - """Return user's calendars, creating 'Personal' and 'Scheduled Tasks' if none exist.""" + """Return user's calendars, creating 'Personal' default if none exist.""" async with get_async_db_context(db) as db: result = await db.execute( select(Calendar).filter(Calendar.user_id == user_id).order_by(Calendar.created_at.asc()) @@ -259,29 +259,18 @@ class CalendarTable: return [CalendarModel.model_validate(c) for c in calendars] now = int(time.time_ns()) - defaults = [ - Calendar( - id=str(uuid4()), - user_id=user_id, - name='Personal', - color='#3b82f6', - is_default=True, - created_at=now, - updated_at=now, - ), - Calendar( - id=str(uuid4()), - user_id=user_id, - name='Scheduled Tasks', - color='#8b5cf6', - created_at=now + 1, - updated_at=now + 1, - ), - ] - for cal in defaults: - db.add(cal) + cal = Calendar( + id=str(uuid4()), + user_id=user_id, + name='Personal', + color='#3b82f6', + is_default=True, + created_at=now, + updated_at=now, + ) + db.add(cal) await db.commit() - return [CalendarModel.model_validate(c) for c in defaults] + return [CalendarModel.model_validate(cal)] async def get_calendars_by_user(self, user_id: str, db: Optional[AsyncSession] = None) -> list[CalendarModel]: """Owned + shared calendars.""" @@ -317,30 +306,7 @@ class CalendarTable: cal = result.scalars().first() return await self._to_calendar_model(cal, db=db) if cal else None - async def get_scheduled_tasks_calendar( - self, user_id: str, db: Optional[AsyncSession] = None - ) -> Optional[CalendarModel]: - """Get the user's Scheduled Tasks calendar (for automation integration).""" - async with get_async_db_context(db) as db: - result = await db.execute( - select(Calendar).filter( - Calendar.user_id == user_id, - Calendar.name == 'Scheduled Tasks', - ) - ) - cal = result.scalars().first() - if not cal: - # Ensure defaults exist then retry - await self.get_or_create_defaults(user_id, db=db) - result = await db.execute( - select(Calendar).filter( - Calendar.user_id == user_id, - Calendar.name == 'Scheduled Tasks', - ) - ) - cal = result.scalars().first() - # Lightweight return — skip access_grants loading since we only need id/color - return CalendarModel.model_validate(cal) if cal else None + async def insert_new_calendar( self, user_id: str, form_data: CalendarForm, db: Optional[AsyncSession] = None From 24dd5b461eb44d306c823389e0f664c45db042e8 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 20 Apr 2026 00:09:24 +0900 Subject: [PATCH 311/404] refac --- backend/open_webui/routers/calendar.py | 51 +++++++++++++++---- .../calendar/CalendarEventModal.svelte | 2 +- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py index 47093ca788..cde2ea0484 100644 --- a/backend/open_webui/routers/calendar.py +++ b/backend/open_webui/routers/calendar.py @@ -30,6 +30,8 @@ log = logging.getLogger(__name__) router = APIRouter() +SCHEDULED_TASKS_CALENDAR_ID = '__scheduled_tasks__' + async def check_calendar_permission(request: Request, user): """Check global feature flag AND per-user permission for calendar access.""" @@ -47,6 +49,17 @@ async def check_calendar_permission(request: Request, user): ) +async def _user_has_automations(request: Request, user) -> bool: + """Check if automations feature is available to this user.""" + if not getattr(request.app.state.config, 'ENABLE_AUTOMATIONS', False): + return False + if user.role == 'admin': + return True + return await has_permission( + user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS + ) + + async def _check_calendar_access(calendar_id: str, user: UserModel, permission: str = 'write') -> CalendarModel: """Verify user has access to a calendar. Returns the calendar or raises 403/404.""" cal = await Calendars.get_calendar_by_id(calendar_id) @@ -74,9 +87,26 @@ async def _check_calendar_access(calendar_id: str, user: UserModel, permission: @router.get('/', response_model=list[CalendarModel]) async def get_calendars(request: Request, user: UserModel = Depends(get_verified_user)): - """List user's calendars (owned + shared). Auto-creates defaults on first call.""" + """List user's calendars (owned + shared), plus a virtual Scheduled Tasks calendar + when automations are available.""" await check_calendar_permission(request, user) - return await Calendars.get_calendars_by_user(user.id) + calendars = await Calendars.get_calendars_by_user(user.id) + + if await _user_has_automations(request, user): + now = int(time.time_ns()) + calendars.append( + CalendarModel( + id=SCHEDULED_TASKS_CALENDAR_ID, + user_id=user.id, + name='Scheduled Tasks', + color='#8b5cf6', + is_default=False, + created_at=now, + updated_at=now, + ) + ) + + return calendars @router.post('/create', response_model=CalendarModel) @@ -144,11 +174,12 @@ async def get_events( expanded.append(event) # 2. Virtual automation events (Scheduled Tasks calendar) - try: - from open_webui.models.automations import Automations, AutomationRuns + if await _user_has_automations(request, user) and ( + cal_id_list is None or SCHEDULED_TASKS_CALENDAR_ID in cal_id_list + ): + try: + from open_webui.models.automations import Automations, AutomationRuns - scheduled_cal = await Calendars.get_scheduled_tasks_calendar(user.id) - if scheduled_cal and (cal_id_list is None or scheduled_cal.id in cal_id_list): # Future runs: expand RRULEs for active automations only active_automations = await Automations.get_active_by_user(user.id) for auto in active_automations: @@ -158,7 +189,7 @@ async def get_events( virtual = { 'id': f'auto_{auto.id}', - 'calendar_id': scheduled_cal.id, + 'calendar_id': SCHEDULED_TASKS_CALENDAR_ID, 'user_id': user.id, 'title': auto.name, 'description': auto.data.get('prompt', '') if auto.data else '', @@ -190,7 +221,7 @@ async def get_events( expanded.append( CalendarEventUserResponse( id=f'run_{run.id}', - calendar_id=scheduled_cal.id, + calendar_id=SCHEDULED_TASKS_CALENDAR_ID, user_id=user.id, title=auto.name, description=run.error if run.status == 'error' else '', @@ -213,8 +244,8 @@ async def get_events( user=None, ) ) - except Exception as e: - log.warning(f'Failed to compute automation events: {e}', exc_info=True) + except Exception as e: + log.warning(f'Failed to compute automation events: {e}', exc_info=True) return [e.model_dump() if hasattr(e, 'model_dump') else e for e in expanded] diff --git a/src/lib/components/calendar/CalendarEventModal.svelte b/src/lib/components/calendar/CalendarEventModal.svelte index ad7bf9b0df..bba3b3426b 100644 --- a/src/lib/components/calendar/CalendarEventModal.svelte +++ b/src/lib/components/calendar/CalendarEventModal.svelte @@ -184,7 +184,7 @@ class="w-full text-sm bg-transparent outline-hidden cursor-pointer" bind:value={calendarId} > - {#each calendars.filter((c) => c.name !== 'Scheduled Tasks') as cal (cal.id)} + {#each calendars.filter((c) => c.id !== '__scheduled_tasks__') as cal (cal.id)} {/each} From 4e31fa4427037c0ffd4ad704308203639bf05df8 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 20 Apr 2026 00:12:53 +0900 Subject: [PATCH 312/404] refac --- .../calendar/CalendarSidebar.svelte | 2 +- .../components/calendar/CalendarView.svelte | 164 ---------------- src/routes/(app)/calendar/+page.svelte | 180 ++++++++++++++++-- 3 files changed, 170 insertions(+), 176 deletions(-) diff --git a/src/lib/components/calendar/CalendarSidebar.svelte b/src/lib/components/calendar/CalendarSidebar.svelte index 8ed0df4727..dc98df05e0 100644 --- a/src/lib/components/calendar/CalendarSidebar.svelte +++ b/src/lib/components/calendar/CalendarSidebar.svelte @@ -71,7 +71,7 @@
-
+
{miniMonthNames[miniMonth]} {miniYear}
- -
- {/if} - -
-
- {headerText} - - -
- -
- - - - - -
-
-
- - {#if view === 'month'}
diff --git a/src/routes/(app)/calendar/+page.svelte b/src/routes/(app)/calendar/+page.svelte index 6e7296efb3..2267c1c799 100644 --- a/src/routes/(app)/calendar/+page.svelte +++ b/src/routes/(app)/calendar/+page.svelte @@ -14,6 +14,11 @@ import CalendarEventModal from '$lib/components/calendar/CalendarEventModal.svelte'; import Spinner from '$lib/components/common/Spinner.svelte'; import Plus from '$lib/components/icons/Plus.svelte'; + import Tooltip from '$lib/components/common/Tooltip.svelte'; + import SidebarIcon from '$lib/components/icons/Sidebar.svelte'; + import Select from '$lib/components/common/Select.svelte'; + import Check from '$lib/components/icons/Check.svelte'; + import ChevronDown from '$lib/components/icons/ChevronDown.svelte'; const i18n = getContext('i18n'); @@ -29,6 +34,22 @@ let editEvent: CalendarEventModel | null = null; let defaultStartAt: number | null = null; + const MONTH_NAMES = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December' + ]; + const DAY_NAMES = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; + function getVisibleRange(): { start: string; end: string } { const d = new Date(currentDate); let start: Date; @@ -128,8 +149,29 @@ showEventModal = true; } + function navigateCalendar(delta: number) { + const d = new Date(currentDate); + if (view === 'month') { + d.setDate(1); + d.setMonth(d.getMonth() + delta); + } else if (view === 'week') d.setDate(d.getDate() + delta * 7); + else d.setDate(d.getDate() + delta); + currentDate = d; + handleNavigate(); + } + + function goToToday() { + currentDate = new Date(); + handleNavigate(); + } + $: defaultCalendarId = calendars.find((c) => c.is_default)?.id || calendars[0]?.id || ''; + $: headerText = + view === 'day' + ? `${DAY_NAMES[currentDate.getDay()]}, ${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getDate()}, ${currentDate.getFullYear()}` + : `${MONTH_NAMES[currentDate.getMonth()]} ${currentDate.getFullYear()}`; + onMount(async () => { await loadCalendars(); await refresh(); @@ -157,17 +199,134 @@ : ''} max-w-full" > {#if loaded} + + +
- From e88e565ab46ed85a7bc95d45ca1057b2951810ed Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 13:18:54 +0900 Subject: [PATCH 331/404] refac --- backend/open_webui/utils/misc.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index 441f26a918..670a94b512 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -148,22 +148,19 @@ def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]: messages = [] pending_tool_calls = [] pending_content = [] - pending_reasoning = '' def flush_pending(): - nonlocal pending_content, pending_tool_calls, pending_reasoning - if pending_content or pending_tool_calls or pending_reasoning: + nonlocal pending_content, pending_tool_calls + if pending_content or pending_tool_calls: messages.append( { 'role': 'assistant', 'content': '\n'.join(pending_content) if pending_content else '', **({'tool_calls': pending_tool_calls} if pending_tool_calls else {}), - **({'reasoning_content': pending_reasoning} if pending_reasoning else {}), } ) pending_content = [] pending_tool_calls = [] - pending_reasoning = '' for item in output: item_type = item.get('type', '') @@ -248,10 +245,12 @@ def convert_output_to_messages(output: list, raw: bool = False) -> list[dict]: start_tag = item.get('start_tag', '') end_tag = item.get('end_tag', '') pending_content.append(f'{start_tag}{reasoning_text}{end_tag}') - # Preserve raw reasoning text as reasoning_content for - # providers that require it on assistant tool-call messages - # (e.g. Moonshot/Kimi K2.5). - pending_reasoning += reasoning_text + # NOTE: Some providers (e.g. Moonshot/Kimi K2.5) require + # reasoning_content as a top-level field on assistant + # messages. This should be handled externally via a + # pipeline filter or connection-level middleware, not + # here — adding it universally breaks strict providers + # (OpenAI, Vertex AI, Azure) that reject unknown fields. # else: skip reasoning blocks for normal LLM messages elif item_type == 'open_webui:code_interpreter': From 4790faba73b1fbc00a296529d4b1ced524247cc7 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Tue, 21 Apr 2026 00:21:48 -0400 Subject: [PATCH 332/404] fix(ui): add shift+click to bypass message deletion confirmation (#23888) --- src/lib/components/chat/Messages/ResponseMessage.svelte | 8 ++++++-- src/lib/components/chat/Messages/UserMessage.svelte | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 487c3a59ab..2d339c6f36 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -1381,8 +1381,12 @@ class="{isLastMessage || ($settings?.highContrastMode ?? false) ? 'visible' : 'invisible group-hover:visible'} p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg dark:hover:text-white hover:text-black transition" - on:click={() => { - showDeleteConfirm = true; + on:click={(e) => { + if (e.shiftKey) { + deleteMessageHandler(); + } else { + showDeleteConfirm = true; + } }} > { - showDeleteConfirm = true; + on:click={(e) => { + if (e.shiftKey) { + deleteMessageHandler(); + } else { + showDeleteConfirm = true; + } }} > Date: Tue, 21 Apr 2026 07:29:33 +0300 Subject: [PATCH 333/404] fix: always rAF-throttle markdown parsing during streaming (#23868) --- src/lib/components/chat/Messages/Markdown.svelte | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/lib/components/chat/Messages/Markdown.svelte b/src/lib/components/chat/Messages/Markdown.svelte index 50c50d5725..d0b54b6528 100644 --- a/src/lib/components/chat/Messages/Markdown.svelte +++ b/src/lib/components/chat/Messages/Markdown.svelte @@ -71,17 +71,11 @@ }; const updateHandler = (content) => { - if (content) { - if (done) { - cancelAnimationFrame(pendingUpdate); + if (content && !pendingUpdate) { + pendingUpdate = requestAnimationFrame(() => { pendingUpdate = null; parseTokens(); - } else if (!pendingUpdate) { - pendingUpdate = requestAnimationFrame(() => { - pendingUpdate = null; - parseTokens(); - }); - } + }); } }; From a2875f13c688c60b2f25f2d40e5026a14aa632d0 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 13:33:33 +0900 Subject: [PATCH 334/404] refac --- backend/open_webui/utils/middleware.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 036dc9bf39..0d1680eb93 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2459,6 +2459,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): tool_ids = form_data.pop('tool_ids', None) terminal_id = form_data.pop('terminal_id', None) files = form_data.pop('files', None) + form_data.pop('folder_id', None) # Caller-provided OpenAI-style tools take precedence over server-side # tool resolution (tool_ids, MCP servers, builtin tools). From 46d73c9dcd4ff7afd6c0efc98fd42f5f18cef555 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 13:46:39 +0900 Subject: [PATCH 335/404] refac --- backend/open_webui/routers/automations.py | 4 ++-- backend/open_webui/tools/builtin.py | 4 ++-- backend/open_webui/utils/automations.py | 21 ++++++++++++++++----- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/backend/open_webui/routers/automations.py b/backend/open_webui/routers/automations.py index ed33c4e8cb..4ff66feb97 100644 --- a/backend/open_webui/routers/automations.py +++ b/backend/open_webui/routers/automations.py @@ -163,7 +163,7 @@ async def create_new_automation( ): await check_automations_permission(request, user) try: - validate_rrule(form_data.data.rrule) + validate_rrule(form_data.data.rrule, tz=user.timezone) except ValueError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -213,7 +213,7 @@ async def update_automation_by_id( check_automation_access(automation, user) try: - validate_rrule(form_data.data.rrule) + validate_rrule(form_data.data.rrule, tz=user.timezone) except ValueError as e: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 9c1a91abc3..afa3cb63a9 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2575,7 +2575,7 @@ async def create_automation( # Validate the RRULE try: - validate_rrule(rrule) + validate_rrule(rrule, tz=user.timezone) except ValueError as e: return json.dumps({'error': f'Invalid schedule: {e}'}) @@ -2656,7 +2656,7 @@ async def update_automation( # Validate RRULE if changed if rrule is not None: try: - validate_rrule(new_rrule) + validate_rrule(new_rrule, tz=user.timezone if user else None) except ValueError as e: return json.dumps({'error': f'Invalid schedule: {e}'}) diff --git a/backend/open_webui/utils/automations.py b/backend/open_webui/utils/automations.py index 0c6e4e969a..984c8a0e4e 100644 --- a/backend/open_webui/utils/automations.py +++ b/backend/open_webui/utils/automations.py @@ -61,13 +61,19 @@ def _parse_rule(s: str): return rrulestr(s, ignoretz=True) -def validate_rrule(s: str) -> None: - """Raise ValueError if the RRULE is malformed or exhausted.""" +def validate_rrule(s: str, tz: str = None) -> None: + """Raise ValueError if the RRULE is malformed or exhausted. + + When *tz* is provided the "now" reference uses the user's local + clock so that near-future schedules are not incorrectly rejected + on servers whose system clock is ahead (e.g. UTC vs US timezones). + """ try: rule = _parse_rule(s) except Exception as e: raise ValueError(ERROR_MESSAGES.AUTOMATION_INVALID_RRULE(e)) - if rule.after(datetime.now()) is None: + now = datetime.now(ZoneInfo(tz)).replace(tzinfo=None) if tz else datetime.now() + if rule.after(now) is None: raise ValueError(ERROR_MESSAGES.AUTOMATION_NO_FUTURE_RUNS) @@ -83,10 +89,15 @@ def next_run_ns(s: str, tz: str = None) -> Optional[int]: def next_n_runs_ns(s: str, n: int = 5, tz: str = None) -> list[int]: - """Compute next N occurrences for UI preview.""" + """Compute next N occurrences for UI preview. + + Uses the user's timezone for the starting "now" so that the + preview matches the user's local clock (same as next_run_ns). + """ rule = _parse_rule(s) result = [] - dt = datetime.now() + now = datetime.now(ZoneInfo(tz)).replace(tzinfo=None) if tz else datetime.now() + dt = now for _ in range(n): dt = rule.after(dt) if not dt: From 65834432a38c483421d41da50ebe981166e59053 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 13:51:39 +0900 Subject: [PATCH 336/404] refac --- backend/open_webui/utils/automations.py | 33 +++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/backend/open_webui/utils/automations.py b/backend/open_webui/utils/automations.py index 984c8a0e4e..95b931e320 100644 --- a/backend/open_webui/utils/automations.py +++ b/backend/open_webui/utils/automations.py @@ -45,6 +45,22 @@ CALENDAR_ALERT_LOOKAHEAD_MINUTES = int(os.getenv('CALENDAR_ALERT_LOOKAHEAD_MINUT #################### +def _resolve_tz(tz: str = None) -> Optional[ZoneInfo]: + """Safely resolve a timezone string to ZoneInfo. + + Returns None (→ server-local fallback) when *tz* is empty, None, + or an unrecognised IANA key. Logs a warning on bad keys so + misconfiguration is visible in the server logs. + """ + if not tz: + return None + try: + return ZoneInfo(tz) + except (KeyError, Exception): + log.warning('Unknown timezone %r — falling back to server time', tz) + return None + + def _parse_rule(s: str): """Parse RRULE with clock-aligned DTSTART for sub-daily frequencies. @@ -72,19 +88,21 @@ def validate_rrule(s: str, tz: str = None) -> None: rule = _parse_rule(s) except Exception as e: raise ValueError(ERROR_MESSAGES.AUTOMATION_INVALID_RRULE(e)) - now = datetime.now(ZoneInfo(tz)).replace(tzinfo=None) if tz else datetime.now() + zi = _resolve_tz(tz) + now = datetime.now(zi).replace(tzinfo=None) if zi else datetime.now() if rule.after(now) is None: raise ValueError(ERROR_MESSAGES.AUTOMATION_NO_FUTURE_RUNS) def next_run_ns(s: str, tz: str = None) -> Optional[int]: """Next occurrence as epoch nanoseconds, respecting user timezone.""" - now = datetime.now(ZoneInfo(tz)) if tz else datetime.now() + zi = _resolve_tz(tz) + now = datetime.now(zi) if zi else datetime.now() dt = _parse_rule(s).after(now.replace(tzinfo=None)) if dt is None: return None - if tz: - dt = dt.replace(tzinfo=ZoneInfo(tz)) + if zi: + dt = dt.replace(tzinfo=zi) return int(dt.timestamp() * 1_000_000_000) @@ -94,16 +112,17 @@ def next_n_runs_ns(s: str, n: int = 5, tz: str = None) -> list[int]: Uses the user's timezone for the starting "now" so that the preview matches the user's local clock (same as next_run_ns). """ + zi = _resolve_tz(tz) rule = _parse_rule(s) result = [] - now = datetime.now(ZoneInfo(tz)).replace(tzinfo=None) if tz else datetime.now() + now = datetime.now(zi).replace(tzinfo=None) if zi else datetime.now() dt = now for _ in range(n): dt = rule.after(dt) if not dt: break - if tz: - dt_tz = dt.replace(tzinfo=ZoneInfo(tz)) + if zi: + dt_tz = dt.replace(tzinfo=zi) result.append(int(dt_tz.timestamp() * 1_000_000_000)) else: result.append(int(dt.timestamp() * 1_000_000_000)) From f485309fd69816dcd025af00717db2b9d422a7dc Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 13:57:43 +0900 Subject: [PATCH 337/404] refac --- src/app.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app.css b/src/app.css index ac02afcb1d..9352177bd8 100644 --- a/src/app.css +++ b/src/app.css @@ -260,10 +260,15 @@ select { display: none; } -/* Hide leaked Mermaid temp containers if render cleanup misses */ +/* Hide leaked Mermaid temp containers if render cleanup misses. + Use visibility:hidden (not display:none) so mermaid can still + measure the SVG layout before extracting its HTML. */ body > div[id^='dmermaid-'], body > iframe[id^='imermaid-'] { - display: none !important; + position: fixed !important; + visibility: hidden !important; + height: 0 !important; + overflow: hidden !important; } .scrollbar-hidden:active::-webkit-scrollbar-thumb, From a27916d1dbd9bc6890f35acb7228e1f2463a3409 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 14:31:04 +0900 Subject: [PATCH 338/404] refac --- backend/open_webui/functions.py | 17 +++++++++++++++-- backend/open_webui/utils/middleware.py | 23 +++++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/functions.py b/backend/open_webui/functions.py index 8bfc2c2b08..1e032759ea 100644 --- a/backend/open_webui/functions.py +++ b/backend/open_webui/functions.py @@ -234,11 +234,24 @@ async def generate_function_chat_completion(request, form_data, user, models: di oauth_token = None try: - if request.cookies.get('oauth_session_id', None): + oauth_session_id = request.cookies.get('oauth_session_id', None) + if oauth_session_id: oauth_token = await request.app.state.oauth_manager.get_oauth_token( user.id, - request.cookies.get('oauth_session_id', None), + oauth_session_id, ) + + # Fallback: no cookie (automation, API key, etc.) — use most recent session + if oauth_token is None: + from open_webui.models.oauth_sessions import OAuthSessions + + sessions = await OAuthSessions.get_sessions_by_user_id(user.id) + if sessions: + best = max(sessions, key=lambda s: s.updated_at) + oauth_token = await request.app.state.oauth_manager.get_oauth_token( + user.id, + best.id, + ) except Exception as e: log.error(f'Error getting OAuth token: {e}') diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 0d1680eb93..8d3b6dd267 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2916,13 +2916,32 @@ def build_response_object(response, response_data): async def get_system_oauth_token(request, user): + """Get the system OAuth token for a user. + + Primary path: use the oauth_session_id cookie (browser requests). + Fallback: look up the user's most recent OAuth session from the DB + (covers automations, API calls, and other cookie-less contexts). + """ oauth_token = None try: - if request.cookies.get('oauth_session_id', None): + oauth_session_id = request.cookies.get('oauth_session_id', None) + if oauth_session_id: oauth_token = await request.app.state.oauth_manager.get_oauth_token( user.id, - request.cookies.get('oauth_session_id', None), + oauth_session_id, ) + + # Fallback: no cookie (automation, API key, etc.) — use most recent session + if oauth_token is None: + from open_webui.models.oauth_sessions import OAuthSessions + + sessions = await OAuthSessions.get_sessions_by_user_id(user.id) + if sessions: + best = max(sessions, key=lambda s: s.updated_at) + oauth_token = await request.app.state.oauth_manager.get_oauth_token( + user.id, + best.id, + ) except Exception as e: log.error(f'Error getting OAuth token: {e}') return oauth_token From c4aac0415cf89b535edf1700473c50dc22f4fb64 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 14:58:28 +0900 Subject: [PATCH 339/404] refac --- backend/open_webui/internal/db.py | 120 +++++++++++++++++++++++++-- backend/open_webui/migrations/env.py | 5 ++ 2 files changed, 120 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index d1c4060cae..e3b4a110cd 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -1,8 +1,10 @@ import os import json import logging +import ssl as _stdlib_ssl from contextlib import asynccontextmanager, contextmanager from typing import Any, Optional +from urllib.parse import parse_qs, urlencode, urlparse, urlunparse from open_webui.internal.wrappers import register_connection from open_webui.env import ( @@ -35,6 +37,96 @@ from typing_extensions import Self log = logging.getLogger(__name__) +def extract_ssl_mode_from_url(url: str) -> tuple[str, str | None]: + """Strip SSL query-string parameters from a PostgreSQL URL. + + asyncpg and psycopg2 use different query-string keys for SSL + (``ssl`` vs ``sslmode``). This helper removes **both** from the + URL so that each driver can receive the correct parameter through + its own mechanism (query-string re-injection for psycopg2, + ``connect_args`` for asyncpg). + + Returns + ------- + (url_without_ssl, ssl_mode) + *url_without_ssl* is the original URL with ``ssl`` / ``sslmode`` + query parameters removed. *ssl_mode* is the extracted mode + string (e.g. ``'require'``), or ``None`` if neither parameter + was present. + + Non-PostgreSQL URLs are returned unchanged with ``ssl_mode=None``. + """ + if not url or not any( + url.startswith(prefix) + for prefix in ('postgresql://', 'postgresql+', 'postgres://') + ): + return url, None + + parsed = urlparse(url) + query_params = parse_qs(parsed.query, keep_blank_values=True) + + # Prefer sslmode (libpq canonical) over the asyncpg-only ssl key. + ssl_mode: str | None = None + for key in ('sslmode', 'ssl'): + values = query_params.pop(key, None) + if values and ssl_mode is None: + ssl_mode = values[0] + + if ssl_mode is None: + # Nothing to strip — return the URL untouched. + return url, None + + # Rebuild the query string without the SSL keys. + remaining_query = urlencode(query_params, doseq=True) + url_without_ssl = urlunparse(parsed._replace(query=remaining_query)) + return url_without_ssl, ssl_mode + + +def build_asyncpg_ssl_args(ssl_mode: str | None) -> dict: + """Convert a libpq-style SSL mode value to asyncpg ``connect_args``. + + Returns a dict suitable for unpacking into + ``create_async_engine(..., connect_args=...)``. + """ + if ssl_mode is None: + return {} + + mode = ssl_mode.lower() + if mode == 'disable': + return {'connect_args': {'ssl': False}} + if mode in ('allow', 'prefer'): + # asyncpg has no direct equivalent — omit to let it try without. + return {} + if mode == 'require': + # SSL required but no certificate verification (matches libpq). + ctx = _stdlib_ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = _stdlib_ssl.CERT_NONE + return {'connect_args': {'ssl': ctx}} + if mode in ('verify-ca', 'verify-full'): + # Full verification — use the system trust store. + ctx = _stdlib_ssl.create_default_context() + if mode == 'verify-ca': + ctx.check_hostname = False + return {'connect_args': {'ssl': ctx}} + + # Unknown value — pass through as-is and let asyncpg decide. + return {'connect_args': {'ssl': ssl_mode}} + + +def reattach_ssl_mode_to_url(url_without_ssl: str, ssl_mode: str | None) -> str: + """Re-append ``sslmode=`` to a cleaned PostgreSQL URL. + + Used for psycopg2 / libpq consumers that expect the canonical + ``sslmode`` query-string key. + """ + if ssl_mode is None: + return url_without_ssl + separator = '&' if '?' in url_without_ssl else '?' + return f'{url_without_ssl}{separator}sslmode={ssl_mode}' + + + class JSONField(types.TypeDecorator): impl = types.Text cache_ok = True @@ -60,10 +152,14 @@ class JSONField(types.TypeDecorator): # Workaround to handle the peewee migration # This is required to ensure the peewee migration is handled before the alembic migration def handle_peewee_migration(DATABASE_URL): - # db = None + db = None try: + # Normalize SSL params so psycopg2 always sees `sslmode=` (never `ssl=`). + url_without_ssl, ssl_mode = extract_ssl_mode_from_url(DATABASE_URL) + normalized_url = reattach_ssl_mode_to_url(url_without_ssl, ssl_mode) + # Replace the postgresql:// with postgres:// to handle the peewee migration - db = register_connection(DATABASE_URL.replace('postgresql://', 'postgres://')) + db = register_connection(normalized_url.replace('postgresql://', 'postgres://')) migrate_dir = OPEN_WEBUI_DIR / 'internal' / 'migrations' router = Router(db, logger=log, migrate_dir=migrate_dir) router.run() @@ -79,14 +175,20 @@ def handle_peewee_migration(DATABASE_URL): db.close() # Assert if db connection has been closed - assert db.is_closed(), 'Database connection is still open.' + if db is not None: + assert db.is_closed(), 'Database connection is still open.' if ENABLE_DB_MIGRATIONS: handle_peewee_migration(DATABASE_URL) -SQLALCHEMY_DATABASE_URL = DATABASE_URL +# Normalize SSL params from the URL once; each engine branch re-injects +# the driver-appropriate form. +DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE = extract_ssl_mode_from_url(DATABASE_URL) + +# For psycopg2 (sync engine), re-append sslmode=. +SQLALCHEMY_DATABASE_URL = reattach_ssl_mode_to_url(DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE) if DATABASE_SSL_MODE else DATABASE_URL def _make_async_url(url: str) -> str: @@ -229,7 +331,8 @@ get_db = contextmanager(get_session) # ASYNC ENGINE (used for ALL runtime database operations) # ============================================================ -ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url(SQLALCHEMY_DATABASE_URL) +# Use the SSL-stripped URL for asyncpg — SSL is injected via connect_args. +ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url(DATABASE_URL_WITHOUT_SSL if DATABASE_SSL_MODE else SQLALCHEMY_DATABASE_URL) if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: # Generous default — async coroutines + no session sharing = high connection demand. @@ -251,6 +354,10 @@ if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: def _set_sqlite_pragmas(dbapi_connection, connection_record): _apply_sqlite_pragmas(dbapi_connection) else: + # Inject asyncpg-compatible SSL connect_args when the user specified + # sslmode/ssl in DATABASE_URL. + asyncpg_ssl_args = build_asyncpg_ssl_args(DATABASE_SSL_MODE) + if isinstance(DATABASE_POOL_SIZE, int): if DATABASE_POOL_SIZE > 0: async_engine = create_async_engine( @@ -260,17 +367,20 @@ else: pool_timeout=DATABASE_POOL_TIMEOUT, pool_recycle=DATABASE_POOL_RECYCLE, pool_pre_ping=True, + **asyncpg_ssl_args, ) else: async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, poolclass=NullPool, + **asyncpg_ssl_args, ) else: async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, + **asyncpg_ssl_args, ) diff --git a/backend/open_webui/migrations/env.py b/backend/open_webui/migrations/env.py index 3840cb4a17..f5e57920ea 100644 --- a/backend/open_webui/migrations/env.py +++ b/backend/open_webui/migrations/env.py @@ -5,6 +5,7 @@ from alembic import context from open_webui.models.auths import Auth from open_webui.models.calendar import Calendar, CalendarEvent, CalendarEventAttendee # noqa: F401 from open_webui.env import DATABASE_URL, DATABASE_PASSWORD, LOG_FORMAT +from open_webui.internal.db import extract_ssl_mode_from_url, reattach_ssl_mode_to_url from sqlalchemy import engine_from_config, pool, create_engine # this is the Alembic Config object, which provides @@ -36,6 +37,10 @@ target_metadata = Auth.metadata DB_URL = DATABASE_URL +# Normalize SSL query params for psycopg2 (Alembic uses psycopg2, not asyncpg). +url_without_ssl, ssl_mode = extract_ssl_mode_from_url(DB_URL) +DB_URL = reattach_ssl_mode_to_url(url_without_ssl, ssl_mode) if ssl_mode else DB_URL + if DB_URL: config.set_main_option('sqlalchemy.url', DB_URL.replace('%', '%%')) From 7fd94b0e73b87fcbd5f8f37898bf617c762a6ace Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 15:15:00 +0900 Subject: [PATCH 340/404] refac --- src/lib/components/chat/MessageInput.svelte | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 92de0c3d43..aeb96af5b0 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1941,7 +1941,8 @@ {#if !history?.currentId || history.messages[history.currentId]?.done == true} - {#if terminalCapableModels.length > 0 && (($terminalServers ?? []).length > 0 || ($settings?.terminalServers ?? []).some((s) => s.url))} + {@const hasDirectToolServerAccess = $_user?.role === 'admin' || ($_user?.permissions?.features?.direct_tool_servers ?? true)} + {#if terminalCapableModels.length > 0 && (($terminalServers ?? []).some((t) => t.id) || (hasDirectToolServerAccess && (($terminalServers ?? []).some((t) => !t.id) || ($settings?.terminalServers ?? []).some((s) => s.url))))} {/if} From 0e3135f8dc203f94f5fe30e94039a7977b2b2059 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 21 Apr 2026 08:18:33 +0200 Subject: [PATCH 341/404] chore: changelog (#23187) * chore: add changelog entry for v0.8.13 * changelog: task management, admin model deletion * changelog: emoji, shortcode, input * changelog: swipe-to-reply mobile gesture * changelog: emoji, recently-used, picker * changelog: files, chat-input, attachments * changelog: terminal session tracking, task list visibility * changelog: move terminal session tracking to Added section * changelog: performance, shared chat deletion * changelog: user activity tracking, shared chat deletion optimizations * changelog: add Russian translation entry * changelog: MCP tool server timeout configuration * changelog: image viewer memory optimization * changelog: error message persistence during streaming * changelog: codespan, animation, streaming * changelog: streaming, performance, yield * changelog: text, animation, streaming * changelog: websearch, settings, fix * changelog: automation, scheduling, workflows * changelog: automations, permissions, access * changelog: automations, editor, logs * changelog: german, completion, tokens * changelog: streaming, entities, defaults * changelog: pyodide, cache, prompt * changelog: details, expansion, settings * changelog: unread, sidebar, automations * changelog: oauth, gravatar, prompts * changelog: wake-lock, writing, retrieval * changelog: mcp, sidebar, usage * changelog: oauth, citations, sidebar * changelog: oauth, cookies, tools * changelog: translations, tamil, localization * changelog: tasks, fallback, stability * changelog: title, query, performance * changelog: sidebar, archived, menu * changelog: input, drafts, uploads * changelog: notes, permissions, security * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog date * reorder changelog entries * restore changelog ordering * restore changelog * changelog updates * adjust changelog ordering * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * Update CHANGELOG.md * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * Update CHANGELOG.md * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog * changelog --- CHANGELOG.md | 235 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 126b19e028..47f6a27199 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,241 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.0] - 2026-04-20 + +### Added + +- 🖥️ **Native desktop app availability.** Open WebUI is now available as a cross-platform desktop app with local model support, multi-server switching, and offline-ready usage after first launch. [#8262](https://github.com/open-webui/open-webui/issues/8262), [Desktop](https://github.com/open-webui/desktop) +- 🤖 **Scheduled chat automations.** Users can now create, schedule, run, and manage recurring automations from both the dedicated automations page and built-in chat tools, with execution logs, direct run controls, and permission-aware access control for user and group policies. [#23303](https://github.com/open-webui/open-webui/pull/23303), [Commit](https://github.com/open-webui/open-webui/commit/5a2ff8b2e5b6f55a20f7ed491f818490eb535ea7), [Commit](https://github.com/open-webui/open-webui/commit/d30a0531d4add045c21a2368d6321a9b1906865f), [Commit](https://github.com/open-webui/open-webui/commit/bae5ff938ac88a3a647cc31ca8db1101015ae18b), [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) +- 🧰 **Automation tools in chat.** Built-in chat tools can now create, update, list, pause, and delete scheduled automations directly in conversation when automation access is enabled. [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) +- 🤖 **Automation model selection reliability.** Automations created from chat now consistently use the calling model, avoiding mismatches when tool calls run under different model contexts. [Commit](https://github.com/open-webui/open-webui/commit/e709d6812f7fba246c4b7907f9fa41f751717566), [Commit](https://github.com/open-webui/open-webui/commit/398718d5059ce2a5614e9e124f20ef48b843ce42), [#23812](https://github.com/open-webui/open-webui/pull/23812) +- ⏱️ **Automation scheduling limits.** Administrators can now set "AUTOMATION_MAX_COUNT" and "AUTOMATION_MIN_INTERVAL" to limit how many automations each non-admin user can create and prevent overly frequent schedules that could overload the system. [Commit](https://github.com/open-webui/open-webui/commit/406251c2f358ffabce4d631c98c6f2c879feae5c) +- 🧭 **Global automations toggle.** Administrators can now disable automations system-wide with the "ENABLE_AUTOMATIONS" setting, which hides automation pages and tools and pauses background automation processing until it is re-enabled. [Commit](https://github.com/open-webui/open-webui/commit/42694c7c0cc8ba586c1dd364ecfaa0b4080b6cad) +- 📋 **Task management tool.** AI models can now create, update, and track tasks within a chat conversation, breaking down complex requests into manageable steps with real-time status updates. [Commit](https://github.com/open-webui/open-webui/commit/bcb71bb5206ac01d97a39fde8ecf0e0541dde636) +- 🗓️ **Calendar workspace and event management.** Users can now manage personal and shared calendars from a dedicated Calendar page, create and edit events (including recurring events), and view scheduled automations directly alongside calendar activity. [#23880](https://github.com/open-webui/open-webui/pull/23880) +- 🔐 **Calendar permission controls.** Administrators can now control calendar access through feature permissions, so calendar pages, APIs, and built-in calendar tools are available only to users and groups with calendar access enabled. [Commit](https://github.com/open-webui/open-webui/commit/5afc258c5b13f456be528420513ade546c5e86f9), [Commit](https://github.com/open-webui/open-webui/commit/37eba1c5a66b3145c122a6b40e5c29707526d121) +- 🗑️ **Calendar deletion controls.** Calendar sidebar entries now include a delete action with confirmation, allowing users to remove custom calendars directly from the Calendar page. [Commit](https://github.com/open-webui/open-webui/commit/51627555bf356c8ec663f4d2f43f2f013eadbce4) +- 🔔 **Calendar reminders and alerts.** Calendar events now support reminder options from no alert up to one hour before start time, with upcoming alerts delivered through in-app toasts, browser notifications, and optional webhooks while avoiding duplicate sends. [Commit](https://github.com/open-webui/open-webui/commit/e5b5a174265d6710e986f6534ee7e3b2923233be) +- ⚙️ **Scheduler reminder configuration.** Administrators can now configure calendar reminder processing with "SCHEDULER_POLL_INTERVAL" and "CALENDAR_ALERT_LOOKAHEAD_MINUTES", while existing "AUTOMATION_POLL_INTERVAL" setups continue to work as a legacy fallback. [Commit](https://github.com/open-webui/open-webui/commit/e5b5a174265d6710e986f6534ee7e3b2923233be) +- 🗓️ **Unified calendar header controls.** The Calendar page now uses a single top navigation bar for date navigation, view selection, and quick event creation, with improved mobile behavior and label truncation for tighter screens. [Commit](https://github.com/open-webui/open-webui/commit/4e31fa4427037c0ffd4ad704308203639bf05df8), [Commit](https://github.com/open-webui/open-webui/commit/3e3f138d9323987a41b1e3c17721a0047cf8e40f) +- 🧰 **Dedicated task checklist tools.** Built-in task tracking exposes separate tools for creating task lists and updating individual task statuses, giving multi-step chats clearer progress control. [Commit](https://github.com/open-webui/open-webui/commit/a35926261646f8897ba71da1572ed5dff802e3be) +- ☁️ **Azure responses support.** Azure OpenAI connections now support the newer "/openai/v1" format, enabling chat, responses, and proxy calls to work correctly with that endpoint style. [#23484](https://github.com/open-webui/open-webui/pull/23484) +- 🤖 **Ollama responses support.** The Ollama proxy now supports the Responses API, letting clients use "/v1/responses" directly with Ollama-hosted models through Open WebUI. [#23483](https://github.com/open-webui/open-webui/pull/23483) +- 🧩 **Responses tool output rendering.** Built-in tool outputs in Responses API flows now render more consistently so downstream chat output is easier to interpret. [Commit](https://github.com/open-webui/open-webui/commit/e695d854f2d11fada84d5fbec8d3edea4e468e19), [#23482](https://github.com/open-webui/open-webui/pull/23482) +- 🔎 **Responses citation visibility.** Responses API flows now emit citation sources more consistently, making linked references easier to preserve and display in chat output. [Commit](https://github.com/open-webui/open-webui/commit/e695d854f2d11fada84d5fbec8d3edea4e468e19), [#23774](https://github.com/open-webui/open-webui/issues/23774) +- 📎 **Attach previously uploaded files.** The chat input menu now includes a Files tab for browsing and attaching previously uploaded files, eliminating the need to re-upload files you have already shared. [Commit](https://github.com/open-webui/open-webui/commit/edb8971c7dbd974322c3207c4655ff66479c3ee2) +- 🖥️ **Terminal session tracking.** Open Terminal now tracks the current working directory per chat session, so relative paths and navigation work correctly across multiple interactions. [Commit](https://github.com/open-webui/open-webui/commit/a06685a47b89fb19dd6124fbe391ff78b54f451d), [Commit](https://github.com/open-webui/open-webui/commit/6512e085c4e56897dd49e56aff5d616820a962f3) +- 🧷 **Default model terminal selection.** Workspace model editors can now preselect an Open Terminal connection, so new chats automatically start with the model’s configured terminal ready to use. [Commit](https://github.com/open-webui/open-webui/commit/47d413ce7b2a006a8126f4a9055b13e5fcb33a1d), [#23605](https://github.com/open-webui/open-webui/issues/23605) +- 🎙️ **Mistral TTS support.** Mistral can now be used as a text-to-speech provider, with admin settings for the API key, base URL, voices, and model selection. [Commit](https://github.com/open-webui/open-webui/commit/4cee67e2be0c80a0b501073ea49a80d13efd1c41) +- 🎧 **STT preprocessing bypass option.** Administrators can now enable "AUDIO_STT_SKIP_PREPROCESSING" to send audio files directly to the speech-to-text backend, reducing memory and CPU consumption during large uploads for better transcription performance and stability on constrained deployments. [#23661](https://github.com/open-webui/open-webui/pull/23661) +- 🗑️ **Admin model deletion.** Administrators can now delete Ollama models directly from the model selector menu, making it easier to clean up unused or unwanted models. [Commit](https://github.com/open-webui/open-webui/commit/2388dd7dc3530b5dd5419c5d0bb1bcdcb7544099) +- 🔌 **Backend outlet filters for local and persisted chats.** Pipeline and function outlet filters now run reliably in backend completion flows for persisted chats and temporary local chats. [#3237](https://github.com/open-webui/open-webui/issues/3237), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67) +- 🎨 **Emoji shortcode support.** Typing a colon in the chat input now opens an emoji suggestion menu, making it easier to insert emojis using shortcodes like :wave:. [Commit](https://github.com/open-webui/open-webui/commit/2040095050056d01c61aa597c5010445449a42c7) +- 📌 **Recently used emojis.** The emoji picker now shows your most recently used emojis at the top, making it faster to find emojis you use often. [Commit](https://github.com/open-webui/open-webui/commit/64da99a32218171d41b3af5acc14783de8dbdf49) +- 👆 **Swipe to reply on mobile.** Swiping right on a message now triggers a reply, making it easier to respond on touch devices with a natural gesture. [Commit](https://github.com/open-webui/open-webui/commit/012ce95f27d57bea8911bd63bfb923443c5797ae) +- 📱 **Screen-awake voice recording.** Voice recording now keeps the screen awake during active dictation and safely re-acquires wake lock after visibility changes, helping prevent long transcriptions from being cut off on mobile devices. [#23145](https://github.com/open-webui/open-webui/issues/23145) +- ✨ **Improved task list visibility.** The task list automatically hides once all tasks are complete and generation is finished, keeping the chat interface cleaner. [Commit](https://github.com/open-webui/open-webui/commit/0ad397c0482004173d4a8bf4722100acc43db454), [Commit](https://github.com/open-webui/open-webui/commit/4b35d70078a2d7a322566699a43594b3c10b2dda) +- 🔔 **Unread chat indicators.** Sidebar chats now show unread status and are marked as read when opened, making it easier to spot conversations with new activity. [Commit](https://github.com/open-webui/open-webui/commit/0638b9f56ce1ba8a496d0e84da2e7fa178b01a3f) +- 🔌 **WebSocket reconnect status feedback.** Open WebUI now warns when the real-time connection drops and confirms when it reconnects, while avoiding a reconnect message on the initial page load. [Commit](https://github.com/open-webui/open-webui/commit/1824e69a70e756cfcf543a9fbe4b0780d9b57292) +- 📍 **Pinned notes in sidebar.** Notes can now be pinned to the sidebar for quick access, and you can also create a new note directly from the pinned notes section. [Commit](https://github.com/open-webui/open-webui/commit/ecd74f220c7dd671d5705189a3f4493a3868c8bf), [Commit](https://github.com/open-webui/open-webui/commit/f1be85d997439b49fc143d2bcd2dc710f44446c8) +- 🗂️ **Model selector focus.** The model selector now resets its search only when it opens, making the popup feel more predictable while still focusing the search field automatically. [Commit](https://github.com/open-webui/open-webui/commit/b89019a8e1f96e01dc8e19a81ef8fb4f4eae3eef) +- 🗂️ **Model selector layout.** The model selector now behaves more predictably as a custom popup, and the completions playground uses a simpler model picker for easier selection. [Commit](https://github.com/open-webui/open-webui/commit/c40ea7f29d34fa9535cdf9ffe599f4429ff3f455) +- 🎚️ **Active filter valve shortcut.** Active filter badges now expose valve configuration directly in the chat input area, so filter tuning is faster during conversations. [Commit](https://github.com/open-webui/open-webui/commit/3c22afc5a67404047797921185aca984b10b45cd), [#23811](https://github.com/open-webui/open-webui/issues/23811), [#23813](https://github.com/open-webui/open-webui/pull/23813) +- 🎨 **Theme updates.** Other windows can now update the app theme directly, keeping the interface in sync when theme changes are triggered externally. [Commit](https://github.com/open-webui/open-webui/commit/9f1b279e88bd22dfff4d2531209536dea6a2f65e) +- 🚀 **Async performance and responsiveness improvements.** The core backend database and request paths now run asynchronously across the application, massively improving responsiveness and performance under concurrent load and reducing request blocking during heavy activity. [Commit](https://github.com/open-webui/open-webui/commit/27169124f220e5cea21c88601c731c3749496ab0), [Commit](https://github.com/open-webui/open-webui/commit/8936721414a17832852a90f3ee592af5a8b7232d) +- ⚡ **Drawer performance and memory optimization.** Drawer interactions now stay smoother over long sessions by removing stale keyboard listeners on teardown, which reduces memory growth and avoids accumulated event handling overhead. [#23724](https://github.com/open-webui/open-webui/pull/23724#issuecomment-4245840810) +- 🚀 **Chat history memory culling.** Long conversations now stay much more responsive by rendering a smaller message window and unloading off-screen messages with spacer-based virtualization, significantly reducing memory pressure and UI freezing on heavy chats and mobile devices. [#23067](https://github.com/open-webui/open-webui/issues/23067), [Commit](https://github.com/open-webui/open-webui/commit/026903399be73ac4b6c226647110e5662d043a50), [Commit](https://github.com/open-webui/open-webui/commit/9dccd29c94875e6f0ac373c5802cb183296e47ff) +- 🧵 **Async file and knowledge processing performance.** File processing, knowledge reindexing, and channel message helper paths now consistently await async operations, preventing skipped processing steps and improving reliability and performance of indexing and tool responses. [Commit](https://github.com/open-webui/open-webui/commit/de27a121511a31606f250ba4033490797216a0eb) +- 🚀 **Persistent chat payload efficiency.** Persisted chats now use server-side history loading instead of repeatedly resending full message payloads, improving multimodal performance and reducing stale-history overwrite risk across devices. [#19064](https://github.com/open-webui/open-webui/issues/19064), [Commit](https://github.com/open-webui/open-webui/commit/18fe17127a7175579506e7456d3e5aba201371e6), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67) +- 🧵 **Non-blocking file storage operations.** Uploading, reading, transcribing, and deleting files now offloads storage I/O to background threads, keeping the application responsive during file-heavy workflows. [Commit](https://github.com/open-webui/open-webui/commit/4866bec0f238198a721c952fe18dd04ba643be33) +- 🏃 **Faster automation list loading.** The automations page now loads more smoothly by batching latest-run lookups and avoiding duplicate initial fetches. [Commit](https://github.com/open-webui/open-webui/commit/09f6d7ba57d2aaad83ad0d29d005feb7157776a1) +- 🏎️ **Streaming response performance.** Streaming responses now process each output line in a single step instead of two separate yields, reducing async overhead and improving responsiveness during long-running generations. [#23266](https://github.com/open-webui/open-webui/pull/23266) +- 🔎 **Faster mention parsing.** Chat text with HTML-like content, file paths, or tool output now parses mentions more efficiently, which helps keep typing and rendering responsive in messages that contain many '<' characters. [#23551](https://github.com/open-webui/open-webui/pull/23551) +- 🧪 **Code block rendering performance.** Code blocks now reuse a shared HTML unescape helper, reducing extra browser work when displaying encoded output in chat. [#23553](https://github.com/open-webui/open-webui/pull/23553) +- 🚀 **Inline code rendering performance.** Inline code tokens in streaming responses now fade in with a lightweight CSS animation, making chat output feel smoother while reducing interface overhead during rapid token updates. [#23258](https://github.com/open-webui/open-webui/pull/23258) +- 🎞️ **Streaming text token animation performance.** Streaming text tokens now use a lightweight CSS intro animation, making output feel smoother while reducing transition overhead and preventing tokens from fading out when generation completes. [#23257](https://github.com/open-webui/open-webui/pull/23257) +- 🎯 **Template token scan optimization.** Streaming responses now skip unnecessary token-replacement processing when no template markers are present, reducing per-update overhead and keeping chat output smoother during rapid generation. [#23161](https://github.com/open-webui/open-webui/pull/23161) +- 🔬 **Chinese text processing guard performance.** Streaming responses without Chinese characters now skip unnecessary Chinese-format processing checks, reducing per-update overhead and keeping output smoother during rapid generation. [#23162](https://github.com/open-webui/open-webui/pull/23162) +- 🧠 **HTML entity decode performance.** Streaming text decoding now avoids repeated document parsing for HTML entity handling, reducing memory churn and improving responsiveness in token-heavy chat output. [#23165](https://github.com/open-webui/open-webui/pull/23165) +- 🏷️ **Chat title update performance.** Chat title updates now run in a single database operation instead of multiple round trips, improving responsiveness and reducing overhead when titles are generated or renamed. [#23214](https://github.com/open-webui/open-webui/pull/23214) +- 📂 **Faster chat list queries performance.** Chat and folder lists now load more efficiently by fetching only the fields needed for sidebar views, improving responsiveness when browsing large conversation histories. [Commit](https://github.com/open-webui/open-webui/commit/0e5696de74cc0ba55b24cfc3d02efa83f08d7d3f) +- 📈 **Sidebar memory optimization.** Sidebar chat items now use shared drag-preview resources and safer listener cleanup, reducing memory growth and keeping large chat lists more responsive during long sessions. [#23209](https://github.com/open-webui/open-webui/pull/23209) +- 🧠 **Image viewer memory optimization.** Viewing images and SVGs now uses significantly less memory and performs faster, keeping the application snappy and responsive even when browsing through many media files during extended sessions. [#23236](https://github.com/open-webui/open-webui/pull/23236) +- 📡 **Optimized user activity tracking performance.** User activity updates now use a single database query instead of multiple operations, improving response times across all authenticated requests. [#23215](https://github.com/open-webui/open-webui/pull/23215) +- 👥 **Faster channel thread author loading.** Channel thread responses now load author details in a single batch query, reducing database overhead and improving responsiveness in threads with many participants. [#23795](https://github.com/open-webui/open-webui/pull/23795) +- 💨 **Optimized shared chat deletion.** Deleting shared chats by user is now faster and more memory-efficient by only loading necessary data. [#23216](https://github.com/open-webui/open-webui/pull/23216) +- 🗃️ **Faster chat tag loading.** Chat tag lookups now load only the metadata needed instead of full chat payloads, improving responsiveness for chats with large histories. [#23798](https://github.com/open-webui/open-webui/pull/23798) +- 📎 **Faster chat file deduplication.** Attaching files to chat messages now checks duplicates more efficiently, reducing overhead when handling larger file lists. [#23800](https://github.com/open-webui/open-webui/pull/23800) +- 📈 **Faster message diff checks.** Chat message and status updates now compare content more efficiently during streaming, making active conversations feel smoother and more responsive. [#23370](https://github.com/open-webui/open-webui/pull/23370) +- ⚖️ **Faster deep equality checks.** Chat message updates, model selection, note editing, code block refreshes, and rich text state comparisons now use deep equality checks that reduce unnecessary UI work and improve responsiveness in active sessions. [#23845](https://github.com/open-webui/open-webui/pull/23845) +- 🏃 **Faster knowledge access updates.** Updating access grants for knowledge items now completes with less backend overhead, making permission changes apply more quickly. [#23799](https://github.com/open-webui/open-webui/pull/23799) +- 🧹 **Mermaid render cleanup performance.** Mermaid diagrams now always clean up temporary render elements after failures, reducing DOM buildup and keeping repeated rendering more stable over time. [#23727](https://github.com/open-webui/open-webui/pull/23727) +- 🖼️ **Model image lookup efficiency.** Model profile image requests now reuse the current request database session, reducing per-request overhead and improving response efficiency. [#23796](https://github.com/open-webui/open-webui/pull/23796) +- 👤 **User endpoint query reduction.** Session-based user settings and status endpoints now avoid redundant user re-fetches, reducing unnecessary database load while preserving behavior. [#23794](https://github.com/open-webui/open-webui/pull/23794) +- 🚦 **Faster startup performance.** Open WebUI now checks for Torch MPS support only on macOS, avoiding unnecessary startup work on other platforms. [#23438](https://github.com/open-webui/open-webui/pull/23438) +- 🛡️ **Redis timeout consistency.** Redis connections now honor the "REDIS_SOCKET_CONNECT_TIMEOUT" setting across standard and cluster setups, helping workers fail faster when Redis is unreachable. [#23572](https://github.com/open-webui/open-webui/pull/23572) +- 🧰 **AIOHTTP pool controls.** Administrators can now tune shared outbound HTTP connection behavior with "AIOHTTP_POOL_CONNECTIONS", "AIOHTTP_POOL_CONNECTIONS_PER_HOST", and "AIOHTTP_POOL_DNS_TTL" for better control under high concurrency. [Commit](https://github.com/open-webui/open-webui/commit/c47dd7b7717c4186e0f0549ca3c8cb4d9bb38135) +- ⏱️ **MCP tool server timeout configuration.** Administrators can now configure request timeouts for MCP tool server connections via the AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER environment variable. [Commit](https://github.com/open-webui/open-webui/commit/10b4b86ada93cd62d994c3179ff14dfd1a6e56f0) +- 🎫 **Static OAuth tool authentication.** Tool server authentication now works reliably for both "oauth_2.1" and "oauth_2.1_static" connection types, so OAuth-backed tool access is correctly detected and forwarded during chat requests. [Commit](https://github.com/open-webui/open-webui/commit/60676bfdcfbce1a69b3e97f2013f0cfd63371737) +- 🗄️ **Configurable storage local cache.** Administrators can now disable persistent local caching for cloud-backed uploads with the "STORAGE_LOCAL_CACHE" setting, reducing local disk usage by cleaning temporary upload copies after processing. [Commit](https://github.com/open-webui/open-webui/commit/8172c7e3d56918d1372be06b9369b58a3a88f6b1) +- 🚪 **Back-channel logout.** OpenID Connect providers can now trigger centralized logout through the "ENABLE_OAUTH_BACKCHANNEL_LOGOUT" setting, helping administrators invalidate user sessions more reliably across connected devices. [Commit](https://github.com/open-webui/open-webui/commit/0dd9f462ffb2f160bc4aebad182047f41874d250) +- 🛡️ **Expanded security header controls.** Administrators can now configure additional browser security headers, including "CONTENT_SECURITY_POLICY_REPORT_ONLY", "CROSS_ORIGIN_EMBEDDER_POLICY", "CROSS_ORIGIN_OPENER_POLICY", and "CROSS_ORIGIN_RESOURCE_POLICY", for stricter and more flexible deployment hardening. [Commit](https://github.com/open-webui/open-webui/commit/f246a66810fa4995d9494da3599c0fb297fb0213) +- 🖼️ **Image MIME fallback option.** Administrators can now enable "ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK" so image-to-base64 conversion can still detect common image types by file extension when MIME metadata is missing, improving compatibility on minimal container images and older file records. [Commit](https://github.com/open-webui/open-webui/commit/5127354b3eb4eaa71bc4ad68da69729e2196e7a4) +- 🛡️ **Public sharing permissions.** Public channels, models, notes, prompts, and tools now respect allowed access grants more consistently, helping administrators control who can share content more safely. [Commit](https://github.com/open-webui/open-webui/commit/9d3e0637c86292b8b92e7607097a83f1075d7cd8) +- 🆔 **Skill lookup by ID.** Skill instructions now include each skill’s ID, and the skill viewer now finds skills by ID in a case-insensitive way so attached skills are identified more reliably in chats. [Commit](https://github.com/open-webui/open-webui/commit/65ee771fd0d62d785ecbcf189e3f5b63858c11e6) +- 🏷️ **Source context metadata.** Retrieval source context now includes each source’s resource type and resource ID metadata, helping downstream model workflows preserve richer source identity during processing. [Commit](https://github.com/open-webui/open-webui/commit/c3c8c605d76a3b0ee067307f9cef6d081658e287) +- 🗂️ **Feedback filtering.** Administrators can now filter feedback history by model and export only the feedback they need. [Commit](https://github.com/open-webui/open-webui/commit/60e4d7517463690b3a87de38babc9ac561897c61) +- 📤 **CSV feedback export.** Feedback history can now be exported as either JSON or CSV, making it easier to analyze feedback in spreadsheet tools. [Commit](https://github.com/open-webui/open-webui/commit/342582676a5212bf196a69d11825cb407992f257) +- 📝 **Optional GET audit logging.** Administrators can now enable auditing for GET requests with the "ENABLE_AUDIT_GET_REQUESTS" setting when they need fuller request visibility. [Commit](https://github.com/open-webui/open-webui/commit/5ee791d5d28f236755243cb7d16d8737bb69ce36) +- 🕒 **Model access updates.** Changing a model’s access grants now updates its timestamp, so recently modified models stay easier to find and sort correctly. [Commit](https://github.com/open-webui/open-webui/commit/53eadb7df7281f5661cbe22c8b26b5aedaba3083) +- 💬 **Queued message handling.** Queued chat messages now send more reliably without advancing the queue too early, keeping follow-up prompts in the intended order. [Commit](https://github.com/open-webui/open-webui/commit/730e52a431d157dc62d72260668087437f1d52f4) +- 🔒 **Rendered content safety.** Placeholder descriptions and the pending account notice now render markdown with safer sanitization ordering, reducing the risk of unsafe HTML appearing in these views. [Commit](https://github.com/open-webui/open-webui/commit/253f416de3f2d3a939a6feef2a56413fd61cc70b) +- 🛡️ **Safer placeholder rendering.** Chat placeholder descriptions and the pending account notice now sanitize rendered markdown more consistently, reducing the risk of unsafe content being shown in these views. [Commit](https://github.com/open-webui/open-webui/commit/ae0316a30e01a2e5ff3f9d2f9f759c1cd6410f34) +- 🧮 **Usage analytics accuracy.** Token usage is now normalized before chat messages are saved, so model and user usage reports stay accurate across OpenAI-compatible providers. [Commit](https://github.com/open-webui/open-webui/commit/4dea4fdf54e00ebaba8e3178128bf8709453d2a2) +- 🧩 **Richer Anthropic tool results.** Anthropic-compatible tool calls now preserve more tool result content types, including images and structured search or document outputs, so models can use fuller tool context instead of receiving only plain text fragments. [#23188](https://github.com/open-webui/open-webui/issues/23188), [Commit](https://github.com/open-webui/open-webui/commit/40f5b3d135190dc9a2d8e94dbb1b2cbcbd829132) +- 🖼️ **ComfyUI request reliability.** ComfyUI image generation and editing now use shared async connections with consistent SSL handling, making image uploads and workflow runs more reliable under concurrent load. [Commit](https://github.com/open-webui/open-webui/commit/5944eda0ff25a284f7157252683bccede741cbe7) +- 🎛️ **Reranking batch size control.** Administrators can now set "RAG_RERANKING_BATCH_SIZE" in Documents settings to control reranking workload size, helping balance retrieval speed and resource usage for their deployment. [Commit](https://github.com/open-webui/open-webui/commit/4d2f18981051205016bd24d39521e25a33581225) +- 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security. +- 🌐 **Translation updates.** Translations for Irish, Catalan, German, Simplified Chinese, Hindi, and Portuguese (Brazil) were enhanced and expanded. + +### Fixed + +- 🛡️ **Model description XSS protection.** Model descriptions shown in chat placeholders are now sanitized before rendering, preventing malicious links from executing scripts and helping protect user sessions from takeover. [#23621](https://github.com/open-webui/open-webui/pull/23621) +- 🧠 **Memory search filtering.** Memory search now correctly filters by the query text instead of returning unrelated results. [Commit](https://github.com/open-webui/open-webui/commit/43e5905c133049036353978704b0abd179716749), [#23826](https://github.com/open-webui/open-webui/issues/23826) +- 📊 **Shared chat analytics consistency.** Usage and message-count analytics now count assistant activity consistently across regular and shared chats, improving accuracy in model, user, chat, and time-based reporting views. [Commit](https://github.com/open-webui/open-webui/commit/e29d145a1cff23122de16123a4cfda1b84abffbb) +- 🧭 **Safer in-flight chat navigation.** Sending a message no longer overwrites your active chat or causes duplicate background notifications when you switch conversations before a response finishes. [Commit](https://github.com/open-webui/open-webui/commit/dc6df52a917b49fa1264ac81a8cc74603f6155b3) +- 🗣️ **Pipeline error detail visibility.** Pipeline inlet and outlet failures now preserve and surface provider error details more reliably in chat error messages, making troubleshooting failed requests much clearer. [Commit](https://github.com/open-webui/open-webui/commit/d5e69f182cd7a6371ab25248f6432b277f83ef23) +- 📨 **Shared chat event routing.** Message update and send events now target the chat owner’s event channel, so shared chats receive the correct real-time updates instead of routing events to the acting user. [Commit](https://github.com/open-webui/open-webui/commit/47329b5032ba29716a7e7e973b07c6d9894968e0) +- 🔐 **Consistent outbound SSL handling.** External requests for tools, functions, terminals, webhooks, retrieval loaders, audio provider discovery, and OpenAI-compatible embedding calls now consistently apply the configured SSL client setting, improving reliability for deployments that require custom certificate or verification behavior. [Commit](https://github.com/open-webui/open-webui/commit/fd25152076ea7c310e42c9bacc5cd2b544eeae48), [Commit](https://github.com/open-webui/open-webui/commit/56c5bc1d3487020ab886d3332aacc1644c1d6123) +- 🧭 **Scheduled Tasks calendar reliability.** Scheduled Tasks is now handled as a virtual automation calendar that appears only when automation access is available, and calendar selection now filters by stable ID instead of name so event forms behave consistently. [Commit](https://github.com/open-webui/open-webui/commit/1d501cfa3f96b3a9a5f4f7ce996947671fd09f29), [Commit](https://github.com/open-webui/open-webui/commit/24dd5b461eb44d306c823389e0f664c45db042e8) +- 🛡️ **Protected calendar deletion rules.** System and default calendars can no longer be deleted, preventing accidental removal of built-in calendar functionality. [Commit](https://github.com/open-webui/open-webui/commit/51627555bf356c8ec663f4d2f43f2f013eadbce4) +- 🖼️ **Image SSL setting support.** Image generation now respects the configured SSL session setting, preventing avoidable connection failures in strict certificate environments. [Commit](https://github.com/open-webui/open-webui/commit/128cf41fcedf2638fc8a6acd850d8b0409be1c4e), [#23777](https://github.com/open-webui/open-webui/issues/23777) +- 🗂️ **Folder ownership assignment hardening.** Folder create and update inputs now reject unexpected extra fields, preventing clients from overriding protected values like ownership through mass-assignment payloads. [#23648](https://github.com/open-webui/open-webui/pull/23648) +- 🔐 **Knowledge file deletion ownership checks.** Collaborators with knowledge base write access can no longer permanently delete files they do not own, preventing unintended file removal across other linked chats and knowledge bases. [Commit](https://github.com/open-webui/open-webui/commit/914ccf07ef158afe5588b97ed42778c93c439938), [#23636](https://github.com/open-webui/open-webui/pull/23636#issuecomment-4232439454) +- 🗑️ **Knowledge deletion reliability.** Deleting a knowledge base by ID now completes reliably without unexpected failures. [Commit](https://github.com/open-webui/open-webui/commit/7e453de4f7794ff386e285aa5951b94e926ec273), [#23776](https://github.com/open-webui/open-webui/issues/23776), [#23814](https://github.com/open-webui/open-webui/pull/23814) +- 🔐 **OAuth 2.1 PKCE enforcement.** OAuth 2.1 providers now default to S256 PKCE even when discovery metadata omits supported challenge methods, preventing login failures with providers that require PKCE by default. [#23667](https://github.com/open-webui/open-webui/issues/23667), [Commit](https://github.com/open-webui/open-webui/commit/050c4b97a95addc5eaeef86ba00631673a90dec4) +- 🔐 **Static OAuth scope handling.** Static OAuth credential flows now prioritize administrator-defined scopes and handle OAuth 2.1 static flow behavior more reliably. [Commit](https://github.com/open-webui/open-webui/commit/349ea4ea9e577f2cbfb4917ef5f52e5ac53c5b70), [#23668](https://github.com/open-webui/open-webui/issues/23668), [#23696](https://github.com/open-webui/open-webui/pull/23696), [#23783](https://github.com/open-webui/open-webui/pull/23783) +- 🔐 **Static OAuth tool registration reliability.** Static OAuth tool server registration now resolves and uses saved admin credentials more reliably, preventing registration failures when valid client credentials are provided. [#23670](https://github.com/open-webui/open-webui/issues/23670), [Commit](https://github.com/open-webui/open-webui/commit/2943955c529138c0e530fd07b6333a0052e3684e), [Commit](https://github.com/open-webui/open-webui/commit/c767bcaa739f76b1a4337dfd9d6be47adb504825) +- ⏳ **OAuth token expiry fallback.** OAuth sessions now always store a safe expiry value even when providers omit "expires_in" or "expires_at", so token refresh checks continue working and tool calls are less likely to fail later with unexpected authorization errors. [#23669](https://github.com/open-webui/open-webui/issues/23669), [Commit](https://github.com/open-webui/open-webui/commit/31406caa795173a59d5843d3601b891bf617cbaa) +- 🔑 **Anthropic x-api-key model access.** Anthropic-compatible clients can now authenticate with the "x-api-key" header across all relevant API routes, so model listing requests like GET "/api/v1/models" no longer fail with unauthorized errors. [#23319](https://github.com/open-webui/open-webui/issues/23319), [Commit](https://github.com/open-webui/open-webui/commit/611fe0c8a938539b73b559e84964f40c30bf436d) +- 🔑 **SSO password option visibility.** Account settings now hide password change controls when password-change access is disabled, avoiding misleading password options for SSO-focused setups. [#15292](https://github.com/open-webui/open-webui/issues/15292), [Commit](https://github.com/open-webui/open-webui/commit/cced77b584d6ea46c58fecddb2b3dd5e955c8417) +- 🔑 **Open Terminal MCP authentication.** Open Terminal MCP tool calls now include the configured API key when calling internal routes, preventing unauthorized errors for commands like file reads and command execution. [#106](https://github.com/open-webui/open-terminal/pull/106) +- 🧯 **Provider error freeze recovery.** Task-based chat requests now surface provider HTTP errors through normal failure handling, so content-filter and other upstream 4xx responses no longer leave chats stuck in a perpetual loading state. [#23663](https://github.com/open-webui/open-webui/issues/23663), [Commit](https://github.com/open-webui/open-webui/commit/96265cf042c8ab97dbec5d0efcce8010d0cd76e5) +- 🔄 **Immediate outlet filter updates.** Assistant messages modified by outlet filters now appear correctly as soon as streaming completes, without requiring a page refresh. [#23829](https://github.com/open-webui/open-webui/pull/23829) +- 🌊 **Middleware cancellation reliability.** Long-running requests now complete more reliably by preventing middleware-level cancellations from interrupting in-flight database and embedding work, reducing unexpected failures and noisy error logs when connections close early. [#23709](https://github.com/open-webui/open-webui/pull/23709) +- 🚦 **Async vector search responsiveness.** File processing, memory updates, and knowledge retrieval no longer block the server event loop during vector database operations, so other chats and requests stay responsive while indexing or search is running. [#23706](https://github.com/open-webui/open-webui/pull/23706) +- 🗒️ **Notes chat llama.cpp compatibility.** Notes AI chat no longer sends empty assistant prefill messages that can conflict with reasoning-enabled llama.cpp responses, preventing immediate 400 errors in Notes conversations. [Commit](https://github.com/open-webui/open-webui/commit/fd93bd3414a1725219e14561bc5640b62f9fd4a1), [#23703](https://github.com/open-webui/open-webui/issues/23703#issuecomment-4243907629) +- 🧩 **Ollama thinking field preservation.** Messages modified by filters now keep the Ollama "thinking" field when sent to the model, so reasoning-aware workflows and custom filter-based passthrough setups work reliably. [Commit](https://github.com/open-webui/open-webui/commit/8bd23b91459914eb7df5b5a66567d3544e0da168), [#22508](https://github.com/open-webui/open-webui/issues/22508) +- 🧾 **Reasoning content preservation.** Assistant tool-call messages now retain reasoning content across turns, improving reliability for reasoning-heavy model workflows. [Commit](https://github.com/open-webui/open-webui/commit/3dd8255816898467246c81cba3c9bc48bc18d86d), [#23175](https://github.com/open-webui/open-webui/issues/23175), [#23742](https://github.com/open-webui/open-webui/pull/23742) +- 🧭 **Background task scoping for new chats.** Chat title and auto-tag generation now run only for the first message of a new conversation and only once in multi-model responses, preventing duplicate or incorrectly triggered background tasks in follow-up flows. [Commit](https://github.com/open-webui/open-webui/commit/f102060a6d85db4acd3d0bf5c25e976f36cd5533..a4ed16999eec9a654a37c2bb4c15ba5ecd1fa3b7) +- 📚 **Channel document context retention.** Channel conversations now preserve and load the correct stored message history so model responses can use uploaded and retrieved document context more reliably. [#23686](https://github.com/open-webui/open-webui/issues/23686), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67), [Commit](https://github.com/open-webui/open-webui/commit/18fe17127a7175579506e7456d3e5aba201371e6) +- ⏳ **Interrupted response recovery.** Assistant placeholder messages now start as incomplete and recover more safely after interrupted generations, preventing silent empty replies after refreshes or dropped requests. [#23176](https://github.com/open-webui/open-webui/issues/23176), [Commit](https://github.com/open-webui/open-webui/commit/c8ef7b028931263e8773cb60a7111d80d9572d26), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67) +- 🧰 **Large tool result rendering.** Tool call details now display large result payloads reliably in chat instead of intermittently showing empty output for bigger tool responses. [#18743](https://github.com/open-webui/open-webui/issues/18743), [Commit](https://github.com/open-webui/open-webui/commit/45e49d33e51f7720c00b564215484aff9b48b20c) +- 🧼 **Null-byte document sanitization.** PDF and other document ingests now sanitize null bytes and invalid surrogate characters before pgvector writes, preventing PostgreSQL upload failures and allowing affected files to index successfully. [#22992](https://github.com/open-webui/open-webui/issues/22992), [Commit](https://github.com/open-webui/open-webui/commit/8dba798cce9fb1efc5f6acc5f37b152662db78d7) +- 📝 **Knowledge text editor stability.** The Knowledge "Add Text Content" modal now uses a plain text editor, avoiding current rich text editor issues and keeping drafting behavior consistent with existing knowledge editing flows. [Commit](https://github.com/open-webui/open-webui/commit/cd55c3e21237e000c13c6f396bb95b261f3bda82) +- 🎤 **STT SSL setting consistency.** Speech and related outbound media requests now consistently use shared async HTTP sessions and honor the configured SSL verification setting, improving compatibility with self-signed deployments. [#23672](https://github.com/open-webui/open-webui/issues/23672), [Commit](https://github.com/open-webui/open-webui/commit/2ddcb30b9a519885422ba1f36cc3485a7d897bf8) +- 🎙️ **Mistral speech input format.** Mistral speech-to-text requests now use the correct chat-completions audio input format for better compatibility. [Commit](https://github.com/open-webui/open-webui/commit/34d569d564a8ef2702c647dbad83eac840b76b2e), [#23822](https://github.com/open-webui/open-webui/issues/23822) +- 🖼️ **Optional image size parameter.** Image generation no longer sends the "size" field when no size is configured, improving compatibility with providers that reject unsupported size arguments. [#23611](https://github.com/open-webui/open-webui/issues/23611), [Commit](https://github.com/open-webui/open-webui/commit/869cf9e848b741705dc058550fa1b3f70db47fe8) +- 🔎 **FireCrawl timeout reliability.** FireCrawl web loading now uses direct scrape requests and improved timeout handling for single-URL fetches, reducing empty results and premature timeout failures with local FireCrawl setups. [#23411](https://github.com/open-webui/open-webui/issues/23411), [Commit](https://github.com/open-webui/open-webui/commit/9c64d84ad90804bf7d891e4a5097c03c4d7044c3) +- 🖱️ **Custom action icon drag prevention.** Custom user-added action icons in chat responses are no longer accidentally draggable, so clicks and hover interactions behave consistently with built-in action icons. [#23412](https://github.com/open-webui/open-webui/pull/23412) +- 🖼️ **Image URL conversion reliability.** Sending image URLs to AI models no longer fails with "cannot pickle 'coroutine' object" errors, so image inputs now convert to base64 reliably during request processing. [#23685](https://github.com/open-webui/open-webui/pull/23685#issuecomment-4240424635) +- 📂 **Channel input menu dismissal.** In Workspace Channels, the message input dropdown now closes immediately after selecting "Upload Files" or "Capture", matching normal chat input behavior and preventing the menu from staying open unnecessarily. [#23684](https://github.com/open-webui/open-webui/pull/23684) +- 📋 **Clipboard copy scroll stability.** Copying content with the fallback clipboard method no longer triggers unwanted page scrolling during focus, keeping your current reading position stable. [Commit](https://github.com/open-webui/open-webui/commit/fc98000aa8d439bbff21a70370f5e962bf23f4bc) +- 🖼️ **Profile image URL validation.** Profile saves now accept valid Open WebUI profile-image paths, trusted external HTTP(S) avatar URLs, and safe raster data-image formats while rejecting unsafe URL patterns that could be abused. [#23389](https://github.com/open-webui/open-webui/pull/23389) +- 👤 **Partial user profile updates.** User update API requests can now modify only the fields you provide, so administrators no longer need to resubmit unchanged name, email, and profile image values when changing a single setting like role. [#23424](https://github.com/open-webui/open-webui/issues/23424), [Commit](https://github.com/open-webui/open-webui/commit/3c2c611ba91d794a1e73134ec41b0de2b3927677) +- 🚨 **Provider SSE error visibility.** Provider failures returned with streaming content types are now surfaced as proper API errors and logged clearly, so issues like context-window limits no longer fail silently during chat generation. [#23379](https://github.com/open-webui/open-webui/pull/23379) +- 🧵 **Queued prompt race prevention.** Chat request queues now prevent overlapping processing for the same chat, avoiding duplicate queue handling when multiple queue-processing triggers fire close together. [#23181](https://github.com/open-webui/open-webui/issues/23181), [Commit](https://github.com/open-webui/open-webui/commit/e10a00132eed54a0108fb6ac120e8229deef3656) +- 🛑 **Cancellation event delivery reliability.** Cancelled chat processing now safely emits task-cancel and error events only when an event emitter is available, while provider HTTP errors now also route through task-cancel handling so chats recover from blocked-loading states more reliably. [#23663](https://github.com/open-webui/open-webui/issues/23663), [Commit](https://github.com/open-webui/open-webui/commit/51765b619c8584b042af68c3a5c87525a105ccd8), [Commit](https://github.com/open-webui/open-webui/commit/96265cf042c8ab97dbec5d0efcce8010d0cd76e5) +- 🔑 **OIDC key-rotation recovery.** OIDC login now retries token authorization with refreshed provider signing keys after a bad-signature failure, so logins recover automatically after identity-provider key rotation without requiring a service restart. [#23582](https://github.com/open-webui/open-webui/issues/23582), [Commit](https://github.com/open-webui/open-webui/commit/facb194a07486e847f0725a0a839e99b5864d37b) +- 🌍 **Non-ASCII tag filtering.** Prompt and model tag filters now handle non-Latin tags more reliably across SQLite and PostgreSQL, so tags like Cyrillic values return the expected items in Workspace lists. [#23381](https://github.com/open-webui/open-webui/issues/23381), [#23427](https://github.com/open-webui/open-webui/pull/23427), [Commit](https://github.com/open-webui/open-webui/commit/57784706e4fee75dec67e20b0d89a97351ac6256) +- 🏷️ **Prompt tag query accuracy.** Prompt tag filtering now uses JSON-element-aware queries so tag-based lookups return the correct prompts. [Commit](https://github.com/open-webui/open-webui/commit/e7e752f8e74e7b01fe2e6cb56f06e99312e1afe7), [#23386](https://github.com/open-webui/open-webui/pull/23386) +- 🗃️ **SQLite async pool compatibility.** SQLite async database setup no longer forces an explicit queue pool class, avoiding pool configuration conflicts in SQLite deployments. [Commit](https://github.com/open-webui/open-webui/commit/26b8ca5b5eeb144fae3fe6eaeae826150d8af826) +- 🧠 **Knowledge embedding deadlock prevention.** Knowledge file processing now runs blocking vector-save work in a worker thread while keeping async status updates reliable, preventing file processing from stalling during long embedding operations. [Commit](https://github.com/open-webui/open-webui/commit/d4b90f93bda2413ec8f040e61959acdb7b242061), [Commit](https://github.com/open-webui/open-webui/commit/22cfb3c673cbfa4a6bce26fde8e2e2754ce4963b) +- 🤖 **Automation worker async DB handling.** Automation claiming and run recording now use async database sessions consistently, improving worker stability for scheduled automations. [Commit](https://github.com/open-webui/open-webui/commit/cb6e77be3ec6ce00dd1f5b9ce3a655e6f65bc5da) +- 🕒 **Automation timezone scheduling.** Scheduled automations now calculate each user’s next run time using that user’s saved timezone, preventing run drift caused by server-time fallback. [Commit](https://github.com/open-webui/open-webui/commit/a4d62253df55c6307112eb76a6bfa29a7f538e21) +- 🔎 **Notes search matching.** Notes search now handles multi-word and hyphenated queries more reliably, so relevant notes and snippets are easier to find from partial phrase searches. [Commit](https://github.com/open-webui/open-webui/commit/a35926261646f8897ba71da1572ed5dff802e3be) +- 📐 **Display math rendering.** Chat markdown now correctly recognizes and renders "$$...$$" expressions as display math, improving reliability for multiline and escaped KaTeX content while keeping malformed delimiters from disrupting message rendering. [#23526](https://github.com/open-webui/open-webui/issues/23526), [Commit](https://github.com/open-webui/open-webui/commit/15b89b9218b7d2c7239c579aa3d23c2892227ac6) +- 🚫 **LDAP empty-password rejection.** LDAP login now rejects empty or whitespace-only passwords before bind attempts, preventing unauthenticated simple-bind behavior from granting access on permissive LDAP server configurations. [#23633](https://github.com/open-webui/open-webui/pull/23633) +- 🌐 **IPv6 SSRF address blocking.** URL validation now uses standard IP address checks for both IPv4 and IPv6, preventing private, loopback, link-local, reserved, and mapped-address SSRF bypasses through IPv6 hostname resolution. [#23453](https://github.com/open-webui/open-webui/pull/23453) +- 🔒 **API key endpoint restriction bypass.** API key endpoint restrictions are now enforced regardless of whether the key is sent through Authorization headers, cookies, or "x-api-key", preventing bypass through alternate key transport paths. [#23637](https://github.com/open-webui/open-webui/pull/23637) +- 🔐 **Channel sharing permission enforcement.** Channel creation and updates now enforce allowed access grant rules for public sharing, preventing unauthorized wildcard sharing on group channels. [#23638](https://github.com/open-webui/open-webui/pull/23638) +- 🛑 **Socket role invalidation.** Socket sessions now disconnect automatically when a user is demoted or deleted, preventing stale admin privileges from persisting until reconnect. [#23642](https://github.com/open-webui/open-webui/pull/23642) +- 🛂 **Tool server access checks.** Tool listing now correctly awaits server access checks, preventing users from seeing server-backed tools they do not have permission to use. [Commit](https://github.com/open-webui/open-webui/commit/d40f31982be3eed37e55e3f67b1eea9a5dc8c525) +- 🛑 **Task endpoint access control.** Global task listing and direct task stop endpoints are now restricted to administrators, while regular users can stop only their own chat tasks through a scoped chat endpoint. [#23454](https://github.com/open-webui/open-webui/pull/23454) +- 🧱 **Redis cache key isolation.** Tool server and terminal server cache entries now include the Redis key prefix, preventing multiple Open WebUI instances that share one Redis database from overwriting each other’s cached connection data. [#23649](https://github.com/open-webui/open-webui/pull/23649) +- 🧠 **Client session leak prevention.** Outbound provider requests now use a shared session pool with safer response cleanup and shutdown handling, preventing aiohttp session buildup and reducing memory growth during heavy concurrent API traffic. [#23540](https://github.com/open-webui/open-webui/issues/23540), [Commit](https://github.com/open-webui/open-webui/commit/c47dd7b7717c4186e0f0549ca3c8cb4d9bb38135) +- 🧩 **Tool enum value handling.** Tool schema generation now safely handles enum values as strings, preventing failures when OpenAPI parameters include non-string enum entries. [#23597](https://github.com/open-webui/open-webui/issues/23597), [Commit](https://github.com/open-webui/open-webui/commit/4498e6faf2b1bdd1caa0e2c1c15d90a2790cd721) +- 🧷 **Responses model access control.** The OpenAI-compatible Responses endpoint now enforces per-model permissions, preventing non-admin users from accessing models they are not allowed to use. [#23481](https://github.com/open-webui/open-webui/pull/23481) +- 🛡️ **Collection process endpoint permissions.** Collection processing endpoints now enforce collection ownership checks for web and text processing requests. [Commit](https://github.com/open-webui/open-webui/commit/ba83613ff297bc82db660b5273f04672d744902f), [#23634](https://github.com/open-webui/open-webui/pull/23634) +- 📚 **Knowledge query access enforcement.** Knowledge-base collection queries now block unauthorized enumeration and require read access before returning results. [Commit](https://github.com/open-webui/open-webui/commit/860b90fd17d14ba00674621edd294dee150491d2), [#23635](https://github.com/open-webui/open-webui/pull/23635), [#23452](https://github.com/open-webui/open-webui/pull/23452) +- 🔍 **RAG collection query permissions.** Vector search collection queries now enforce access checks before retrieval results are returned. [Commit](https://github.com/open-webui/open-webui/commit/f44b7a01f5b854f47c1594a1ab5f72096f736262), [#23627](https://github.com/open-webui/open-webui/pull/23627) +- 🔗 **Chained base model access checks.** Chained base model execution now enforces per-model access rules to prevent unauthorized model usage. [Commit](https://github.com/open-webui/open-webui/commit/8acce144f99992b75c25f0e5038b16881ce9f066), [Commit](https://github.com/open-webui/open-webui/commit/50363ba66b19613a2fc0cab6a3f7f724a825135e), [#23647](https://github.com/open-webui/open-webui/pull/23647) +- ✍️ **Collaborative document write checks.** Collaborative document updates now require proper write permission before changes are accepted. [Commit](https://github.com/open-webui/open-webui/commit/638c7ab80216452910bdc59a19eb90e6b7244c6c), [Commit](https://github.com/open-webui/open-webui/commit/3271b013a8b30a882364679dcb40ffc9a89f037e), [#23624](https://github.com/open-webui/open-webui/pull/23624) +- 📥 **Model import ownership validation.** Model import now enforces ownership and access grant checks to prevent unauthorized imports. [Commit](https://github.com/open-webui/open-webui/commit/499129625bf96b2c03a6d057a2f91fdf07fd1c49), [#23628](https://github.com/open-webui/open-webui/pull/23628) +- 🚫 **Inactive member channel access.** Deactivated group members can no longer read or write channel content through direct API calls, so channel permissions now match active membership status. [#23623](https://github.com/open-webui/open-webui/pull/23623) +- 🎛️ **Ollama endpoint model permissions.** Restricted models are now protected on Ollama show, generate, embed, and embeddings endpoints, preventing authenticated users from using private models without read access. [#23631](https://github.com/open-webui/open-webui/pull/23631) +- 🧭 **Azure deployment path validation.** Azure model names are now validated and safely encoded before request URL construction, preventing path traversal attempts from reaching unintended Azure endpoints. [#23629](https://github.com/open-webui/open-webui/pull/23629) +- 👥 **Private channel member list access.** Standard channel member lists now require proper read permission, preventing unauthorized users from enumerating members of private channels by direct API calls. [#23625](https://github.com/open-webui/open-webui/pull/23625) +- 🌀 **Tool server schema recursion safety.** Tool server OpenAPI conversion now handles circular request schema references safely, preventing conversion crashes and ensuring one bad tool server spec does not break the full tool server list. [#23588](https://github.com/open-webui/open-webui/pull/23588), [Commit](https://github.com/open-webui/open-webui/commit/d3df8f1f372411314be9121fbf61d107939fa258) +- 🧱 **Safer file path handling.** File upload, transcription cache, and model download paths now use safer path construction helpers to reduce path parsing risks and improve cross-platform path safety. [Commit](https://github.com/open-webui/open-webui/commit/15f9a8f3f13f112c96cb1b16f88859f65de58346) +- 🧾 **Prompt save error feedback.** Saving prompt edits now shows a clear error toast if the save fails, so failed updates are visible instead of silently failing in the editor flow. [Commit](https://github.com/open-webui/open-webui/commit/36a81ad43b7c0d450079f818a7546eaa517e3d95) +- 🧾 **Tool call JSON rendering.** Tool call arguments and structured results now render as plain formatted JSON blocks instead of markdown code fences, preventing formatting quirks and making tool output easier to read consistently. [Commit](https://github.com/open-webui/open-webui/commit/a7d4c53f3adb80768b67e4a410b486b04a581521) +- 👥 **First-user admin race protection.** Concurrent first-time LDAP or OAuth registrations can no longer create multiple admin accounts, so only the true first account is promoted during initial setup. [#23626](https://github.com/open-webui/open-webui/pull/23626) +- 🔒 **SCIM token checks.** SCIM authentication now compares tokens in a safer way, helping prevent timing-based token guessing attacks. [#23577](https://github.com/open-webui/open-webui/pull/23577) +- 🔒 **Safer file access checks.** HTML file previews now treat missing or non-admin owners as inaccessible, preventing accidental access to files that should not be shown. [Commit](https://github.com/open-webui/open-webui/commit/6acaaea59a50ec26da03e6144017a2fd86241ce9) +- 🖼️ **ComfyUI request hangs.** Concurrent image generation and editing requests to ComfyUI now complete reliably instead of getting stuck when the same user starts multiple requests at once. [#23592](https://github.com/open-webui/open-webui/pull/23592), [#23591](https://github.com/open-webui/open-webui/issues/23591) +- 🧭 **Permission-aware built-in tools.** Built-in tools now consistently respect user feature permissions for memories, web search, image generation, code interpreter, notes, channels, and automations, preventing tools from being exposed to users without access. [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) +- 🛑 **Interrupted MCP cleanup stability.** Interrupted MCP tool calls no longer leave runaway cleanup behavior that can drive container CPU usage to 100%, keeping instances stable after cancellations or dropped connections. [#23143](https://github.com/open-webui/open-webui/issues/23143) +- 🚪 **OAuth redirect URI reliability.** OAuth login redirects now use provider client metadata more consistently, preventing incorrect HTTP callback URLs behind reverse proxies and improving sign-in reliability for providers such as Feishu. [#23203](https://github.com/open-webui/open-webui/pull/23203), [#23128](https://github.com/open-webui/open-webui/issues/23128) +- 🌐 **OAuth redirect handling.** OAuth provider token exchange now follows redirects automatically, improving sign-in reliability with identity providers that redirect token endpoint requests. [#23409](https://github.com/open-webui/open-webui/issues/23409), [Commit](https://github.com/open-webui/open-webui/commit/498ff8cdc3dd47000cdc60e5adcf36f4adfbe07d) +- ☁️ **OneDrive picker redirect handling.** OneDrive file picker authentication now uses the current app origin as the redirect URI, improving sign-in reliability when launching the picker from deployed environments. [#23450](https://github.com/open-webui/open-webui/issues/23450), [Commit](https://github.com/open-webui/open-webui/commit/21cc8281323d505d7d084cc496bd433063315c86) +- 🍪 **OAuth session cookie persistence.** OIDC sign-in now correctly sets the "oauth_session_id" cookie, so "system_oauth" connections can forward user OAuth tokens to upstream providers as expected. [#23251](https://github.com/open-webui/open-webui/pull/23251), [#23250](https://github.com/open-webui/open-webui/issues/23250) +- 🔑 **OAuth session cookie handling.** OAuth callback processing no longer fails on undefined cookie expiry data, so OAuth session cookies are stored correctly after sign-in. [#23207](https://github.com/open-webui/open-webui/pull/23207), [#23197](https://github.com/open-webui/open-webui/issues/23197) +- 🔏 **Ollama SSL handling.** Ollama model management and file uploads now respect the configured SSL verification setting, so self-signed certificates work when SSL verification is disabled. [#23503](https://github.com/open-webui/open-webui/issues/23503), [Commit](https://github.com/open-webui/open-webui/commit/e51b661af0e71a24f041428f328fcc6e97a15262) +- 🛡️ **OAuth avatar URL validation.** OAuth sign-in now validates profile picture URLs before fetching them, preventing invalid image links from causing login-time errors. [#23356](https://github.com/open-webui/open-webui/pull/23356) +- 🔑 **User invite token expiry.** New user invite logins now respect the configured "JWT_EXPIRES_IN" setting, so signup tokens expire as expected instead of using the default lifetime. [#23576](https://github.com/open-webui/open-webui/pull/23576) +- 🚪 **Channel access checks.** Channel actions now verify the current user when checking access, improving permission enforcement across channel views and message actions. [Commit](https://github.com/open-webui/open-webui/commit/4632f200a9ac98c915aee412b34e86c3d3c58bb1) +- 📣 **Channel message lookups.** Channel message details and pinning now work more reliably when the sender account is missing, avoiding failures in those views. [Commit](https://github.com/open-webui/open-webui/commit/6acaaea59a50ec26da03e6144017a2fd86241ce9) +- 📌 **Pinned webhook message handling.** Viewing pinned webhook messages now works reliably even when webhook profile data is missing, preventing server errors and frontend crashes in channel pinned message dialogs. [#23414](https://github.com/open-webui/open-webui/pull/23414) +- 🛡️ **Note edit permission enforcement.** Note saving now requires write access instead of read access, preventing unauthorized users from modifying notes while preserving expected collaboration permissions. [Commit](https://github.com/open-webui/open-webui/commit/584a9a0920d8c8c72fc89ccbac83c970b5a4bd4a) +- 🗂️ **Archived chats menu visibility.** The 'Archived Chats' option in the user menu is now shown reliably for all users, so non-admin accounts can consistently access archived conversations. [Commit](https://github.com/open-webui/open-webui/commit/07262fa62c2323fc7948389e5b5b8a5d1b72fade) +- 💾 **Error message persistence.** LLM errors that occur during streaming are now saved to the database even if the connection drops, so users can see what went wrong when they reconnect. [#23231](https://github.com/open-webui/open-webui/pull/23231) +- 🚫 **Missing message completion guard.** Chat completion finalization now skips invalid requests without a message identifier, preventing unnecessary error toasts caused by rare frontend concurrency timing. [#23184](https://github.com/open-webui/open-webui/pull/23184) +- 🧠 **Active message completion accuracy.** Switching chats or refreshing during generation no longer marks the currently streaming assistant message as finished too early, so thinking blocks and action buttons appear at the correct time. [#23171](https://github.com/open-webui/open-webui/issues/23171) +- 📞 **Call overlay visibility.** Incoming call events now open the call overlay and controls reliably, preventing cases where the call interface briefly appeared and then disappeared. [Commit](https://github.com/open-webui/open-webui/commit/ee9db91df02120e1e3651e8881734966b710ad52) +- 💬 **Prompt submission handling.** Chat messages now preserve attached files more reliably when prompts are sent, including queued messages and shared prompt actions. [Commit](https://github.com/open-webui/open-webui/commit/6d6dfbf02c893d72d85d4490cb41f1665b1f9f95) +- 🧾 **Prompt variable form saving.** Prompt variable forms now save reliably without runtime errors or an unresponsive save action, so input values and placeholders work correctly when applying prompt templates with variables. [#23225](https://github.com/open-webui/open-webui/issues/23225), [#23480](https://github.com/open-webui/open-webui/issues/23480) +- 🛟 **Task model fallback safety.** Task routing now handles missing default model entries safely, preventing task execution failures when the previously selected model is no longer available. [#23169](https://github.com/open-webui/open-webui/pull/23169) +- 📊 **Usage statistic preservation.** Follow-up generation no longer overwrites existing token usage fields, so stored usage statistics remain accurate for the main response. [#23152](https://github.com/open-webui/open-webui/issues/23152) +- 📝 **Writing block parsing reliability.** ":::writing" blocks now parse more reliably when headers or extra inline text are present, preventing malformed rendering and duplicate output artifacts. [#23174](https://github.com/open-webui/open-webui/issues/23174) +- 🧾 **Code block line break reliability.** Blank lines in submitted code blocks are now preserved more reliably instead of being collapsed. [Commit](https://github.com/open-webui/open-webui/commit/1be9627dd27ffe75957729a4a0d1682a98684f01), [#20302](https://github.com/open-webui/open-webui/issues/20302), [#23451](https://github.com/open-webui/open-webui/pull/23451) +- ✂️ **Citation spacing cleanup.** When citations are disabled for a model, citation markers and their leftover spacing are now removed together so punctuation and copied text remain cleanly formatted. [#23141](https://github.com/open-webui/open-webui/issues/23141) +- 🧰 **Pipe tool access.** Pipe functions now receive built-in and MCP tools in __tools__, so tools like Web Search and code execution are available when enabled. [#23365](https://github.com/open-webui/open-webui/issues/23365) +- 📚 **Batch file processing database handling.** Batch knowledge file processing now consistently uses the active database session, preventing failures caused by missing database context during file ownership checks and update writes. [#23137](https://github.com/open-webui/open-webui/issues/23137) +- ⚙️ **Default model parameter loading.** The "DEFAULT_MODEL_PARAMS" environment variable is now parsed and applied correctly, so default generation settings are honored reliably without being ignored at startup. [#23223](https://github.com/open-webui/open-webui/pull/23223) +- 🔧 **Web search settings save reliability.** Saving web search configuration now works without server errors, so administrators can update "WEB_FETCH_MAX_CONTENT_LENGTH" and related retrieval settings successfully from the admin interface. [Commit](https://github.com/open-webui/open-webui/commit/36d02aa1477aa1b4e7fb59d022f99693ebfa8667), [#23127](https://github.com/open-webui/open-webui/issues/23127) +- 🔍 **Web search result count.** The built-in search_web tool now respects the admin-configured "Search Result Count" setting instead of always returning 5 results when using Native Function Calling mode. [#23488](https://github.com/open-webui/open-webui/pull/23488), [#23485](https://github.com/open-webui/open-webui/issues/23485) +- 🖼️ **Open Terminal file response handling.** Open Terminal tool responses now preserve binary content types in user-side connections, so image and non-text file reads work consistently instead of being forced into plain text. [#23125](https://github.com/open-webui/open-webui/issues/23125) +- 🖥️ **Terminal label casing.** Terminal names in the chat input now display exactly as stored instead of being automatically capitalized, so domain-style server names appear correctly. [#23518](https://github.com/open-webui/open-webui/pull/23518) +- 🖼️ **Gravatar profile photo saving.** Gravatar profile images can now be saved successfully from account settings, with clearer validation and error handling instead of failing with generic object errors. [#23156](https://github.com/open-webui/open-webui/issues/23156) +- 🪟 **Details expansion preference.** Tool call detail groups now honor the 'Always Expand Details' chat setting, so they open expanded by default when that preference is enabled. [#23262](https://github.com/open-webui/open-webui/pull/23262), [#23255](https://github.com/open-webui/open-webui/issues/23255) +- 🖱️ **Rapid sidebar action protection.** Archive and delete actions in the chat sidebar now ignore repeated clicks while a request is in progress, preventing duplicate requests and stacked error toasts. [#23172](https://github.com/open-webui/open-webui/issues/23172) +- 📲 **Mobile model selector positioning.** The mobile model selector dropdown now applies a constrained viewport width and left offset, preventing overflow and making model selection easier on small screens. [#23310](https://github.com/open-webui/open-webui/pull/23310) +- 🔽 **Task list toggle icons.** The task list collapse button now shows the correct arrow direction, making task sections easier to expand and collapse at a glance. [Commit](https://github.com/open-webui/open-webui/commit/f66b67c8b86b6f9d896a23c7bb53907c2e6b15d3), [#23354](https://github.com/open-webui/open-webui/issues/23354) +- ➕ **Attachment menu auto-close.** The chat attachment menu now closes immediately after selecting upload actions like file upload, camera capture, web attach, Google Drive, or OneDrive, preventing the menu from lingering on screen. [Commit](https://github.com/open-webui/open-webui/commit/4764dd5d3765c22384ed38cbc97a8170daa7a75f), [#23320](https://github.com/open-webui/open-webui/issues/23320) +- 🧹 **Per-chat draft clearing.** Sent message drafts are now cleared using the active chat key, so sent text no longer reappears in the input after a refresh. [Commit](https://github.com/open-webui/open-webui/commit/124b7e9154d7f3ca8a16f2b90621209ac8d6b8c1), [#23296](https://github.com/open-webui/open-webui/issues/23296) +- ✉️ **Context-aware input action button.** The input now shows the send action when text or files are present during generation, while keeping stop controls for truly empty input states to avoid action confusion. [Commit](https://github.com/open-webui/open-webui/commit/86472bb4453af7ea4e5ddc8d127b14d8e67733bc), [#23306](https://github.com/open-webui/open-webui/issues/23306) +- 📉 **Pyodide prompt cache stability.** Pyodide code interpreter context is now appended to the system prompt instead of user messages, preserving stable prefix caching across turns and reducing repeated token costs in long native tool-calling chats. [#23269](https://github.com/open-webui/open-webui/issues/23269) +- 🧪 **Temp chat outlet filtering.** Outlet filters now process temporary chats more reliably, preserving assistant output and usage data so local chat responses stay consistent when filter pipelines are enabled. [Commit](https://github.com/open-webui/open-webui/commit/70a6a24f143b221c787bc50b72582ee1e0c2dac0) + +### Changed + +- ⚠️ **Database Migrations**: This release includes database schema changes; we strongly recommend backing up your database and all associated data before upgrading in production environments. If you are running a multi-worker, multi-server, or load-balanced deployment, all instances must be updated simultaneously, rolling updates are not supported and will cause application failures due to schema incompatibility. +- 🧨 **Plugin async migration required.** Custom plugins for Tools, Functions, and Pipelines may require migration to the new async backend signatures after upgrading, so plugin maintainers should update handlers and database call patterns for compatibility and follow the 0.9.0 plugin migration guide. [Migration Guide](https://docs.openwebui.com/features/extensibility/plugin/migration/to-0.9.0) +- 🔄 **Automation terminal source.** Automations now use the terminal configured on the selected model instead of a separate per-automation terminal picker, keeping terminal behavior consistent between chat and scheduled runs. [Commit](https://github.com/open-webui/open-webui/commit/47d413ce7b2a006a8126f4a9055b13e5fcb33a1d) +- 🚧 **OpenAI passthrough now opt-in.** Direct OpenAI catch-all proxy requests are now disabled by default and require enabling "ENABLE_OPENAI_API_PASSTHROUGH", so deployments relying on passthrough must explicitly turn it on after upgrading. [#23640](https://github.com/open-webui/open-webui/pull/23640) +- 🗄️ **SQLite WAL default enabled.** SQLite deployments now default to enabling write-ahead logging, improving concurrent read and write behavior without requiring manual configuration. [Commit](https://github.com/open-webui/open-webui/commit/2f9e326dba3b1087932cb6b8075ed1881bd1c6d6) + ## [0.8.12] - 2026-03-26 ### Added From 5f76c250f880d07ebc9b856b604cc1b8029f7eb4 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 15:20:28 +0900 Subject: [PATCH 342/404] refac --- src/lib/components/chat/MessageInput/TerminalMenu.svelte | 2 +- src/lib/components/chat/SettingsModal.svelte | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/lib/components/chat/MessageInput/TerminalMenu.svelte b/src/lib/components/chat/MessageInput/TerminalMenu.svelte index 8aaf880c90..ca721ceb2d 100644 --- a/src/lib/components/chat/MessageInput/TerminalMenu.svelte +++ b/src/lib/components/chat/MessageInput/TerminalMenu.svelte @@ -125,7 +125,7 @@ class="p-0.5 rounded-md text-gray-400 hover:text-gray-600 dark:text-gray-500 dark:hover:text-gray-300 transition" on:click|stopPropagation={() => { show = false; - showSettings.set(true); + showSettings.set('tools'); }} > Date: Tue, 21 Apr 2026 15:41:07 +0900 Subject: [PATCH 343/404] refac --- backend/open_webui/routers/channels.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index 22feb1b8f6..487899fccf 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -305,7 +305,7 @@ async def create_new_channel( detail=ERROR_MESSAGES.UNAUTHORIZED, ) - form_data.access_grants = filter_allowed_access_grants( + form_data.access_grants = await filter_allowed_access_grants( request.app.state.config.USER_PERMISSIONS, user.id, user.role, @@ -643,7 +643,7 @@ async def update_channel_by_id( if channel.user_id != user.id and user.role != 'admin': raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT()) - form_data.access_grants = filter_allowed_access_grants( + form_data.access_grants = await filter_allowed_access_grants( request.app.state.config.USER_PERMISSIONS, user.id, user.role, From b9fc3f367ae739a0c9364417c1be31681e0b237b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 15:47:32 +0900 Subject: [PATCH 344/404] refac --- backend/open_webui/retrieval/utils.py | 117 +++++++++++++++++++++++- backend/open_webui/routers/retrieval.py | 38 +------- 2 files changed, 117 insertions(+), 38 deletions(-) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index 93ba72ce13..cafb8fe4f0 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -83,11 +83,120 @@ def get_loader(request, url: str): ) +def build_loader_from_config(request): + """Build a Loader instance with the admin's configured extraction engine settings.""" + from open_webui.retrieval.loaders.main import Loader + + config = request.app.state.config + return Loader( + engine=config.CONTENT_EXTRACTION_ENGINE, + DATALAB_MARKER_API_KEY=config.DATALAB_MARKER_API_KEY, + DATALAB_MARKER_API_BASE_URL=config.DATALAB_MARKER_API_BASE_URL, + DATALAB_MARKER_ADDITIONAL_CONFIG=config.DATALAB_MARKER_ADDITIONAL_CONFIG, + DATALAB_MARKER_SKIP_CACHE=config.DATALAB_MARKER_SKIP_CACHE, + DATALAB_MARKER_FORCE_OCR=config.DATALAB_MARKER_FORCE_OCR, + DATALAB_MARKER_PAGINATE=config.DATALAB_MARKER_PAGINATE, + DATALAB_MARKER_STRIP_EXISTING_OCR=config.DATALAB_MARKER_STRIP_EXISTING_OCR, + DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION=config.DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION, + DATALAB_MARKER_FORMAT_LINES=config.DATALAB_MARKER_FORMAT_LINES, + DATALAB_MARKER_USE_LLM=config.DATALAB_MARKER_USE_LLM, + DATALAB_MARKER_OUTPUT_FORMAT=config.DATALAB_MARKER_OUTPUT_FORMAT, + EXTERNAL_DOCUMENT_LOADER_URL=config.EXTERNAL_DOCUMENT_LOADER_URL, + EXTERNAL_DOCUMENT_LOADER_API_KEY=config.EXTERNAL_DOCUMENT_LOADER_API_KEY, + TIKA_SERVER_URL=config.TIKA_SERVER_URL, + DOCLING_SERVER_URL=config.DOCLING_SERVER_URL, + DOCLING_API_KEY=config.DOCLING_API_KEY, + DOCLING_PARAMS=config.DOCLING_PARAMS, + PDF_EXTRACT_IMAGES=config.PDF_EXTRACT_IMAGES, + PDF_LOADER_MODE=config.PDF_LOADER_MODE, + DOCUMENT_INTELLIGENCE_ENDPOINT=config.DOCUMENT_INTELLIGENCE_ENDPOINT, + DOCUMENT_INTELLIGENCE_KEY=config.DOCUMENT_INTELLIGENCE_KEY, + DOCUMENT_INTELLIGENCE_MODEL=config.DOCUMENT_INTELLIGENCE_MODEL, + MISTRAL_OCR_API_BASE_URL=config.MISTRAL_OCR_API_BASE_URL, + MISTRAL_OCR_API_KEY=config.MISTRAL_OCR_API_KEY, + MINERU_API_MODE=config.MINERU_API_MODE, + MINERU_API_URL=config.MINERU_API_URL, + MINERU_API_KEY=config.MINERU_API_KEY, + MINERU_API_TIMEOUT=config.MINERU_API_TIMEOUT, + MINERU_PARAMS=config.MINERU_PARAMS, + ) + + +def _extract_text_from_binary_response( + request, response: requests.Response, url: str +) -> tuple[str, list]: + """Download response body to a temp file and extract text using the Loader pipeline.""" + import mimetypes + import tempfile + import urllib.parse + + content_type = response.headers.get('Content-Type', '').split(';')[0].strip() + + # Derive filename from URL path, falling back to Content-Disposition or mime guess + url_path = urllib.parse.urlparse(url).path + filename = os.path.basename(url_path) if url_path else '' + + if not filename or '.' not in filename: + # Try Content-Disposition header + cd = response.headers.get('Content-Disposition', '') + if 'filename=' in cd: + filename = cd.split('filename=')[-1].strip('"\'') + + if not filename or '.' not in filename: + ext = mimetypes.guess_extension(content_type) or '' + filename = f'download{ext}' + + suffix = '.' + filename.split('.')[-1].lower() if '.' in filename else '' + + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp: + tmp.write(response.content) + tmp_path = tmp.name + + try: + loader = build_loader_from_config(request) + docs = loader.load(filename, content_type, tmp_path) + for doc in docs: + doc.metadata['source'] = url + content = ' '.join([doc.page_content for doc in docs]) + return content, docs + finally: + os.remove(tmp_path) + + +def _is_text_content_type(content_type: str) -> bool: + """Return True if the content type should be handled by the web loader.""" + ct = content_type.split(';')[0].strip().lower() + if ct.startswith('text/'): + return True + if any(t in ct for t in ['xml', 'json', 'javascript']): + return True + return not ct # empty / missing → assume HTML + + def get_content_from_url(request, url: str) -> str: - loader = get_loader(request, url) - docs = loader.load() - content = ' '.join([doc.page_content for doc in docs]) - return content, docs + # Streamed GET to check Content-Type without downloading the body. + try: + response = requests.get(url, stream=True, timeout=30) + response.raise_for_status() + content_type = response.headers.get('Content-Type', '') + except Exception: + content_type = '' + response = None + + # Text / HTML / unknown — use the configured web loader + if response is None or _is_text_content_type(content_type): + if response is not None: + response.close() + loader = get_loader(request, url) + docs = loader.load() + content = ' '.join([doc.page_content for doc in docs]) + return content, docs + + # Binary content (PDF, DOCX, XLSX, PPTX, etc.) — download and extract + try: + return _extract_text_from_binary_response(request, response, url) + finally: + response.close() CHUNK_HASH_KEY = '_chunk_hash' diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index ee8a9007fe..fea00143e6 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -48,7 +48,7 @@ from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT from open_webui.retrieval.vector.async_client import ASYNC_VECTOR_DB_CLIENT # Document loaders -from open_webui.retrieval.loaders.main import Loader + from open_webui.retrieval.loaders.youtube import YoutubeLoader # Web search engines @@ -82,6 +82,7 @@ from open_webui.retrieval.web.yandex import search_yandex from open_webui.retrieval.web.ydc import search_youcom from open_webui.retrieval.utils import ( + build_loader_from_config, filter_accessible_collections, get_content_from_url, get_embedding_function, @@ -1623,39 +1624,8 @@ async def process_file( file_path = file.path if file_path: file_path = await asyncio.to_thread(Storage.get_file, file_path) - loader = Loader( - engine=request.app.state.config.CONTENT_EXTRACTION_ENGINE, - user=user, - DATALAB_MARKER_API_KEY=request.app.state.config.DATALAB_MARKER_API_KEY, - DATALAB_MARKER_API_BASE_URL=request.app.state.config.DATALAB_MARKER_API_BASE_URL, - DATALAB_MARKER_ADDITIONAL_CONFIG=request.app.state.config.DATALAB_MARKER_ADDITIONAL_CONFIG, - DATALAB_MARKER_SKIP_CACHE=request.app.state.config.DATALAB_MARKER_SKIP_CACHE, - DATALAB_MARKER_FORCE_OCR=request.app.state.config.DATALAB_MARKER_FORCE_OCR, - DATALAB_MARKER_PAGINATE=request.app.state.config.DATALAB_MARKER_PAGINATE, - DATALAB_MARKER_STRIP_EXISTING_OCR=request.app.state.config.DATALAB_MARKER_STRIP_EXISTING_OCR, - DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION=request.app.state.config.DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION, - DATALAB_MARKER_FORMAT_LINES=request.app.state.config.DATALAB_MARKER_FORMAT_LINES, - DATALAB_MARKER_USE_LLM=request.app.state.config.DATALAB_MARKER_USE_LLM, - DATALAB_MARKER_OUTPUT_FORMAT=request.app.state.config.DATALAB_MARKER_OUTPUT_FORMAT, - EXTERNAL_DOCUMENT_LOADER_URL=request.app.state.config.EXTERNAL_DOCUMENT_LOADER_URL, - EXTERNAL_DOCUMENT_LOADER_API_KEY=request.app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY, - TIKA_SERVER_URL=request.app.state.config.TIKA_SERVER_URL, - DOCLING_SERVER_URL=request.app.state.config.DOCLING_SERVER_URL, - DOCLING_API_KEY=request.app.state.config.DOCLING_API_KEY, - DOCLING_PARAMS=request.app.state.config.DOCLING_PARAMS, - PDF_EXTRACT_IMAGES=request.app.state.config.PDF_EXTRACT_IMAGES, - PDF_LOADER_MODE=request.app.state.config.PDF_LOADER_MODE, - DOCUMENT_INTELLIGENCE_ENDPOINT=request.app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT, - DOCUMENT_INTELLIGENCE_KEY=request.app.state.config.DOCUMENT_INTELLIGENCE_KEY, - DOCUMENT_INTELLIGENCE_MODEL=request.app.state.config.DOCUMENT_INTELLIGENCE_MODEL, - MISTRAL_OCR_API_BASE_URL=request.app.state.config.MISTRAL_OCR_API_BASE_URL, - MISTRAL_OCR_API_KEY=request.app.state.config.MISTRAL_OCR_API_KEY, - MINERU_API_MODE=request.app.state.config.MINERU_API_MODE, - MINERU_API_URL=request.app.state.config.MINERU_API_URL, - MINERU_API_KEY=request.app.state.config.MINERU_API_KEY, - MINERU_API_TIMEOUT=request.app.state.config.MINERU_API_TIMEOUT, - MINERU_PARAMS=request.app.state.config.MINERU_PARAMS, - ) + loader = build_loader_from_config(request) + loader.user = user docs = await loader.aload(file.filename, file.meta.get('content_type'), file_path) docs = [ From 6cc799b1bbc77a3ec3d1484abd0d95b41a5baca7 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 15:52:00 +0900 Subject: [PATCH 345/404] chore: format --- CHANGELOG.md | 2 +- backend/open_webui/internal/db.py | 20 +++++------ backend/open_webui/models/calendar.py | 2 -- backend/open_webui/retrieval/utils.py | 4 +-- backend/open_webui/routers/calendar.py | 4 +-- backend/open_webui/routers/configs.py | 16 ++++++--- backend/open_webui/routers/functions.py | 4 ++- backend/open_webui/routers/tools.py | 4 ++- backend/open_webui/utils/files.py | 36 ++++++++----------- backend/open_webui/utils/tools.py | 8 +++-- .../calendar/CalendarSidebar.svelte | 11 +++--- src/lib/components/chat/Chat.svelte | 13 ++----- src/lib/components/chat/MessageInput.svelte | 4 ++- src/lib/i18n/locales/ar-BH/translation.json | 23 ++++++++++++ src/lib/i18n/locales/ar/translation.json | 23 ++++++++++++ src/lib/i18n/locales/az-AZ/translation.json | 19 ++++++++++ src/lib/i18n/locales/bg-BG/translation.json | 19 ++++++++++ src/lib/i18n/locales/bn-BD/translation.json | 19 ++++++++++ src/lib/i18n/locales/bo-TB/translation.json | 18 ++++++++++ src/lib/i18n/locales/bs-BA/translation.json | 20 +++++++++++ src/lib/i18n/locales/ca-ES/translation.json | 20 +++++++++++ src/lib/i18n/locales/ceb-PH/translation.json | 19 ++++++++++ src/lib/i18n/locales/cs-CZ/translation.json | 21 +++++++++++ src/lib/i18n/locales/da-DK/translation.json | 19 ++++++++++ src/lib/i18n/locales/de-DE/translation.json | 19 ++++++++++ src/lib/i18n/locales/dg-DG/translation.json | 19 ++++++++++ src/lib/i18n/locales/el-GR/translation.json | 19 ++++++++++ src/lib/i18n/locales/en-GB/translation.json | 19 ++++++++++ src/lib/i18n/locales/en-US/translation.json | 19 ++++++++++ src/lib/i18n/locales/es-ES/translation.json | 20 +++++++++++ src/lib/i18n/locales/et-EE/translation.json | 19 ++++++++++ src/lib/i18n/locales/eu-ES/translation.json | 19 ++++++++++ src/lib/i18n/locales/fa-IR/translation.json | 19 ++++++++++ src/lib/i18n/locales/fi-FI/translation.json | 19 ++++++++++ src/lib/i18n/locales/fr-CA/translation.json | 20 +++++++++++ src/lib/i18n/locales/fr-FR/translation.json | 20 +++++++++++ src/lib/i18n/locales/gl-ES/translation.json | 19 ++++++++++ src/lib/i18n/locales/he-IL/translation.json | 20 +++++++++++ src/lib/i18n/locales/hi-IN/translation.json | 19 ++++++++++ src/lib/i18n/locales/hr-HR/translation.json | 20 +++++++++++ src/lib/i18n/locales/hu-HU/translation.json | 19 ++++++++++ src/lib/i18n/locales/id-ID/translation.json | 18 ++++++++++ src/lib/i18n/locales/ie-GA/translation.json | 19 ++++++++++ src/lib/i18n/locales/it-IT/translation.json | 20 +++++++++++ src/lib/i18n/locales/ja-JP/translation.json | 18 ++++++++++ src/lib/i18n/locales/ka-GE/translation.json | 19 ++++++++++ src/lib/i18n/locales/kab-DZ/translation.json | 19 ++++++++++ src/lib/i18n/locales/ko-KR/translation.json | 18 ++++++++++ src/lib/i18n/locales/lt-LT/translation.json | 21 +++++++++++ src/lib/i18n/locales/lv-LV/translation.json | 20 +++++++++++ src/lib/i18n/locales/ms-MY/translation.json | 18 ++++++++++ src/lib/i18n/locales/nb-NO/translation.json | 19 ++++++++++ src/lib/i18n/locales/nl-NL/translation.json | 19 ++++++++++ src/lib/i18n/locales/pa-IN/translation.json | 19 ++++++++++ src/lib/i18n/locales/pl-PL/translation.json | 21 +++++++++++ src/lib/i18n/locales/pt-BR/translation.json | 20 +++++++++++ src/lib/i18n/locales/pt-PT/translation.json | 20 +++++++++++ src/lib/i18n/locales/ro-RO/translation.json | 20 +++++++++++ src/lib/i18n/locales/ru-RU/translation.json | 21 +++++++++++ src/lib/i18n/locales/sk-SK/translation.json | 21 +++++++++++ src/lib/i18n/locales/sr-RS/translation.json | 20 +++++++++++ src/lib/i18n/locales/sv-SE/translation.json | 19 ++++++++++ src/lib/i18n/locales/ta-IN/translation.json | 19 ++++++++++ src/lib/i18n/locales/th-TH/translation.json | 18 ++++++++++ src/lib/i18n/locales/tk-TM/translation.json | 19 ++++++++++ src/lib/i18n/locales/tr-TR/translation.json | 19 ++++++++++ src/lib/i18n/locales/ug-CN/translation.json | 19 ++++++++++ src/lib/i18n/locales/uk-UA/translation.json | 21 +++++++++++ src/lib/i18n/locales/ur-PK/translation.json | 19 ++++++++++ .../i18n/locales/uz-Cyrl-UZ/translation.json | 19 ++++++++++ .../i18n/locales/uz-Latn-Uz/translation.json | 19 ++++++++++ src/lib/i18n/locales/vi-VN/translation.json | 18 ++++++++++ src/lib/i18n/locales/zh-CN/translation.json | 18 ++++++++++ src/lib/i18n/locales/zh-TW/translation.json | 18 ++++++++++ 74 files changed, 1244 insertions(+), 67 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47f6a27199..7d5f34d74f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -214,7 +214,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 📝 **Writing block parsing reliability.** ":::writing" blocks now parse more reliably when headers or extra inline text are present, preventing malformed rendering and duplicate output artifacts. [#23174](https://github.com/open-webui/open-webui/issues/23174) - 🧾 **Code block line break reliability.** Blank lines in submitted code blocks are now preserved more reliably instead of being collapsed. [Commit](https://github.com/open-webui/open-webui/commit/1be9627dd27ffe75957729a4a0d1682a98684f01), [#20302](https://github.com/open-webui/open-webui/issues/20302), [#23451](https://github.com/open-webui/open-webui/pull/23451) - ✂️ **Citation spacing cleanup.** When citations are disabled for a model, citation markers and their leftover spacing are now removed together so punctuation and copied text remain cleanly formatted. [#23141](https://github.com/open-webui/open-webui/issues/23141) -- 🧰 **Pipe tool access.** Pipe functions now receive built-in and MCP tools in __tools__, so tools like Web Search and code execution are available when enabled. [#23365](https://github.com/open-webui/open-webui/issues/23365) +- 🧰 **Pipe tool access.** Pipe functions now receive built-in and MCP tools in **tools**, so tools like Web Search and code execution are available when enabled. [#23365](https://github.com/open-webui/open-webui/issues/23365) - 📚 **Batch file processing database handling.** Batch knowledge file processing now consistently uses the active database session, preventing failures caused by missing database context during file ownership checks and update writes. [#23137](https://github.com/open-webui/open-webui/issues/23137) - ⚙️ **Default model parameter loading.** The "DEFAULT_MODEL_PARAMS" environment variable is now parsed and applied correctly, so default generation settings are honored reliably without being ignored at startup. [#23223](https://github.com/open-webui/open-webui/pull/23223) - 🔧 **Web search settings save reliability.** Saving web search configuration now works without server errors, so administrators can update "WEB_FETCH_MAX_CONTENT_LENGTH" and related retrieval settings successfully from the admin interface. [Commit](https://github.com/open-webui/open-webui/commit/36d02aa1477aa1b4e7fb59d022f99693ebfa8667), [#23127](https://github.com/open-webui/open-webui/issues/23127) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index e3b4a110cd..25aa94591b 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -56,10 +56,7 @@ def extract_ssl_mode_from_url(url: str) -> tuple[str, str | None]: Non-PostgreSQL URLs are returned unchanged with ``ssl_mode=None``. """ - if not url or not any( - url.startswith(prefix) - for prefix in ('postgresql://', 'postgresql+', 'postgres://') - ): + if not url or not any(url.startswith(prefix) for prefix in ('postgresql://', 'postgresql+', 'postgres://')): return url, None parsed = urlparse(url) @@ -126,7 +123,6 @@ def reattach_ssl_mode_to_url(url_without_ssl: str, ssl_mode: str | None) -> str: return f'{url_without_ssl}{separator}sslmode={ssl_mode}' - class JSONField(types.TypeDecorator): impl = types.Text cache_ok = True @@ -188,7 +184,9 @@ if ENABLE_DB_MIGRATIONS: DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE = extract_ssl_mode_from_url(DATABASE_URL) # For psycopg2 (sync engine), re-append sslmode=. -SQLALCHEMY_DATABASE_URL = reattach_ssl_mode_to_url(DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE) if DATABASE_SSL_MODE else DATABASE_URL +SQLALCHEMY_DATABASE_URL = ( + reattach_ssl_mode_to_url(DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE) if DATABASE_SSL_MODE else DATABASE_URL +) def _make_async_url(url: str) -> str: @@ -332,15 +330,13 @@ get_db = contextmanager(get_session) # ============================================================ # Use the SSL-stripped URL for asyncpg — SSL is injected via connect_args. -ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url(DATABASE_URL_WITHOUT_SSL if DATABASE_SSL_MODE else SQLALCHEMY_DATABASE_URL) +ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url( + DATABASE_URL_WITHOUT_SSL if DATABASE_SSL_MODE else SQLALCHEMY_DATABASE_URL +) if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: # Generous default — async coroutines + no session sharing = high connection demand. - _sqlite_pool_size = ( - DATABASE_POOL_SIZE - if isinstance(DATABASE_POOL_SIZE, int) and DATABASE_POOL_SIZE > 0 - else 512 - ) + _sqlite_pool_size = DATABASE_POOL_SIZE if isinstance(DATABASE_POOL_SIZE, int) and DATABASE_POOL_SIZE > 0 else 512 async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, connect_args={'check_same_thread': False}, diff --git a/backend/open_webui/models/calendar.py b/backend/open_webui/models/calendar.py index dbb070013e..47f0a6f722 100644 --- a/backend/open_webui/models/calendar.py +++ b/backend/open_webui/models/calendar.py @@ -307,8 +307,6 @@ class CalendarTable: cal = result.scalars().first() return await self._to_calendar_model(cal, db=db) if cal else None - - async def insert_new_calendar( self, user_id: str, form_data: CalendarForm, db: Optional[AsyncSession] = None ) -> Optional[CalendarModel]: diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index cafb8fe4f0..b9bfcc12c8 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -122,9 +122,7 @@ def build_loader_from_config(request): ) -def _extract_text_from_binary_response( - request, response: requests.Response, url: str -) -> tuple[str, list]: +def _extract_text_from_binary_response(request, response: requests.Response, url: str) -> tuple[str, list]: """Download response body to a temp file and extract text using the Loader pipeline.""" import mimetypes import tempfile diff --git a/backend/open_webui/routers/calendar.py b/backend/open_webui/routers/calendar.py index 152b932234..c95888ebfa 100644 --- a/backend/open_webui/routers/calendar.py +++ b/backend/open_webui/routers/calendar.py @@ -55,9 +55,7 @@ async def _user_has_automations(request: Request, user) -> bool: return False if user.role == 'admin': return True - return await has_permission( - user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS - ) + return await has_permission(user.id, 'features.automations', request.app.state.config.USER_PERMISSIONS) async def _check_calendar_access(calendar_id: str, user: UserModel, permission: str = 'write') -> CalendarModel: diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 68e1d129dc..02b16d8e5b 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -293,7 +293,9 @@ async def verify_terminal_server_connection( ) as session: # Orchestrators expose a policies API; plain terminals don't. try: - async with session.get(f'{base_url}/api/v1/policies', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + async with session.get( + f'{base_url}/api/v1/policies', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.ok: return {'status': True, 'type': 'orchestrator'} except Exception: @@ -301,7 +303,9 @@ async def verify_terminal_server_connection( # Fall back to open-terminal config endpoint. try: - async with session.get(f'{base_url}/api/config', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + async with session.get( + f'{base_url}/api/config', headers=headers, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.ok: return {'status': True, 'type': 'terminal'} except Exception: @@ -342,7 +346,9 @@ async def put_terminal_server_policy( timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), ) as session: policy_url = f'{base_url}/api/v1/policies/{form_data.policy_id}' - async with session.put(policy_url, headers=headers, json=form_data.policy_data, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + async with session.put( + policy_url, headers=headers, json=form_data.policy_data, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.ok: return await resp.json() detail = await resp.text() @@ -369,7 +375,9 @@ async def verify_tool_servers_config(request: Request, form_data: ToolServerConn trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), ) as session: - async with session.get(discovery_url, ssl=AIOHTTP_CLIENT_SESSION_SSL) as oauth_server_metadata_response: + async with session.get( + discovery_url, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as oauth_server_metadata_response: if oauth_server_metadata_response.status == 200: try: oauth_server_metadata = OAuthMetadata.model_validate( diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index baec1f0870..f40cd1ab82 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -117,7 +117,9 @@ async def load_function_from_url(request: Request, form_data: LoadUrlForm, user= async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.get(url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + async with session.get( + url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status != 200: raise HTTPException(status_code=resp.status, detail='Failed to fetch the function') data = await resp.text() diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index 4c3e77e566..04d845c3de 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -274,7 +274,9 @@ async def load_tool_from_url(request: Request, form_data: LoadUrlForm, user=Depe async with aiohttp.ClientSession( trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) ) as session: - async with session.get(url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + async with session.get( + url, headers={'Content-Type': 'application/json'}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status != 200: raise HTTPException(status_code=resp.status, detail='Failed to fetch the tool') data = await resp.text() diff --git a/backend/open_webui/utils/files.py b/backend/open_webui/utils/files.py index 7d0d9da2c2..8149987fe4 100644 --- a/backend/open_webui/utils/files.py +++ b/backend/open_webui/utils/files.py @@ -34,19 +34,19 @@ MARKDOWN_IMAGE_URL_PATTERN = re.compile(r'!\[(.*?)\]\((.+?)\)', re.IGNORECASE) # Extension-based MIME fallback, only used when ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK is True. _IMAGE_MIME_FALLBACK = { - ".webp": "image/webp", - ".png": "image/png", - ".jpg": "image/jpeg", - ".jpeg": "image/jpeg", - ".gif": "image/gif", - ".svg": "image/svg+xml", - ".bmp": "image/bmp", - ".tiff": "image/tiff", - ".tif": "image/tiff", - ".ico": "image/x-icon", - ".heic": "image/heic", - ".heif": "image/heif", - ".avif": "image/avif", + '.webp': 'image/webp', + '.png': 'image/png', + '.jpg': 'image/jpeg', + '.jpeg': 'image/jpeg', + '.gif': 'image/gif', + '.svg': 'image/svg+xml', + '.bmp': 'image/bmp', + '.tiff': 'image/tiff', + '.tif': 'image/tiff', + '.ico': 'image/x-icon', + '.heic': 'image/heic', + '.heif': 'image/heif', + '.avif': 'image/avif', } @@ -75,10 +75,7 @@ async def get_image_base64_from_url(url: str) -> Optional[str]: if file_path.is_file(): with open(file_path, 'rb') as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') - content_type = ( - mimetypes.guess_type(file_path.name)[0] - or (file.meta or {}).get('content_type') - ) + content_type = mimetypes.guess_type(file_path.name)[0] or (file.meta or {}).get('content_type') if not content_type and ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK: content_type = _IMAGE_MIME_FALLBACK.get(file_path.suffix.lower()) if not content_type: @@ -204,10 +201,7 @@ async def get_image_base64_from_file_id(id: str) -> Optional[str]: if file_path.is_file(): with open(file_path, 'rb') as image_file: encoded_string = base64.b64encode(image_file.read()).decode('utf-8') - content_type = ( - mimetypes.guess_type(file_path.name)[0] - or (file.meta or {}).get('content_type') - ) + content_type = mimetypes.guess_type(file_path.name)[0] or (file.meta or {}).get('content_type') if not content_type and ENABLE_IMAGE_CONTENT_TYPE_EXTENSION_FALLBACK: content_type = _IMAGE_MIME_FALLBACK.get(file_path.suffix.lower()) if not content_type: diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 3f4eac7e91..9f3ab0bce4 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -908,7 +908,9 @@ async def get_terminal_cwd( timeout=aiohttp.ClientTimeout(total=5), trust_env=True, ) as session: - async with session.get(cwd_url, headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + async with session.get( + cwd_url, headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status == 200: data = await resp.json() return data.get('cwd') @@ -943,7 +945,9 @@ async def get_terminal_system_prompt( return None # 2. Fetch system prompt - async with session.get(f'{base}/system', headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL) as resp: + async with session.get( + f'{base}/system', headers=headers, cookies=cookies or {}, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resp: if resp.status == 200: data = await resp.json() return data.get('prompt') diff --git a/src/lib/components/calendar/CalendarSidebar.svelte b/src/lib/components/calendar/CalendarSidebar.svelte index 76d762760a..d3ea51a472 100644 --- a/src/lib/components/calendar/CalendarSidebar.svelte +++ b/src/lib/components/calendar/CalendarSidebar.svelte @@ -94,7 +94,10 @@ @@ -219,11 +222,7 @@ stroke="currentColor" class="size-3" > - + {/if} diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index fbd91e512c..03af994a68 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -757,10 +757,7 @@ const selectedFolderSubscribe = selectedFolder.subscribe(async (folder) => { await tick(); - if ( - folder?.data?.model_ids && - !equal(selectedModels, folder.data.model_ids) - ) { + if (folder?.data?.model_ids && !equal(selectedModels, folder.data.model_ids)) { selectedModels = folder.data.model_ids; console.log('Set selectedModels from folder data:', selectedModels); @@ -1836,8 +1833,7 @@ ); chatFiles = chatFiles.filter( // Remove duplicates - (item, index, array) => - array.findIndex((i) => equal(i, item)) === index + (item, index, array) => array.findIndex((i) => equal(i, item)) === index ); // Create user message @@ -2176,10 +2172,7 @@ ) ); // Remove duplicates - files = files.filter( - (item, index, array) => - array.findIndex((i) => equal(i, item)) === index - ); + files = files.filter((item, index, array) => array.findIndex((i) => equal(i, item)) === index); scrollToBottom(); eventTarget.dispatchEvent( diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index aeb96af5b0..11cd749987 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -1941,7 +1941,9 @@ {#if !history?.currentId || history.messages[history.currentId]?.done == true} - {@const hasDirectToolServerAccess = $_user?.role === 'admin' || ($_user?.permissions?.features?.direct_tool_servers ?? true)} + {@const hasDirectToolServerAccess = + $_user?.role === 'admin' || + ($_user?.permissions?.features?.direct_tool_servers ?? true)} {#if terminalCapableModels.length > 0 && (($terminalServers ?? []).some((t) => t.id) || (hasDirectToolServerAccess && (($terminalServers ?? []).some((t) => !t.id) || ($settings?.terminalServers ?? []).some((s) => s.url))))} {/if} diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index 1b4ff02105..13e9aed4e9 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -37,8 +37,13 @@ "{{user}}'s Chats": "دردشات {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} مطلوب", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -206,6 +211,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -280,6 +286,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -417,6 +424,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "اتصالات", @@ -529,6 +537,8 @@ "Delete All Chats": "حذف جميع الدردشات", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "حذف المحادثه.", "Delete chat?": "", "Delete Event": "", @@ -890,6 +900,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "فشل في إنشاء مفتاح API.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1629,6 +1640,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "سجل صوت", "Redirecting you to Open WebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ", @@ -1652,6 +1664,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "إزالة", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1902,7 +1915,15 @@ "Start a new conversation": "", "Start of the channel": "بداية القناة", "Start Tag": "", + "Starting in {{count}} minutes_zero": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_two": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2015,6 +2036,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "شرح شامل", "Thought": "", @@ -2101,6 +2123,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/ar/translation.json b/src/lib/i18n/locales/ar/translation.json index 49a3c5be10..3eb53e68bd 100644 --- a/src/lib/i18n/locales/ar/translation.json +++ b/src/lib/i18n/locales/ar/translation.json @@ -37,8 +37,13 @@ "{{user}}'s Chats": "محادثات المستخدم {{user}}", "{{webUIName}} Backend Required": "يتطلب الخلفية الخاصة بـ {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*معرّف/معرّفات عقدة الموجه مطلوبة لتوليد الصور", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "يتوفر الآن إصدار جديد (v{{LATEST_VERSION}}).", @@ -206,6 +211,7 @@ "Ask a question": "اطرح سؤالاً", "Assistant": "المساعد", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -280,6 +286,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "التقويم", + "Calendar deleted": "", "Calendars": "", "Call": "مكالمة", "Call feature is not supported when using Web STT engine": "ميزة الاتصال غير مدعومة عند استخدام محرك Web STT", @@ -417,6 +424,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "الاتصالات", @@ -529,6 +537,8 @@ "Delete All Chats": "حذف جميع الدردشات", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "حذف المحادثه.", "Delete chat?": "هل تريد حذف المحادثة؟", "Delete Event": "", @@ -890,6 +900,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "فشل في إنشاء مفتاح API.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1629,6 +1640,7 @@ "Reasoning Effort": "جهد الاستدلال", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "سجل صوت", "Redirecting you to Open WebUI Community": "OpenWebUI إعادة توجيهك إلى مجتمع ", @@ -1652,6 +1664,7 @@ "Relevance": "الصلة", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "إزالة", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1902,7 +1915,15 @@ "Start a new conversation": "", "Start of the channel": "بداية القناة", "Start Tag": "", + "Starting in {{count}} minutes_zero": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_two": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2015,6 +2036,7 @@ "This will delete {{NAME}} and all its contents.": "هذا سيحذف {{NAME}} وكل محتوياته.", "This will delete all models including custom models": "هذا سيحذف جميع النماذج بما في ذلك النماذج المخصصة", "This will delete all models including custom models and cannot be undone.": "هذا سيحذف جميع النماذج بما في ذلك المخصصة ولا يمكن التراجع عن هذا الإجراء.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "هذا سيؤدي إلى إعادة تعيين قاعدة المعرفة ومزامنة جميع الملفات. هل ترغب في المتابعة؟", "Thorough explanation": "شرح شامل", "Thought": "", @@ -2101,6 +2123,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "اكشف الأسرار", "Unpin": "إزالة التثبيت", + "Unpin from Sidebar": "", "Unravel secrets": "فكّ الأسرار", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/az-AZ/translation.json b/src/lib/i18n/locales/az-AZ/translation.json index 9e316d538d..8eec5e5732 100644 --- a/src/lib/i18n/locales/az-AZ/translation.json +++ b/src/lib/i18n/locales/az-AZ/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} adlı istifadəçinin söhbətləri", "{{webUIName}} Backend Required": "{{webUIName}} üçün Backend tələb olunur", "*Prompt node ID(s) are required for image generation": "*Şəkil yaradılması üçün sorğu (prompt) qovşaq ID-ləri tələb olunur", + "1 hour before": "", "1 Source": "1 Mənbə", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 dəq əvvəl", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "İnsanların üzv kimi qoşulduğu əməkdaşlıq kanalı", "A discussion channel where access is controlled by groups and permissions": "Girişin qruplar və icazələrlə idarə olunduğu müzakirə kanalı", "A new version (v{{LATEST_VERSION}}) is now available.": "Yeni versiya (v{{LATEST_VERSION}}) artıq mövcuddur.", @@ -202,6 +207,7 @@ "Ask a question": "Sual verin", "Assistant": "Köməkçi", "Async Embedding Processing": "Asinxron Yerləşdirmə (Embedding) Emalı", + "At time of event": "", "Attach File From Knowledge": "Bilik bazasından fayl əlavə et", "Attach Files": "", "Attach Knowledge": "Bilik əlavə et", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Veb Yükləyicidən Yan Keç", "Cache Base Model List": "Əsas Model Siyahısını Keşlə", "Calendar": "Təqvim", + "Calendar deleted": "", "Calendars": "", "Call": "Zəng", "Call feature is not supported when using Web STT engine": "Veb STT mühərriki istifadə edildikdə zəng funksiyası dəstəklənmir", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Öz OpenAPI uyğun xarici alət serverlərinizə qoşulun.", "Connected ({{type}})": "", "Connection failed": "Bağlantı uğursuz oldu", + "Connection lost. Reconnecting...": "", "Connection successful": "Bağlantı uğurludur", "Connection Type": "Bağlantı növü", "Connections": "Bağlantılar", @@ -525,6 +533,8 @@ "Delete All Chats": "Bütün çatları sil", "Delete all contents inside this folder": "Bu qovluğun daxilindəki bütün məzmunu sil", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Çatı sil", "Delete chat?": "Çat silinsin?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "{{URL}} terminal serverinə qoşulmaq mümkün olmadı", "Failed to copy link": "Link kopyalanmadı", "Failed to create API Key.": "API açarı yaradılmadı.", + "Failed to delete calendar": "", "Failed to delete note": "Qeyd silinmədi", "Failed to download image": "Şəkil yüklənmədi", "Failed to extract content from the file: {{error}}": "Fayldan məzmun çıxarıla bilmədi: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Mühakimə səyi", "Reasoning Tags": "Mühakimə etiketləri", "Recently Used": "", + "Reconnected": "", "Record": "Yaz (səs)", "Record voice": "Səsi yaz", "Redirecting you to Open WebUI Community": "Open WebUI İcmasına yönləndirilirsiniz", @@ -1648,6 +1660,7 @@ "Relevance": "Uyğunluq", "Relevance Threshold": "Uyğunluq həddi", "Remember Dismissal": "İmtinanı yadda saxla", + "Reminder": "", "Remove": "Çıxar", "Remove {{MODELID}} from list.": "{{MODELID}} siyahıdan çıxarılsın.", "Remove action": "Əməliyyatı çıxar", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Yeni söhbətə başlayın", "Start of the channel": "Kanalın başlanğıcı", "Start Tag": "Start Tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Starting kernel...", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status uğurla təmizləndi", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Bu, {{NAME}} adlı elementi və onun bütün məzmununu siləcək.", "This will delete all models including custom models": "Bu, fərdi modellər də daxil olmaqla bütün modelləri siləcək", "This will delete all models including custom models and cannot be undone.": "Bu, fərdi modellər də daxil olmaqla bütün modelləri siləcək və geri qaytarıla bilməz.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Bu, bilik bazasını sıfırlayacaq və bütün faylları sinxronizasiya edəcək. Davam etmək istəyirsiniz?", "Thorough explanation": "Ətraflı izahat", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} sonra yaddaşdan silinir", "Unlock mysteries": "Sirrləri açın", "Unpin": "Sabitlənmişdən çıxar", + "Unpin from Sidebar": "", "Unravel secrets": "Gizlinləri üzə çıxarın", "Unshare Chat": "Çatı paylaşımı dayandır", "Unsupported file type.": "Dəstəklənməyən fayl növü.", diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index 51dbe73be0..685debf883 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'s чатове", "{{webUIName}} Backend Required": "{{webUIName}} Изисква се Бекенд", "*Prompt node ID(s) are required for image generation": "*Идентификатор(ите) на възел-а се изисква(т) за генериране на изображения", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Вече е налична нова версия (v{{LATEST_VERSION}}).", @@ -202,6 +207,7 @@ "Ask a question": "Задайте въпрос", "Assistant": "Асистент", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Календар", + "Calendar deleted": "", "Calendars": "", "Call": "Обаждане", "Call feature is not supported when using Web STT engine": "Функцията за обаждане не се поддържа при използването на Web STT двигател", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Връзки", @@ -525,6 +533,8 @@ "Delete All Chats": "Изтриване на всички чатове", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Изтриване на Чат", "Delete chat?": "Изтриване на чата?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Неуспешно създаване на API ключ.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Усилие за разсъждение", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Запиши", "Record voice": "Записване на глас", "Redirecting you to Open WebUI Community": "Пренасочване към OpenWebUI общността", @@ -1648,6 +1660,7 @@ "Relevance": "Релевантност", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Изтриване", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Начало на канала", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Това ще изтрие {{NAME}} и цялото му съдържание.", "This will delete all models including custom models": "Това ще изтрие всички модели, включително персонализираните модели", "This will delete all models including custom models and cannot be undone.": "Това ще изтрие всички модели, включително персонализираните модели, и не може да бъде отменено.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Това ще нулира базата знания и ще синхронизира всички файлове. Желаете ли да продължите?", "Thorough explanation": "Подробно обяснение", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Разкрий мистерии", "Unpin": "Откачи", + "Unpin from Sidebar": "", "Unravel secrets": "Разгадай тайни", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index 5a1589d3b4..9437c8a347 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}র চ্যাটস", "{{webUIName}} Backend Required": "{{webUIName}} ব্যাকএন্ড আবশ্যক", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "কানেকশনগুলো", @@ -525,6 +533,8 @@ "Delete All Chats": "সব চ্যাট মুছে ফেলুন", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "চ্যাট মুছে ফেলুন", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API Key তৈরি করা যায়নি।", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "ভয়েস রেকর্ড করুন", "Redirecting you to Open WebUI Community": "আপনাকে OpenWebUI কমিউনিটিতে পাঠানো হচ্ছে", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "রিমুভ করুন", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "চ্যানেলের শুরু", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "পুঙ্খানুপুঙ্খ ব্যাখ্যা", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/bo-TB/translation.json b/src/lib/i18n/locales/bo-TB/translation.json index c7f3716239..a65771c7b5 100644 --- a/src/lib/i18n/locales/bo-TB/translation.json +++ b/src/lib/i18n/locales/bo-TB/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} ཡི་ཁ་བརྡ།", "{{webUIName}} Backend Required": "{{webUIName}} རྒྱབ་སྣེ་དགོས།", "*Prompt node ID(s) are required for image generation": "*པར་བཟོའི་ཆེད་དུ་འགུལ་སློང་མདུད་ཚེག་གི་ ID(s) དགོས།", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "པར་གཞི་གསར་པ། (v{{LATEST_VERSION}}) ད་ལྟ་ཡོད།", @@ -201,6 +206,7 @@ "Ask a question": "དྲི་བ་ཞིག་འདྲི་བ།", "Assistant": "ལག་རོགས་པ།", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -275,6 +281,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "ལོ་ཐོ།", + "Calendar deleted": "", "Calendars": "", "Call": "སྐད་འབོད།", "Call feature is not supported when using Web STT engine": "Web STT མ་ལག་སྤྱོད་སྐབས་སྐད་འབོད་ཀྱི་ཁྱད་ཆོས་ལ་རྒྱབ་སྐྱོར་མེད།", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "ཁྱེད་རང་གི་ OpenAPI དང་མཐུན་པའི་ཕྱི་རོལ་ལག་ཆའི་སར་བར་ལ་སྦྲེལ་བ།", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "སྦྲེལ་མཐུད།", @@ -524,6 +532,8 @@ "Delete All Chats": "ཁ་བརྡ་ཡོངས་རྫོགས་བསུབ་པ།", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "ཁ་བརྡ་བསུབ་པ།", "Delete chat?": "ཁ་བརྡ་བསུབ་པ།?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API ལྡེ་མིག་བཟོ་མ་ཐུབ།", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "རྒྱུ་མཚན་འདྲེན་པའི་འབད་བརྩོན།", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "སྐད་སྒྲ་ཕབ་པ།", "Redirecting you to Open WebUI Community": "ཁྱེད་ Open WebUI སྤྱི་ཚོགས་ལ་ཁ་ཕྱོགས་སྒྱུར་བཞིན་པ།", @@ -1647,6 +1659,7 @@ "Relevance": "འབྲེལ་ཡོད་རང་བཞིན།", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "འདོར་བ།", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1892,7 +1905,10 @@ "Start a new conversation": "", "Start of the channel": "རྒྱས་ལམ་འགོ་རིམ་", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "འདིས་ {{NAME}} དང་ དེའི་ནང་དོན་ཡོངས་རྫོགས་ བསུབ་ངེས།", "This will delete all models including custom models": "འདིས་སྲོལ་བཟོས་དཔེ་དབྱིབས་ཚུད་པའི་དཔེ་དབྱིབས་ཡོངས་རྫོགས་བསུབ་ངེས།", "This will delete all models including custom models and cannot be undone.": "འདིས་སྲོལ་བཟོས་དཔེ་དབྱིབས་ཚུད་པའི་དཔེ་དབྱིབས་ཡོངས་རྫོགས་བསུབ་ངེས་པ་དང་ཕྱིར་ལྡོག་བྱེད་མི་ཐུབ།", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "འདིས་ཤེས་བྱའི་རྟེན་གཞི་སླར་སྒྲིག་བྱས་ནས་ཡིག་ཆ་ཡོངས་རྫོགས་མཉམ་སྡེབ་བྱེད་ངེས། ཁྱེད་མུ་མཐུད་འདོད་ཡོད་དམ།", "Thorough explanation": "འགྲེལ་བཤད་ཞིབ་ཚགས།", "Thought": "", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "གསང་བ་གྲོལ་བ།", "Unpin": "ཕྱིར་འདོན།", + "Unpin from Sidebar": "", "Unravel secrets": "གསང་བ་གྲོལ་བ།", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/bs-BA/translation.json b/src/lib/i18n/locales/bs-BA/translation.json index 3316f8c4a7..d28abefd59 100644 --- a/src/lib/i18n/locales/bs-BA/translation.json +++ b/src/lib/i18n/locales/bs-BA/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Razgovori korisnika {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend je potreban", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -203,6 +208,7 @@ "Ask a question": "Pitaj pitanje", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Prikazi znanje", @@ -277,6 +283,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Poziv", "Call feature is not supported when using Web STT engine": "Značajka poziva nije podržana kada se koristi Web STT mehanizam", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "Konekcija nije uspjela", + "Connection lost. Reconnecting...": "", "Connection successful": "Konekcija uspjesna", "Connection Type": "Tip Konekcije", "Connections": "Povezivanja", @@ -526,6 +534,8 @@ "Delete All Chats": "Izbriši sve razgovore", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Izbriši razgovor", "Delete chat?": "", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Neuspješno stvaranje API ključa.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Snimanje glasa", "Redirecting you to Open WebUI Community": "Preusmjeravanje na OpenWebUI zajednicu", @@ -1649,6 +1661,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Ukloni", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Početak kanala", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Detaljno objašnjenje", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index add558aebf..a3793e5e42 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Els xats de {{user}}", "{{webUIName}} Backend Required": "El Backend de {{webUIName}} és necessari", "*Prompt node ID(s) are required for image generation": "*Els identificadors de nodes d'indicacions són necessaris per a la generació d'imatges", + "1 hour before": "", "1 Source": "1 font", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m_time_ago", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Un canal de col·laboració on la gent s'uneix com a membres", "A discussion channel where access is controlled by groups and permissions": "Un canal de discussió on l'accés està controlat per grups i permisos", "A new version (v{{LATEST_VERSION}}) is now available.": "Hi ha una nova versió disponible (v{{LATEST_VERSION}}).", @@ -203,6 +208,7 @@ "Ask a question": "Fer una pregunta", "Assistant": "Assistent", "Async Embedding Processing": "Procés d'incrustat asíncron", + "At time of event": "", "Attach File From Knowledge": "Adjuntar arxiu del coneixement", "Attach Files": "Adjuntar arxius", "Attach Knowledge": "Adjuntar coneixement", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Ometre el càrregador web", "Cache Base Model List": "Llista de models base en memòria cau", "Calendar": "Calendari", + "Calendar deleted": "", "Calendars": "", "Call": "Trucada", "Call feature is not supported when using Web STT engine": "La funció de trucada no s'admet quan s'utilitza el motor Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connecta als teus propis servidors d'eines externs compatibles amb OpenAPI", "Connected ({{type}})": "Connectat ({{type}})", "Connection failed": "La connexió ha fallat", + "Connection lost. Reconnecting...": "", "Connection successful": "Connexió correcta", "Connection Type": "Tipus de connexió", "Connections": "Connexions", @@ -526,6 +534,8 @@ "Delete All Chats": "Eliminar tots els xats", "Delete all contents inside this folder": "Eliminar tot el contingut d'aquesta carpeta", "Delete automation?": "Eliminar l'automatització", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Eliminar xat", "Delete chat?": "Eliminar el xat?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "No s'ha pogut connecta al servidor de terminal {{URL}}", "Failed to copy link": "No s'ha pogut copiar l'enllaç", "Failed to create API Key.": "No s'ha pogut crear la clau API.", + "Failed to delete calendar": "", "Failed to delete note": "No s'ha pogut eliminar la nota", "Failed to download image": "No s'ha pogut descarregar la imatge", "Failed to extract content from the file: {{error}}": "No s'ha pogut extreure el contingut del fitxer: {{error}}", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Esforç de raonament", "Reasoning Tags": "Etiqueta de raonament", "Recently Used": "Recentment utilitzat", + "Reconnected": "", "Record": "Enregistrar", "Record voice": "Enregistrar la veu", "Redirecting you to Open WebUI Community": "Redirigint-te a la comunitat OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Rellevància", "Relevance Threshold": "Límit de rellevància", "Remember Dismissal": "Recordar la decisió de refutar", + "Reminder": "", "Remove": "Eliminar", "Remove {{MODELID}} from list.": "Eliminar {{MODELID}} de la llista", "Remove action": "Eliminar l'acció", @@ -1896,7 +1909,12 @@ "Start a new conversation": "Iniciar una nova conversa", "Start of the channel": "Inici del canal", "Start Tag": "Etiqueta d'inici", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciant el kernel...", + "Starting now": "", "State": "Estat", "Status": "Estat", "Status cleared successfully": "S'ha eliminat correctament el teu estat", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Això eliminarà {{NAME}} i tots els continguts.", "This will delete all models including custom models": "Això eliminarà tots els models incloent els personalitzats", "This will delete all models including custom models and cannot be undone.": "Això eliminarà tots els models incloent els personalitzats i no es pot desfer", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Això restablirà la base de coneixement i sincronitzarà tots els fitxers. Vols continuar?", "Thorough explanation": "Explicació en detall", "Thought": "Pensament", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Es descarrega {{FROM_NOW}}", "Unlock mysteries": "Desbloqueja els misteris", "Unpin": "Alliberar", + "Unpin from Sidebar": "", "Unravel secrets": "Descobreix els secrets", "Unshare Chat": "Deixar de compartir el xat", "Unsupported file type.": "Tipus no suportat", diff --git a/src/lib/i18n/locales/ceb-PH/translation.json b/src/lib/i18n/locales/ceb-PH/translation.json index db49608fee..d1278ac30b 100644 --- a/src/lib/i18n/locales/ceb-PH/translation.json +++ b/src/lib/i18n/locales/ceb-PH/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "Backend {{webUIName}} gikinahanglan", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Mga koneksyon", @@ -525,6 +533,8 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Irekord ang tingog", "Redirecting you to Open WebUI Community": "Gi-redirect ka sa komunidad sa OpenWebUI", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Sinugdan sa channel", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/cs-CZ/translation.json b/src/lib/i18n/locales/cs-CZ/translation.json index b2ec0ebb05..a787579837 100644 --- a/src/lib/i18n/locales/cs-CZ/translation.json +++ b/src/lib/i18n/locales/cs-CZ/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Konverzace uživatele {{user}}", "{{webUIName}} Backend Required": "Je vyžadován backend {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Pro generování obrázků jsou vyžadována ID uzlů instrukce", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Nová verze (v{{LATEST_VERSION}}) je nyní k dispozici.", @@ -204,6 +209,7 @@ "Ask a question": "Položit otázku", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Připojit znalosti", @@ -278,6 +284,7 @@ "Bypass Web Loader": "Obejít webový zavaděč", "Cache Base Model List": "Ukládat seznam základních modelů do mezipaměti", "Calendar": "Kalendář", + "Calendar deleted": "", "Calendars": "", "Call": "Volání", "Call feature is not supported when using Web STT engine": "Funkce volání není podporována při použití webového STT jádra.", @@ -415,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Připojte se k vlastním externím serverům nástrojů kompatibilním s OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Připojení se nezdařilo", + "Connection lost. Reconnecting...": "", "Connection successful": "Připojení úspěšné", "Connection Type": "Typ připojení", "Connections": "Připojení", @@ -527,6 +535,8 @@ "Delete All Chats": "Smazat všechny konverzace", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Smazat konverzaci", "Delete chat?": "Smazat konverzaci?", "Delete Event": "", @@ -888,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Nepodařilo se zkopírovat odkaz", "Failed to create API Key.": "Nepodařilo se vytvořit API klíč.", + "Failed to delete calendar": "", "Failed to delete note": "Nepodařilo se smazat poznámku", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Nepodařilo se extrahovat obsah ze souboru: {{error}}", @@ -1627,6 +1638,7 @@ "Reasoning Effort": "reasoning effort", "Reasoning Tags": "reasoning tags", "Recently Used": "", + "Reconnected": "", "Record": "Nahrát", "Record voice": "Nahrát hlas", "Redirecting you to Open WebUI Community": "Přesměrovávám vás do komunity Open WebUI", @@ -1650,6 +1662,7 @@ "Relevance": "Relevance", "Relevance Threshold": "Prahová hodnota relevance", "Remember Dismissal": "Pamatovat si zavření", + "Reminder": "", "Remove": "Odebrat", "Remove {{MODELID}} from list.": "Odebrat {{MODELID}} ze seznamu.", "Remove action": "", @@ -1898,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Začátek kanálu", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2011,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "Tím se smaže {{NAME}} a veškerý jeho obsah.", "This will delete all models including custom models": "Tím se smažou všechny modely včetně vlastních modelů", "This will delete all models including custom models and cannot be undone.": "Tím se smažou všechny modely včetně vlastních a tuto akci nelze vrátit zpět.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Tím se resetuje znalostní báze a synchronizují se všechny soubory. Přejete si pokračovat?", "Thorough explanation": "Důkladné vysvětlení", "Thought": "", @@ -2097,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "Uvolní se {{FROM_NOW}}", "Unlock mysteries": "Odhalte záhady", "Unpin": "Odepnout", + "Unpin from Sidebar": "", "Unravel secrets": "Rozplétejte tajemství", "Unshare Chat": "", "Unsupported file type.": "Nepodporovaný typ souboru.", diff --git a/src/lib/i18n/locales/da-DK/translation.json b/src/lib/i18n/locales/da-DK/translation.json index 09d336d179..cde38de62f 100644 --- a/src/lib/i18n/locales/da-DK/translation.json +++ b/src/lib/i18n/locales/da-DK/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}s chats", "{{webUIName}} Backend Required": "{{webUIName}} Backend kræves", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) er påkrævet for at kunne generere billeder", + "1 hour before": "", "1 Source": "1 kilde", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "En samarbejdskanal hvor folk tilmelder sig som medlemmer", "A discussion channel where access is controlled by groups and permissions": "En diskussionskanal hvor adgang styres af grupper og tilladelser", "A new version (v{{LATEST_VERSION}}) is now available.": "En ny version (v{{LATEST_VERSION}}) er nu tilgængelig.", @@ -202,6 +207,7 @@ "Ask a question": "Stil et spørgsmål", "Assistant": "Assistent", "Async Embedding Processing": "Asynkron embedding processering", + "At time of event": "", "Attach File From Knowledge": "Vedhæft fil fra viden", "Attach Files": "", "Attach Knowledge": "Vedhæft viden", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Omgå Web Loader", "Cache Base Model List": "Cache Base Model List", "Calendar": "Kalender", + "Calendar deleted": "", "Calendars": "", "Call": "Opkald", "Call feature is not supported when using Web STT engine": "Opkaldsfunktion er ikke understøttet for Web STT engine", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Opret forbindelse til dine egne OpenAPI kompatible eksterne værktøjsservere.", "Connected ({{type}})": "", "Connection failed": "Forbindelse mislykkedes", + "Connection lost. Reconnecting...": "", "Connection successful": "Forbindelse lykkedes", "Connection Type": "Forbindelsestype", "Connections": "Forbindelser", @@ -525,6 +533,8 @@ "Delete All Chats": "Slet alle chats", "Delete all contents inside this folder": "Slet alt indhold i denne mappe", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Slet chat", "Delete chat?": "Slet chat?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Kunne ikke kopiere link", "Failed to create API Key.": "Kunne ikke oprette API-nøgle.", + "Failed to delete calendar": "", "Failed to delete note": "Kunne ikke slette note", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Kunne ikke udtrække indhold fra filen: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Ræsonnements indsats", "Reasoning Tags": "Ræsonneringstags", "Recently Used": "", + "Reconnected": "", "Record": "Optag", "Record voice": "Optag stemme", "Redirecting you to Open WebUI Community": "Omdirigerer dig til OpenWebUI Community", @@ -1648,6 +1660,7 @@ "Relevance": "Relevans", "Relevance Threshold": "Relevans tærskel", "Remember Dismissal": "Husk afvisning", + "Reminder": "", "Remove": "Fjern", "Remove {{MODELID}} from list.": "Fjern {{MODELID}} fra listen.", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Start en ny samtale", "Start of the channel": "Kanalens start", "Start Tag": "Start tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status slettet", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dette vil slette {{NAME}} og alt dens indhold.", "This will delete all models including custom models": "Dette vil slette alle modeller, inklusive brugerdefinerede modeller", "This will delete all models including custom models and cannot be undone.": "Dette vil slette alle modeller, inklusive brugerdefinerede modeller og kan ikke fortrydes.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dette vil nulstille vidensbasen og synkronisere alle filer. Vil du fortsætte?", "Thorough explanation": "Grundig forklaring", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Aflaster {{FROM_NOW}}", "Unlock mysteries": "Lås op for mysterier", "Unpin": "Frigør", + "Unpin from Sidebar": "", "Unravel secrets": "Afslør hemmeligheder", "Unshare Chat": "", "Unsupported file type.": "Ikke-understøttet filtype.", diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 5cd8fc30e6..aec1910274 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Chats von {{user}}", "{{webUIName}} Backend Required": "{{webUIName}}-Backend erforderlich", "*Prompt node ID(s) are required for image generation": "*Prompt-Node-ID(s) sind für die Bildgenerierung erforderlich", + "1 hour before": "", "1 Source": "1 Quelle", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "vor 1 Minute", + "30 minutes before": "", + "5 minutes before": "", "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.", @@ -202,6 +207,7 @@ "Ask a question": "Stellen Sie eine Frage", "Assistant": "Assistent", "Async Embedding Processing": "Asynchrone Embedding-Verarbeitung", + "At time of event": "", "Attach File From Knowledge": "Datei aus Wissensspeicher anhängen", "Attach Files": "Dateien anhängen", "Attach Knowledge": "Wissen anhängen", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Web-Loader umgehen", "Cache Base Model List": "Basismodell-Liste cachen", "Calendar": "Kalender", + "Calendar deleted": "", "Calendars": "", "Call": "Anruf", "Call feature is not supported when using Web STT engine": "Die Anruffunktion wird bei Verwendung der Web-STT-Engine nicht unterstützt.", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Verbinden Sie Ihre eigenen OpenAPI-kompatiblen externen Tool-Server.", "Connected ({{type}})": "Verbunden ({{type}})", "Connection failed": "Verbindung fehlgeschlagen", + "Connection lost. Reconnecting...": "", "Connection successful": "Verbindung erfolgreich", "Connection Type": "Verbindungstyp", "Connections": "Verbindungen", @@ -525,6 +533,8 @@ "Delete All Chats": "Alle Chats löschen", "Delete all contents inside this folder": "Alle Inhalte in diesem Ordner löschen", "Delete automation?": "Automatisierung löschen?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Chat löschen", "Delete chat?": "Chat löschen?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Fehler beim Verbinden zum Terminal Server {{URL}}", "Failed to copy link": "Link konnte nicht kopiert werden", "Failed to create API Key.": "API-Schlüssel konnte nicht erstellt werden.", + "Failed to delete calendar": "", "Failed to delete note": "Notiz konnte nicht gelöscht werden", "Failed to download image": "Bild konnte nicht heruntergeladen werden", "Failed to extract content from the file: {{error}}": "Inhaltsextraktion fehlgeschlagen: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Reasoning Effort", "Reasoning Tags": "Reasoning Tags", "Recently Used": "Kürzlich verwendet", + "Reconnected": "", "Record": "Aufnehmen", "Record voice": "Stimme aufnehmen", "Redirecting you to Open WebUI Community": "Sie werden zur Open WebUI Community weitergeleitet", @@ -1648,6 +1660,7 @@ "Relevance": "Relevanz", "Relevance Threshold": "Relevanzschwelle", "Remember Dismissal": "Ausblendung merken", + "Reminder": "", "Remove": "Entfernen", "Remove {{MODELID}} from list.": "{{MODELID}} von der Liste entfernen.", "Remove action": "Action entfernen", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Neue Unterhaltung beginnen", "Start of the channel": "Beginn des Kanals", "Start Tag": "Start-Tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kernel starten...", + "Starting now": "", "State": "Zustand", "Status": "Status", "Status cleared successfully": "Status erfolgreich gelöscht", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dies löscht {{NAME}} und alle Inhalte.", "This will delete all models including custom models": "Dies löscht alle Modelle, einschließlich benutzerdefinierter Modelle", "This will delete all models including custom models and cannot be undone.": "Dies löscht alle Modelle, einschließlich benutzerdefinierter Modelle, und kann nicht rückgängig gemacht werden.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dadurch wird der Wissensspeicher zurückgesetzt und alle Dateien werden synchronisiert. Möchten Sie fortfahren?", "Thorough explanation": "Ausführliche Erklärung", "Thought": "Gedanke", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Entlädt {{FROM_NOW}}", "Unlock mysteries": "Geheimnisse entschlüsseln", "Unpin": "Lösen", + "Unpin from Sidebar": "", "Unravel secrets": "Geheimnisse lüften", "Unshare Chat": "Chat-Freigabe entfernen", "Unsupported file type.": "Nicht unterstützter Dateityp.", diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index f1e6fddc73..b4a402abac 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "{{webUIName}} Backend Much Required", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Connections", @@ -525,6 +533,8 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Record Bark", "Redirecting you to Open WebUI Community": "Redirecting you to Open WebUI Community", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Start of channel", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/el-GR/translation.json b/src/lib/i18n/locales/el-GR/translation.json index 3d59704cdb..22391542aa 100644 --- a/src/lib/i18n/locales/el-GR/translation.json +++ b/src/lib/i18n/locales/el-GR/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Συνομιλίες του {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Απαιτείται Backend", "*Prompt node ID(s) are required for image generation": "*Τα αναγνωριστικά κόμβου Prompt απαιτούνται για τη δημιουργία εικόνων", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Μια νέα έκδοση (v{{LATEST_VERSION}}) είναι τώρα διαθέσιμη.", @@ -202,6 +207,7 @@ "Ask a question": "Ρωτήστε μια ερώτηση", "Assistant": "Βοηθός", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Προσθήκη Knowledge", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Παράκαμψη Φορτωτή Διαδικτύου", "Cache Base Model List": "Αποθήκευση Λίστας Βασικών Μοντέλων Στην Κρυφή Μνήμη", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Κλήση", "Call feature is not supported when using Web STT engine": "Η λειτουργία κλήσης δεν υποστηρίζεται όταν χρησιμοποιείται η μηχανή Web STT", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Συνδεθείτε στους δικούς σας διακομιστές εξωτερικών εργαλείων συμβατών με OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Σύνδεση απέτυχε", + "Connection lost. Reconnecting...": "", "Connection successful": "Σύνδεση επιτυχής", "Connection Type": "Είδος Σύνδεσης", "Connections": "Συνδέσεις", @@ -525,6 +533,8 @@ "Delete All Chats": "Διαγραφή Όλων των Συνομιλιών", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Διαγραφή Συνομιλίας", "Delete chat?": "Διαγραφή συνομιλίας;", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Αποτυχία αντιγραφής συνδέσμου", "Failed to create API Key.": "Αποτυχία δημιουργίας Κλειδιού API.", + "Failed to delete calendar": "", "Failed to delete note": "Αποτυχία διαγραφής σημειώσεως", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Εγγραφή φωνής", "Redirecting you to Open WebUI Community": "Μετακατεύθυνση στην Κοινότητα OpenWebUI", @@ -1648,6 +1660,7 @@ "Relevance": "Σχετικότητα", "Relevance Threshold": "Όριο Σχετικότητας", "Remember Dismissal": "Θύμηση Απόρριψης", + "Reminder": "", "Remove": "Αφαίρεση", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Αρχή του καναλιού", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Αυτό θα διαγράψει το {{NAME}} και όλο το περιεχόμενό του.", "This will delete all models including custom models": "Αυτό θα διαγράψει όλα τα μοντέλα, συμπεριλαμβανομένων των προσαρμοσμένων μοντέλων", "This will delete all models including custom models and cannot be undone.": "Αυτό θα διαγράψει όλα τα μοντέλα, συμπεριλαμβανομένων των προσαρμοσμένων μοντέλων και δεν μπορεί να αναιρεθεί.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Αυτό θα επαναφέρει τη βάση γνώσης και θα συγχρονίσει όλα τα αρχεία. Θέλετε να συνεχίσετε;", "Thorough explanation": "Λεπτομερής εξήγηση", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Ξεκλείδωμα μυστηρίων", "Unpin": "Ξεκαρφίτσωμα", + "Unpin from Sidebar": "", "Unravel secrets": "Ξετυλίξτε μυστικά", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/en-GB/translation.json b/src/lib/i18n/locales/en-GB/translation.json index d24b7aeda5..88cfb9a311 100644 --- a/src/lib/i18n/locales/en-GB/translation.json +++ b/src/lib/i18n/locales/en-GB/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "", @@ -525,6 +533,8 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "", "Redirecting you to Open WebUI Community": "", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index b53f2ae485..ad0f42f733 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "", "{{webUIName}} Backend Required": "", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "", @@ -525,6 +533,8 @@ "Delete All Chats": "", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "", "Redirecting you to Open WebUI Community": "", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 2958a4ddfd..2f44afcee4 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido", "*Prompt node ID(s) are required for image generation": "Los ID de nodo son requeridos para la generación de imágenes", + "1 hour before": "", "1 Source": "1 Fuente", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "hace_1m", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Canal colaborativo donde la gente se une como miembro", "A discussion channel where access is controlled by groups and permissions": "Un canal de discusión con el acceso controlado mediante grupos y permisos", "A new version (v{{LATEST_VERSION}}) is now available.": "Nueva versión (v{{LATEST_VERSION}}) disponible.", @@ -203,6 +208,7 @@ "Ask a question": "Haz una pregunta", "Assistant": "Asistente", "Async Embedding Processing": "Procesado Asíncrono al Incrustrar", + "At time of event": "", "Attach File From Knowledge": "Adjuntar Archivo desde Conocimiento", "Attach Files": "Adjuntar Archivos", "Attach Knowledge": "Adjuntar Conocimiento", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Desactivar Cargar de Web", "Cache Base Model List": "Cachear Lista de Cache Modelos", "Calendar": "Calendario", + "Calendar deleted": "", "Calendars": "", "Call": "Llamada", "Call feature is not supported when using Web STT engine": "La funcionalidad de Llamada no está soportada cuando se usa el motor Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Conectar a tus propios endpoints externos de herramientas compatibles con OpenAPI.", "Connected ({{type}})": "Connectado ({{type}})", "Connection failed": "Conexión fallida", + "Connection lost. Reconnecting...": "", "Connection successful": "Conexión realizada", "Connection Type": "Tipo de Conexión", "Connections": "Conexiones", @@ -526,6 +534,8 @@ "Delete All Chats": "Borrar todos los chats", "Delete all contents inside this folder": "Borrar todo el contenido de esta carpeta", "Delete automation?": "¿Borrar automatización?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Borrar Chat", "Delete chat?": "¿Borrar el chat?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Fallo al conectar al servidor de terminal: {{URL}}", "Failed to copy link": "Fallo al copiar enlace", "Failed to create API Key.": "Fallo al crear la Clave API.", + "Failed to delete calendar": "", "Failed to delete note": "Fallo al eliminar nota", "Failed to download image": "Fallo al descargar imagen", "Failed to extract content from the file: {{error}}": "Fallo al extraer el contenido del archivo: {{error}}", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Esfuerzo del Razonamiento", "Reasoning Tags": "Etiquetas de Razonamiento", "Recently Used": "Usado Recientemente", + "Reconnected": "", "Record": "Grabar", "Record voice": "Grabar voz", "Redirecting you to Open WebUI Community": "Redireccionando a la Comunidad Open-WebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "Umbral de Relevancia", "Remember Dismissal": "Recordar Descartes (de notificaciones)", + "Reminder": "", "Remove": "Eliminar", "Remove {{MODELID}} from list.": "Eliminar {{MODELID}} de la lista.", "Remove action": "Eliminar acción", @@ -1896,7 +1909,12 @@ "Start a new conversation": "Comenzar una conversación nueva", "Start of the channel": "Inicio del canal", "Start Tag": "Etiqueta de Inicio", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciando el núcleo...", + "Starting now": "", "State": "Estado", "Status": "Estado", "Status cleared successfully": "Estado limpiado correctamente", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Esto eliminará {{NAME}} y todo su contenido.", "This will delete all models including custom models": "Esto eliminará todos los modelos, incluidos los modelos personalizados", "This will delete all models including custom models and cannot be undone.": "Esto eliminará todos los modelos, incluidos los modelos personalizados y no se puede deshacer.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Esto reinicializará la base de conocimientos y sincronizará todos los archivos. ¿Desea continuar?", "Thorough explanation": "Explicación exhaustiva", "Thought": "Pensando", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Descargas {{FROM_NOW}}", "Unlock mysteries": "Desbloquear misterios", "Unpin": "Desfijar", + "Unpin from Sidebar": "", "Unravel secrets": "Desentrañar secretos", "Unshare Chat": "Descompartir Chat", "Unsupported file type.": "Tipo de archivo no soportado", diff --git a/src/lib/i18n/locales/et-EE/translation.json b/src/lib/i18n/locales/et-EE/translation.json index a7da9119d8..a0ce487ea6 100644 --- a/src/lib/i18n/locales/et-EE/translation.json +++ b/src/lib/i18n/locales/et-EE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} vestlused", "{{webUIName}} Backend Required": "{{webUIName}} taustaserver on vajalik", "*Prompt node ID(s) are required for image generation": "*Sisendi sõlme ID(d) on piltide genereerimiseks vajalikud", + "1 hour before": "", "1 Source": "1 allikas", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m tagasi", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Koostöökanal, kuhu inimesed liituvad liikmetena", "A discussion channel where access is controlled by groups and permissions": "Arutelukanal, kus juurdepääsu kontrollivad grupid ja õigused", "A new version (v{{LATEST_VERSION}}) is now available.": "Uus versioon (v{{LATEST_VERSION}}) on saadaval.", @@ -202,6 +207,7 @@ "Ask a question": "Esita küsimus", "Assistant": "Assistent", "Async Embedding Processing": "Asünkroonne manustamise töötlemine", + "At time of event": "", "Attach File From Knowledge": "Lisa fail teadmistest", "Attach Files": "", "Attach Knowledge": "Lisa teadmised", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Jäta veebilaadija vahele", "Cache Base Model List": "Puhverda baasmudelite nimekiri", "Calendar": "Kalender", + "Calendar deleted": "", "Calendars": "", "Call": "Kõne", "Call feature is not supported when using Web STT engine": "Kõnefunktsioon ei ole Web STT mootorit kasutades toetatud", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Ühendu oma OpenAPI-ga ühilduvate väliste tööriistaserveritega.", "Connected ({{type}})": "", "Connection failed": "Ühendus ebaõnnestus", + "Connection lost. Reconnecting...": "", "Connection successful": "Ühendus õnnestus", "Connection Type": "Ühenduse tüüp", "Connections": "Ühendused", @@ -525,6 +533,8 @@ "Delete All Chats": "Kustuta kõik vestlused", "Delete all contents inside this folder": "Kustuta kogu selle kausta sisu", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Kustuta vestlus", "Delete chat?": "Kustutada vestlus?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Ühendamine {{URL}} terminali serveriga ebaõnnestus", "Failed to copy link": "Lingi kopeerimine ebaõnnestus", "Failed to create API Key.": "API võtme loomine ebaõnnestus.", + "Failed to delete calendar": "", "Failed to delete note": "Märkme kustutamine ebaõnnestus", "Failed to download image": "Pildi allalaadimine ebaõnnestus", "Failed to extract content from the file: {{error}}": "Failist sisu eraldamine ebaõnnestus: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Arutluspingutus", "Reasoning Tags": "Arutlussildid", "Recently Used": "", + "Reconnected": "", "Record": "Salvesta", "Record voice": "Salvesta hääl", "Redirecting you to Open WebUI Community": "Suunamine Open WebUI kogukonda", @@ -1648,6 +1660,7 @@ "Relevance": "Asjakohasus", "Relevance Threshold": "Asjakohasuse lävi", "Remember Dismissal": "Pea sulgemist meeles", + "Reminder": "", "Remove": "Eemalda", "Remove {{MODELID}} from list.": "Eemalda {{MODELID}} nimekirjast.", "Remove action": "Eemalda toiming", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Alusta uut vestlust", "Start of the channel": "Kanali algus", "Start Tag": "Algussilt", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kerneli käivitamine...", + "Starting now": "", "State": "", "Status": "Olek", "Status cleared successfully": "Olek edukalt tühjendatud", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "See kustutab {{NAME}} ja kogu selle sisu.", "This will delete all models including custom models": "See kustutab kõik mudelid, sealhulgas kohandatud mudelid", "This will delete all models including custom models and cannot be undone.": "See kustutab kõik mudelid, sealhulgas kohandatud mudelid, ja seda ei saa tagasi võtta.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "See lähtestab teadmiste baasi ja sünkroniseerib kõik failid. Kas soovite jätkata?", "Thorough explanation": "Põhjalik selgitus", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Laaditakse maha {{FROM_NOW}}", "Unlock mysteries": "Ava mõistatused", "Unpin": "Eemalda kinnitus", + "Unpin from Sidebar": "", "Unravel secrets": "Ava saladused", "Unshare Chat": "Lõpeta vestluse jagamine", "Unsupported file type.": "Toetamata failitüüp.", diff --git a/src/lib/i18n/locales/eu-ES/translation.json b/src/lib/i18n/locales/eu-ES/translation.json index b8314d577a..bbb86b2023 100644 --- a/src/lib/i18n/locales/eu-ES/translation.json +++ b/src/lib/i18n/locales/eu-ES/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}-ren Txatak", "{{webUIName}} Backend Required": "{{webUIName}} Backend-a Beharrezkoa", "*Prompt node ID(s) are required for image generation": "Prompt nodoaren IDa(k) beharrezkoak dira irudiak sortzeko", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Bertsio berri bat (v{{LATEST_VERSION}}) eskuragarri dago orain.", @@ -202,6 +207,7 @@ "Ask a question": "Egin galdera bat", "Assistant": "Laguntzailea", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Deia", "Call feature is not supported when using Web STT engine": "Dei funtzioa ez da onartzen Web STT motorra erabiltzean", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Konexioak", @@ -525,6 +533,8 @@ "Delete All Chats": "Ezabatu Txat Guztiak", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Ezabatu Txata", "Delete chat?": "Ezabatu txata?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Huts egin du API Gakoa sortzean.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Grabatu ahotsa", "Redirecting you to Open WebUI Community": "OpenWebUI Komunitatera berbideratzen", @@ -1648,6 +1660,7 @@ "Relevance": "Garrantzia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Kendu", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Kanalaren hasiera", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Honek {{NAME}} eta bere eduki guztiak ezabatuko ditu.", "This will delete all models including custom models": "Honek modelo guztiak ezabatuko ditu, modelo pertsonalizatuak barne", "This will delete all models including custom models and cannot be undone.": "Honek modelo guztiak ezabatuko ditu, modelo pertsonalizatuak barne, eta ezin da desegin.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Honek ezagutza-basea berrezarri eta fitxategi guztiak sinkronizatuko ditu. Jarraitu nahi duzu?", "Thorough explanation": "Azalpen sakona", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Askatu misterioak", "Unpin": "Kendu aingura", + "Unpin from Sidebar": "", "Unravel secrets": "Askatu sekretuak", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index 3dd9dc4d32..39de7bb016 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} گفتگوهای", "{{webUIName}} Backend Required": "بکند {{webUIName}} نیاز است.", "*Prompt node ID(s) are required for image generation": "*شناسه(های) گره پرامپت برای تولید تصویر مورد نیاز است", + "1 hour before": "", "1 Source": "۱ منبع", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "نسخه جدید (v{{LATEST_VERSION}}) در دسترس است.", @@ -202,6 +207,7 @@ "Ask a question": "سوالی بپرسید", "Assistant": "دستیار", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "پیوست فایل از دانش", "Attach Files": "", "Attach Knowledge": "پیوست دانش", @@ -276,6 +282,7 @@ "Bypass Web Loader": "دور زدن بارگذاری وب", "Cache Base Model List": "کش لیست مدل پایه", "Calendar": "تقویم", + "Calendar deleted": "", "Calendars": "", "Call": "تماس", "Call feature is not supported when using Web STT engine": "ویژگی تماس هنگام استفاده از موتور Web STT پشتیبانی نمی\u200cشود", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "به سرورهای ابزار خارجی سازگار با OpenAPI خود متصل شوید.", "Connected ({{type}})": "", "Connection failed": "اتصال ناموفق بود", + "Connection lost. Reconnecting...": "", "Connection successful": "اتصال موفقیت\u200cآمیز بود", "Connection Type": "نوع اتصال", "Connections": "ارتباطات", @@ -525,6 +533,8 @@ "Delete All Chats": "حذف همه گفتگوها", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "حذف گپ", "Delete chat?": "گفتگو حذف شود؟", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "کپی لینک ناموفق بود", "Failed to create API Key.": "ایجاد کلید API با خطا مواجه شد.", + "Failed to delete calendar": "", "Failed to delete note": "حذف یادداشت ناموفق بود", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "استخراج محتوا از فایل ناموفق بود: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "تلاش استدلال", "Reasoning Tags": "تگ\u200cهای استدلال", "Recently Used": "", + "Reconnected": "", "Record": "ضبط", "Record voice": "ضبط صدا", "Redirecting you to Open WebUI Community": "در حال هدایت به OpenWebUI Community", @@ -1648,6 +1660,7 @@ "Relevance": "ارتباط", "Relevance Threshold": "آستانه ارتباط", "Remember Dismissal": "به خاطر سپردن رد کردن", + "Reminder": "", "Remove": "حذف", "Remove {{MODELID}} from list.": "حذف {{MODELID}} از لیست.", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "شروع یک مکالمه جدید", "Start of the channel": "آغاز کانال", "Start Tag": "تگ شروع", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "این {{NAME}} و تمام محتویات آن را حذف خواهد کرد.", "This will delete all models including custom models": "این همه مدل\u200cها از جمله مدل\u200cهای سفارشی را حذف خواهد کرد", "This will delete all models including custom models and cannot be undone.": "این همه مدل\u200cها از جمله مدل\u200cهای سفارشی را حذف خواهد کرد و قابل بازگشت نیست.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "این پایگاه دانش را بازنشانی کرده و همه فایل\u200cها را همگام\u200cسازی خواهد کرد. آیا می\u200cخواهید ادامه دهید؟", "Thorough explanation": "توضیح کامل", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "خارج می\u200cشود {{FROM_NOW}}", "Unlock mysteries": "رمزگشایی از اسرار", "Unpin": "برداشتن پین", + "Unpin from Sidebar": "", "Unravel secrets": "کشف رازها", "Unshare Chat": "", "Unsupported file type.": "نوع فایل پشتیبانی نمی\u200cشود.", diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index 7c856082bc..16501646eb 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}:n keskustelut", "{{webUIName}} Backend Required": "{{webUIName}}-backend vaaditaan", "*Prompt node ID(s) are required for image generation": "Kuvan luomiseen vaaditaan kehote-solmun ID(t)", + "1 hour before": "", "1 Source": "1 lähde", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Yhteistyökanava, johon ihmiset liittyvät jäseninä", "A discussion channel where access is controlled by groups and permissions": "Keskustelukanava, johon pääsyä rajoitetaan ryhmillä ja käyttöoikeuksilla", "A new version (v{{LATEST_VERSION}}) is now available.": "Uusi versio (v{{LATEST_VERSION}}) on nyt saatavilla.", @@ -202,6 +207,7 @@ "Ask a question": "Kysy kysymys", "Assistant": "Avustaja", "Async Embedding Processing": "Asynkroninen upotus prosessointi", + "At time of event": "", "Attach File From Knowledge": "Liitä tiedosto tietämyksestä", "Attach Files": "", "Attach Knowledge": "Liitä tietoa", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Ohita verkkolataaja", "Cache Base Model List": "Malli luettelon välimuisti", "Calendar": "Kalenteri", + "Calendar deleted": "", "Calendars": "", "Call": "Puhelu", "Call feature is not supported when using Web STT engine": "Puhelutoimintoa ei tueta käytettäessä web-puheentunnistusmoottoria", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Yhdistä omat ulkopuoliset OpenAPI yhteensopivat työkalu palvelimet.", "Connected ({{type}})": "Yhdistetty ({{type}})", "Connection failed": "Yhteys epäonnistui", + "Connection lost. Reconnecting...": "", "Connection successful": "Yhteys onnistui", "Connection Type": "Yhteystyyppi", "Connections": "Yhteydet", @@ -525,6 +533,8 @@ "Delete All Chats": "Poista kaikki keskustelut", "Delete all contents inside this folder": "Poista kaikki sisällöt tästä kansiosta", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Poista keskustelu", "Delete chat?": "Haluatko varmasti poistaa tämän keskustelun?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Yhdistäminen {{URL}} päätepalvelimeen epäonnistui", "Failed to copy link": "Linkin kopiointi epäonnistui", "Failed to create API Key.": "API-avaimen luonti epäonnistui.", + "Failed to delete calendar": "", "Failed to delete note": "Muistiinpanon poistaminen epäonnistui", "Failed to download image": "Kuvan lataaminen epäonnistui", "Failed to extract content from the file: {{error}}": "Tiedoston sisällön pomiminen epäonnistui: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Päättelyn määrä", "Reasoning Tags": "Päättely tagit", "Recently Used": "", + "Reconnected": "", "Record": "Nauhoita", "Record voice": "Nauhoita ääntä", "Redirecting you to Open WebUI Community": "Ohjataan sinut OpenWebUI-yhteisöön", @@ -1648,6 +1660,7 @@ "Relevance": "Relevanssi", "Relevance Threshold": "Relevanssikynnys", "Remember Dismissal": "Muista sulkeminen", + "Reminder": "", "Remove": "Poista", "Remove {{MODELID}} from list.": "Poista {{MODELID}} listalta", "Remove action": "Poista toiminto", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Aloita uusi keskustelu", "Start of the channel": "Kanavan alku", "Start Tag": "Aloitus tagi", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Käynnistetään kerneliä...", + "Starting now": "", "State": "", "Status": "Tila", "Status cleared successfully": "Tila poistettu onnistuneesti", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Tämä poistaa {{NAME}} ja kaikki sen sisällöt.", "This will delete all models including custom models": "Tämä poistaa kaikki mallit mukaan lukien mukautetut mallit", "This will delete all models including custom models and cannot be undone.": "Tämä poistaa kaikki mallit, mukaan lukien mukautetut mallit, eikä sitä voi peruuttaa.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Tämä nollaa tietokannan ja synkronoi kaikki tiedostot. Haluatko jatkaa?", "Thorough explanation": "Perusteellinen selitys", "Thought": "Ajatus", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Purkuja {{FROM_NOW}}", "Unlock mysteries": "Selvitä arvoituksia", "Unpin": "Irrota kiinnitys", + "Unpin from Sidebar": "", "Unravel secrets": "Avaa salaisuuksia", "Unshare Chat": "Lopeta keskustelun jakaminen", "Unsupported file type.": "Ei tuettu tiedostotyyppi", diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index a91ad0b618..d59ea0abf3 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Conversations de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} requis", "*Prompt node ID(s) are required for image generation": "*Les ID de noeud du prompt sont nécessaires pour la génération d'images", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Une nouvelle version (v{{LATEST_VERSION}}) est disponible.", @@ -203,6 +208,7 @@ "Ask a question": "Posez votre question", "Assistant": "Assistant", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Ignorer le chargeur Web", "Cache Base Model List": "Mettre en cache la liste des modèles de base", "Calendar": "Calendrier", + "Calendar deleted": "", "Calendars": "", "Call": "Appeler", "Call feature is not supported when using Web STT engine": "La fonction d'appel n'est pas prise en charge lors de l'utilisation du moteur Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connectez-vous à vos serveurs d'outils externes.", "Connected ({{type}})": "", "Connection failed": "Échec de la connexion", + "Connection lost. Reconnecting...": "", "Connection successful": "Connexion réussie", "Connection Type": "Type de connexion", "Connections": "Connexions", @@ -526,6 +534,8 @@ "Delete All Chats": "Supprimer toutes les conversations", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Supprimer la Conversation", "Delete chat?": "Supprimer la conversation ?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Échec de la copie du lien", "Failed to create API Key.": "Échec de la création de la clé API.", + "Failed to delete calendar": "", "Failed to delete note": "Échec de la délétion de la note", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Effort de raisonnement", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Enregistrement", "Record voice": "Enregistrer la voix", "Redirecting you to Open WebUI Community": "Redirection vers la communauté OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Pertinence", "Relevance Threshold": "Seuil de pertinence", "Remember Dismissal": "Se souvenir du rejet", + "Reminder": "", "Remove": "Retirer", "Remove {{MODELID}} from list.": "Retirer {{MODELID}} de la liste.", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Début du canal", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Cela supprimera {{NAME}} et tout son contenu.", "This will delete all models including custom models": "Cela supprimera tous les modèles, y compris les modèles personnalisés", "This will delete all models including custom models and cannot be undone.": "Cela supprimera tous les modèles, y compris les modèles personnalisés, et ne peut pas être annulé.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Cela réinitialisera la base de connaissances et synchronisera tous les fichiers. Souhaitez-vous continuer ?", "Thorough explanation": "Explication approfondie", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Décharge {{FROM_NOW}}", "Unlock mysteries": "Déverrouiller les mystères", "Unpin": "Désépingler", + "Unpin from Sidebar": "", "Unravel secrets": "Dévoiler les secrets", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 0de23b8898..4572e362c8 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Conversations de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} requis", "*Prompt node ID(s) are required for image generation": "*Les ID de noeud du prompt sont nécessaires pour la génération d'image", + "1 hour before": "", "1 Source": "1 Source", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1min", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Un canal collaboratif où les membres rejoignent librement", "A discussion channel where access is controlled by groups and permissions": "Un canal de discussion où l'accès est contrôlé par les groupes et les permissions", "A new version (v{{LATEST_VERSION}}) is now available.": "Une nouvelle version (v{{LATEST_VERSION}}) est disponible.", @@ -203,6 +208,7 @@ "Ask a question": "Posez votre question", "Assistant": "Assistant", "Async Embedding Processing": "Traitement asynchrone des embeddings", + "At time of event": "", "Attach File From Knowledge": "Joindre un fichier depuis les connaissances", "Attach Files": "", "Attach Knowledge": "Joindre une connaissance", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Ignorer le chargeur Web", "Cache Base Model List": "Mettre en cache la liste des modèles de base", "Calendar": "Calendrier", + "Calendar deleted": "", "Calendars": "", "Call": "Appeler", "Call feature is not supported when using Web STT engine": "La fonction d'appel n'est pas prise en charge lors de l'utilisation du moteur Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connectez-vous à vos serveurs d'outils externes.", "Connected ({{type}})": "", "Connection failed": "Échec de la connexion", + "Connection lost. Reconnecting...": "", "Connection successful": "Connexion réussie", "Connection Type": "Type de connexion", "Connections": "Connexions", @@ -526,6 +534,8 @@ "Delete All Chats": "Supprimer toutes les conversations", "Delete all contents inside this folder": "Supprimer tout le contenu de ce dossier", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Supprimer la Conversation", "Delete chat?": "Supprimer la conversation ?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Échec de la connexion au serveur de terminal {{URL}}", "Failed to copy link": "Échec de la copie du lien", "Failed to create API Key.": "Échec de la création de la clé API.", + "Failed to delete calendar": "", "Failed to delete note": "Échec de la délétion de la note", "Failed to download image": "Échec du téléchargement de l'image", "Failed to extract content from the file: {{error}}": "Échec de l'extraction du contenu du fichier : {{error}}", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Effort de raisonnement", "Reasoning Tags": "Balises de raisonnement", "Recently Used": "", + "Reconnected": "", "Record": "Enregistrement", "Record voice": "Enregistrer la voix", "Redirecting you to Open WebUI Community": "Redirection vers la communauté OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Pertinence", "Relevance Threshold": "Seuil de pertinence", "Remember Dismissal": "Se souvenir du rejet", + "Reminder": "", "Remove": "Retirer", "Remove {{MODELID}} from list.": "Retirer {{MODELID}} de la liste.", "Remove action": "Retirer l'action", @@ -1896,7 +1909,12 @@ "Start a new conversation": "Démarrer une nouvelle conversation", "Start of the channel": "Début du canal", "Start Tag": "Balise de départ", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Démarrage du noyau...", + "Starting now": "", "State": "", "Status": "Statut", "Status cleared successfully": "Statut effacé avec succès", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Cela supprimera {{NAME}} et tout son contenu.", "This will delete all models including custom models": "Cela supprimera tous les modèles, y compris les modèles personnalisés", "This will delete all models including custom models and cannot be undone.": "Cela supprimera tous les modèles, y compris les modèles personnalisés, et ne peut pas être annulé.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Cela réinitialisera la base de connaissances et synchronisera tous les fichiers. Souhaitez-vous continuer ?", "Thorough explanation": "Explication approfondie", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Décharge {{FROM_NOW}}", "Unlock mysteries": "Déverrouiller les mystères", "Unpin": "Désépingler", + "Unpin from Sidebar": "", "Unravel secrets": "Dévoiler les secrets", "Unshare Chat": "Annuler le partage de la conversation", "Unsupported file type.": "Type de fichier non pris en charge.", diff --git a/src/lib/i18n/locales/gl-ES/translation.json b/src/lib/i18n/locales/gl-ES/translation.json index 3c36e045e9..df434bfa1a 100644 --- a/src/lib/i18n/locales/gl-ES/translation.json +++ b/src/lib/i18n/locales/gl-ES/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Chats do {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Servidor Requerido", "*Prompt node ID(s) are required for image generation": "Os ID do nodo son requeridos para a xeneración de imáxes", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Unha nova versión (v{{LATEST_VERSION}}) está disponible.", @@ -202,6 +207,7 @@ "Ask a question": "Fai unha pregunta", "Assistant": "Asistente", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Chamada", "Call feature is not supported when using Web STT engine": "A funcionalidade da chamada non pode usarse xunto co motor da STT Web", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Conexions", @@ -525,6 +533,8 @@ "Delete All Chats": "Eliminar todos os chats", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Borrar Chat", "Delete chat?": "Borrar o chat?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Non pudo xerarse a chave API.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Esfuerzo de razonamiento", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Grabar voz", "Redirecting you to Open WebUI Community": "Redireccionándote a a comunidad OpenWebUI", @@ -1648,6 +1660,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Eliminar", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Inicio da canle", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Esto eliminará {{NAME}} y todo su contido.", "This will delete all models including custom models": "Esto eliminará todos os modelos, incluidos os modelos personalizados", "This will delete all models including custom models and cannot be undone.": "Esto eliminará todos os modelos, incluidos os modelos personalizados y no se puede deshacer.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Esto reseteará la base de coñecementos y sincronizará todos os arquivos. ¿Desea continuar?", "Thorough explanation": "Explicación exhaustiva", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Desbloquear misterios", "Unpin": "Desanclar", + "Unpin from Sidebar": "", "Unravel secrets": "Desentrañar secretos", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index 2bb98c4d4e..f36e6d332e 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "צ'אטים של {{user}}", "{{webUIName}} Backend Required": "נדרש Backend של {{webUIName}}", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -203,6 +208,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -277,6 +283,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "לוח שנה", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "החיבור נכשל", + "Connection lost. Reconnecting...": "", "Connection successful": "החיבור הצליח", "Connection Type": "סוג חיבור", "Connections": "חיבורים", @@ -526,6 +534,8 @@ "Delete All Chats": "מחק את כל הצ'אטים", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "מחק צ'אט", "Delete chat?": "", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "יצירת מפתח API נכשלה.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "הקלט קול", "Redirecting you to Open WebUI Community": "מפנה אותך לקהילת OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "הסר", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "תחילת הערוץ", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_two": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "תיאור מפורט", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index ce96aa2286..eeeff64210 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} की चैट", "{{webUIName}} Backend Required": "{{webUIName}} बैकएंड आवश्यक", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "सम्बन्ध", @@ -525,6 +533,8 @@ "Delete All Chats": "सभी चैट हटाएं", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "चैट हटाएं", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "एपीआई कुंजी बनाने में विफल.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "आवाज रिकॉर्ड करना", "Redirecting you to Open WebUI Community": "आपको OpenWebUI समुदाय पर पुनर्निर्देशित किया जा रहा है", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "हटा दें", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "चैनल की शुरुआत", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "विस्तृत व्याख्या", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/hr-HR/translation.json b/src/lib/i18n/locales/hr-HR/translation.json index 01e9f0fdf1..c0525013e9 100644 --- a/src/lib/i18n/locales/hr-HR/translation.json +++ b/src/lib/i18n/locales/hr-HR/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Razgovori korisnika {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend je potreban", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -203,6 +208,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -277,6 +283,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Poziv", "Call feature is not supported when using Web STT engine": "Značajka poziva nije podržana kada se koristi Web STT mehanizam", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Povezivanja", @@ -526,6 +534,8 @@ "Delete All Chats": "Izbriši sve razgovore", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Izbriši razgovor", "Delete chat?": "", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Neuspješno stvaranje API ključa.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Snimanje glasa", "Redirecting you to Open WebUI Community": "Preusmjeravanje na OpenWebUI zajednicu", @@ -1649,6 +1661,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Ukloni", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Početak kanala", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Detaljno objašnjenje", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/hu-HU/translation.json b/src/lib/i18n/locales/hu-HU/translation.json index 5d2fee4e33..22f4ea62cf 100644 --- a/src/lib/i18n/locales/hu-HU/translation.json +++ b/src/lib/i18n/locales/hu-HU/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} beszélgetései", "{{webUIName}} Backend Required": "{{webUIName}} Backend szükséges", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(k) szükségesek a képgeneráláshoz", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Új verzió (v{{LATEST_VERSION}}) érhető el.", @@ -202,6 +207,7 @@ "Ask a question": "Kérdezz valamit", "Assistant": "Asszisztens", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Naptár", + "Calendar deleted": "", "Calendars": "", "Call": "Hívás", "Call feature is not supported when using Web STT engine": "A hívás funkció nem támogatott Web STT motor használatakor", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Csatlakozz saját OpenAPI kompatibilis külső eszköszervereidhez.", "Connected ({{type}})": "", "Connection failed": "Kapcsolat sikertelen", + "Connection lost. Reconnecting...": "", "Connection successful": "Kapcsolat sikeres", "Connection Type": "", "Connections": "Kapcsolatok", @@ -525,6 +533,8 @@ "Delete All Chats": "Minden beszélgetés törlése", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Beszélgetés törlése", "Delete chat?": "Törli a beszélgetést?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Nem sikerült létrehozni az API kulcsot.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Érvelési erőfeszítés", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Hang rögzítése", "Redirecting you to Open WebUI Community": "Átirányítás az OpenWebUI közösséghez", @@ -1648,6 +1660,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Eltávolítás", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "A csatorna eleje", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Ez törölni fogja a {{NAME}}-t és minden tartalmát.", "This will delete all models including custom models": "Ez törölni fogja az összes modellt, beleértve az egyéni modelleket is", "This will delete all models including custom models and cannot be undone.": "Ez törölni fogja az összes modellt, beleértve az egyéni modelleket is, és nem vonható vissza.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Ez visszaállítja a tudásbázist és szinkronizálja az összes fájlt. Szeretné folytatni?", "Thorough explanation": "Alapos magyarázat", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Titkok feloldása", "Unpin": "Rögzítés feloldása", + "Unpin from Sidebar": "", "Unravel secrets": "Titkok megfejtése", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/id-ID/translation.json b/src/lib/i18n/locales/id-ID/translation.json index 2e60de3ed1..c537fb24bb 100644 --- a/src/lib/i18n/locales/id-ID/translation.json +++ b/src/lib/i18n/locales/id-ID/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "Obrolan {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Diperlukan Backend", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -201,6 +206,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -275,6 +281,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Panggilan", "Call feature is not supported when using Web STT engine": "Fitur panggilan tidak didukung saat menggunakan mesin Web STT", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Koneksi", @@ -524,6 +532,8 @@ "Delete All Chats": "Menghapus Semua Obrolan", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Menghapus Obrolan", "Delete chat?": "Menghapus obrolan?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Gagal membuat API Key.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Rekam suara", "Redirecting you to Open WebUI Community": "Mengarahkan Anda ke Komunitas OpenWebUI", @@ -1647,6 +1659,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Hapus", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1892,7 +1905,10 @@ "Start a new conversation": "", "Start of the channel": "Awal saluran", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Penjelasan menyeluruh", "Thought": "", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/ie-GA/translation.json b/src/lib/i18n/locales/ie-GA/translation.json index df9257c7e9..e5550ac069 100644 --- a/src/lib/i18n/locales/ie-GA/translation.json +++ b/src/lib/i18n/locales/ie-GA/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Comhráite {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Ceoldeireadh Riachtanach", "*Prompt node ID(s) are required for image generation": "* Tá ID(anna) nód treorach ag teastáil chun íomhá a ghiniúint", + "1 hour before": "", "1 Source": "1 Foinse", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 nóiméad ó shin", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Cainéal comhoibrithe ina mbíonn daoine ag glacadh páirte mar bhaill", "A discussion channel where access is controlled by groups and permissions": "Cainéal plé ina bhfuil rochtain rialaithe ag grúpaí agus ceadanna", "A new version (v{{LATEST_VERSION}}) is now available.": "Tá leagan nua (v {{LATEST_VERSION}}) ar fáil anois.", @@ -202,6 +207,7 @@ "Ask a question": "Cuir ceist", "Assistant": "Cúntóir", "Async Embedding Processing": "Próiseáil Leabaithe Asyncrónach", + "At time of event": "", "Attach File From Knowledge": "Ceangail Comhad ó Eolas", "Attach Files": "Ceangail Comhaid", "Attach Knowledge": "Ceangail Eolas", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Seachbhóthar Luchtaire Gréasáin", "Cache Base Model List": "Liosta Samhail Bunáite Taisce", "Calendar": "Féilire", + "Calendar deleted": "", "Calendars": "", "Call": "Glaoigh", "Call feature is not supported when using Web STT engine": "Ní thacaítear le gné glaonna agus inneall Web STT á úsáid", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Ceangail le do fhreastalaithe uirlisí seachtracha atá comhoiriúnach le OpenAPI.", "Connected ({{type}})": "Ceangailte ({{type}})", "Connection failed": "Theip ar an gceangal", + "Connection lost. Reconnecting...": "", "Connection successful": "Ceangal rathúil", "Connection Type": "Cineál Ceangail", "Connections": "Naisc", @@ -525,6 +533,8 @@ "Delete All Chats": "Scrios Gach Comhrá", "Delete all contents inside this folder": "Scrios an t-ábhar go léir atá sa fhillteán seo", "Delete automation?": "Scrios an t-uathoibriú?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Scrios Comhrá", "Delete chat?": "Scrios comhrá?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Theip ar cheangal le freastalaí críochfoirt {{URL}}", "Failed to copy link": "Theip ar an nasc a chóipeáil", "Failed to create API Key.": "Theip ar an eochair API a chruthú.", + "Failed to delete calendar": "", "Failed to delete note": "Theip ar an nóta a scriosadh", "Failed to download image": "Theip ar an íomhá a íoslódáil", "Failed to extract content from the file: {{error}}": "Theip ar an ábhar a bhaint as an gcomhad: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Iarracht Réasúnúcháin", "Reasoning Tags": "Clibeanna Réasúnaíochta", "Recently Used": "Úsáidte le Déanaí", + "Reconnected": "", "Record": "Taifead", "Record voice": "Taifead guth", "Redirecting you to Open WebUI Community": "Tú a atreorú chuig OpenWebUI Community", @@ -1648,6 +1660,7 @@ "Relevance": "Ábharthacht", "Relevance Threshold": "Tairseach Ábharthaíochta", "Remember Dismissal": "Cuimhnigh ar an Dífhostú", + "Reminder": "", "Remove": "Bain", "Remove {{MODELID}} from list.": "Bain {{MODELID}} den liosta.", "Remove action": "Bain gníomh", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Tosaigh comhrá nua", "Start of the channel": "Tús an chainéil", "Start Tag": "Clib Tosaigh", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Ag tosú an eithne...", + "Starting now": "", "State": "Stát", "Status": "Stádas", "Status cleared successfully": "Glanadh an stádais go rathúil", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Scriosfaidh sé seo {{NAME}} agus a bhfuil ann go léir.", "This will delete all models including custom models": "Scriosfaidh sé seo gach samhail lena n-áirítear samhlacha saincheaptha", "This will delete all models including custom models and cannot be undone.": "Scriosfaidh sé seo gach samhail, lena n-áirítear samhlacha saincheaptha, agus ní féidir é a chealú.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Déanfaidh sé seo an bonn eolais a athshocrú agus gach comhad a shioncronú. Ar mhaith leat leanúint ar aghaidh?", "Thorough explanation": "Míniú críochnúil", "Thought": "Smaoineamh", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Díluchtuithe {{FROM_NOW}}", "Unlock mysteries": "Díghlasáil rúndiamhra", "Unpin": "Díphoráil", + "Unpin from Sidebar": "", "Unravel secrets": "Rúin a réiteach", "Unshare Chat": "Díroinn Comhrá", "Unsupported file type.": "Cineál comhaid nach dtacaítear leis.", diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index e8b2b0f217..c94b0f7f5a 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "{{user}} Chat", "{{webUIName}} Backend Required": "{{webUIName}} Richiesta Backend", "*Prompt node ID(s) are required for image generation": "*ID nodo prompt sono necessari per la generazione di immagini", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Una nuova versione (v{{LATEST_VERSION}}) è ora disponibile.", @@ -203,6 +208,7 @@ "Ask a question": "Fai una domanda", "Assistant": "Assistente", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Bypassa il Web Loader", "Cache Base Model List": "", "Calendar": "Calendario", + "Calendar deleted": "", "Calendars": "", "Call": "Chiamata", "Call feature is not supported when using Web STT engine": "La funzione di chiamata non è supportata quando si utilizza il motore Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Connettiti ai tuoi server di tool esterni compatibili con OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Connessione fallita", + "Connection lost. Reconnecting...": "", "Connection successful": "Connessione riuscita", "Connection Type": "Tipo Connessione", "Connections": "Connessioni", @@ -526,6 +534,8 @@ "Delete All Chats": "Elimina tutte le chat", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Elimina chat", "Delete chat?": "Elimina chat?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Impossibile copiare il link", "Failed to create API Key.": "Impossibile creare Chiave API.", + "Failed to delete calendar": "", "Failed to delete note": "Impossibile eliminare la nota", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Sforzo di ragionamento", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Registra", "Record voice": "Registra voce", "Redirecting you to Open WebUI Community": "Reindirizzamento alla comunità OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Rilevanza", "Relevance Threshold": "Soglia di Rilevanza", "Remember Dismissal": "", + "Reminder": "", "Remove": "Rimuovi", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Inizio del canale", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Questa opzione eliminerà {{NAME}} e tutti i suoi contenuti.", "This will delete all models including custom models": "Questa opzione eliminerà tutti i modelli, compresi i modelli personalizzati", "This will delete all models including custom models and cannot be undone.": "Questa opzione eliminerà tutti i modelli, compresi i modelli personalizzati e non può essere annullata.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Questa opzione ripristinerà la base di conoscenza e sincronizzerà tutti i file. Vuoi continuare?", "Thorough explanation": "Spiegazione dettagliata", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Scarica {{FROM_NOW}}", "Unlock mysteries": "Sblocca misteri", "Unpin": "Rimuovi fissato", + "Unpin from Sidebar": "", "Unravel secrets": "Svela segreti", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index 77aa239d44..af0c4211b5 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} のチャット", "{{webUIName}} Backend Required": "{{webUIName}} バックエンドが必要です", "*Prompt node ID(s) are required for image generation": "*画像生成にはプロンプトノードIDが必要です", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "新しいバージョン (v{{LATEST_VERSION}}) が利用可能です。", @@ -201,6 +206,7 @@ "Ask a question": "質問する", "Assistant": "アシスタント", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "ナレッジからファイルを添付", "Attach Files": "ファイルを追加", "Attach Knowledge": "ナレッジを追加", @@ -275,6 +281,7 @@ "Bypass Web Loader": "Webローダーをバイパス", "Cache Base Model List": "ベースモデルリストをキャッシュ", "Calendar": "カレンダー", + "Calendar deleted": "", "Calendars": "", "Call": "コール", "Call feature is not supported when using Web STT engine": "Web STTエンジンを使用している場合、コール機能は使用できません", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "独自のOpenAPI互換外部ツールサーバーに接続します。", "Connected ({{type}})": "", "Connection failed": "接続に失敗しました", + "Connection lost. Reconnecting...": "", "Connection successful": "接続に成功しました", "Connection Type": "接続タイプ", "Connections": "接続", @@ -524,6 +532,8 @@ "Delete All Chats": "すべてのチャットを削除", "Delete all contents inside this folder": "", "Delete automation?": "オートメーションを削除しますか?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "チャットを削除", "Delete chat?": "チャットを削除しますか?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "リンクのコピーに失敗しました。", "Failed to create API Key.": "APIキーの作成に失敗しました。", + "Failed to delete calendar": "", "Failed to delete note": "ノートの削除に失敗しました。", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "ファイルから中身の取得に失敗しました: {{error}}", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "推理の努力", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "録音", "Record voice": "音声を録音", "Redirecting you to Open WebUI Community": "OpenWebUI コミュニティにリダイレクトしています", @@ -1647,6 +1659,7 @@ "Relevance": "関連性", "Relevance Threshold": "関連性の閾値", "Remember Dismissal": "閉じたことを記憶する", + "Reminder": "", "Remove": "削除", "Remove {{MODELID}} from list.": "{{MODELID}} をリストから削除する", "Remove action": "", @@ -1892,7 +1905,10 @@ "Start a new conversation": "新しい会話を開始", "Start of the channel": "チャンネルの開始", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "状態", "Status": "ステータス", "Status cleared successfully": "正常にステータスをクリアしました", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "これは{{NAME}}とそのすべての内容を削除します。", "This will delete all models including custom models": "これはカスタムモデルを含むすべてのモデルを削除します", "This will delete all models including custom models and cannot be undone.": "これはカスタムモデルを含むすべてのモデルを削除し、元に戻すことはできません。", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "これは知識ベースをリセットし、すべてのファイルを同期します。続けますか?", "Thorough explanation": "詳細な説明", "Thought": "", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}}にアンロード", "Unlock mysteries": "ミステリーを解き明かす", "Unpin": "ピン留め解除", + "Unpin from Sidebar": "", "Unravel secrets": "秘密を解き明かす", "Unshare Chat": "", "Unsupported file type.": "未対応のファイルタイプです", diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index b2726bf790..acdc14db3c 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}-ის ჩათები", "{{webUIName}} Backend Required": "{{webUIName}} საჭიროა უკანაბოლო", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "1 წყარო", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "ხელმისაწვდომია ახალი ვერსია (v{{LATEST_VERSION}}).", @@ -202,6 +207,7 @@ "Ask a question": "კითხვის დასმა", "Assistant": "დამხმარე", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "ცოდნის მიმაგრება", @@ -276,6 +282,7 @@ "Bypass Web Loader": "ვებჩამტვირთავის გამოტოვება", "Cache Base Model List": "საბაზისო მოდელების სიის დაკეშვა", "Calendar": "კალენდარი", + "Calendar deleted": "", "Calendars": "", "Call": "ზარი", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "დაკავშირება ვერ მოხერხდა", + "Connection lost. Reconnecting...": "", "Connection successful": "შეერთება წარმატებულია", "Connection Type": "შეერთების ტიპი", "Connections": "კავშირები", @@ -525,6 +533,8 @@ "Delete All Chats": "ყველა ჩატის წაშლა", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "საუბრის წაშლა", "Delete chat?": "წავშალო ჩატი?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "ბმულის კოპირება ჩავარდა", "Failed to create API Key.": "API-ის გასაღების შექმნა ჩავარდა.", + "Failed to delete calendar": "", "Failed to delete note": "შენიშვნის წაშლა ჩავარდა", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "ჩაწერა", "Record voice": "ხმის ჩაწერა", "Redirecting you to Open WebUI Community": "მიმდინარეობს გადამისამართება OpenWebUI-ის საზოგადოების საიტზე", @@ -1648,6 +1660,7 @@ "Relevance": "შესაბამისობა", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "წაშლა", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "არხის დასაწყისი", "Start Tag": "დაწყების ჭდე", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "საფუძვლიანი ახსნა", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "გამოტვირთვა {{FROM_NOW}}", "Unlock mysteries": "", "Unpin": "ჩამოხსნა", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/kab-DZ/translation.json b/src/lib/i18n/locales/kab-DZ/translation.json index 4d0c32b8d6..0fc3787813 100644 --- a/src/lib/i18n/locales/kab-DZ/translation.json +++ b/src/lib/i18n/locales/kab-DZ/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "Asqerdec n {{user}}", "{{webUIName}} Backend Required": "", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "1 n weɣbalu", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Lqem amaynut n (v{{LATEST_VERSION}}), yella akka tura.", @@ -202,6 +207,7 @@ "Ask a question": "Efk-d asteqsi", "Assistant": "Amallal", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Qqen-as tamessunt", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Zgel asalay Web", "Cache Base Model List": "Ffer tabdart n tmudmiwin n taffa", "Calendar": "Awitay", + "Calendar deleted": "", "Calendars": "", "Call": "Siwel", "Call feature is not supported when using Web STT engine": "Tamahilt n usiwel ur tettwasefrak ara mi ara tesqedceḍ amsedday Web STT", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Qqen ɣer yiqeddacen-ik n yifecka imeṛṛa yeldin.", "Connected ({{type}})": "", "Connection failed": "Tuqqna d-tawezɣit", + "Connection lost. Reconnecting...": "", "Connection successful": "Tuqqna tedda akken iwata", "Connection Type": "Anaw n tuqqna", "Connections": "Tuqqniwin", @@ -525,6 +533,8 @@ "Delete All Chats": "Kkes akk idiwenniyen", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Kkes asqerdec", "Delete chat?": "Tebɣiḍ ad tekkseḍ adiwenni?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Ur yessaweḍ ara ad yessukken aseɣwen", "Failed to create API Key.": "Ur yessaweḍ ara ad d-yesnulfu tasarut API.", + "Failed to delete calendar": "", "Failed to delete note": "Ur yessaweḍ ara ad yekkes tazmilt", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Ur yessaweḍ ara ad d-yekkes agbur seg ufaylu: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Aklas", "Record voice": "Sekles taɣect", "Redirecting you to Open WebUI Community": "Aseḍfeṛ ar Temɣiwant n Open WebUI", @@ -1648,6 +1660,7 @@ "Relevance": "Tawatit", "Relevance Threshold": "", "Remember Dismissal": "Ccfawa ɣef ugdal", + "Reminder": "", "Remove": "Kkes", "Remove {{MODELID}} from list.": "Kkes {{MODELID}} seg wumuɣ.", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Tazwara n ubadu", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Aya ad yekkes {NAME}} akked akk ayen yellan deg-s.", "This will delete all models including custom models": "Aya ad yekkes akk timudmin yellan gar-asent timudmin n tannumi", "This will delete all models including custom models and cannot be undone.": "Aya ad yekkes akk timudmin gar-asent timudmin tudmawanin yerna ur yezmir yiwen ad tent-id-yerr.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Aya ad yales taffa n tmussni u ad yemtawi akk ifuyla. Tebɣiḍ ad tkemmleḍ?", "Thorough explanation": "Asegzi leqqayen", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Kkes asenteḍ", + "Unpin from Sidebar": "", "Unravel secrets": "Sban-d ayen yeffren", "Unshare Chat": "", "Unsupported file type.": "Tawsit n ufaylu ur tettusefrak ara.", diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 2c4d22b843..e29c402508 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}}의 채팅", "{{webUIName}} Backend Required": "{{webUIName}} 백엔드가 필요합니다.", "*Prompt node ID(s) are required for image generation": "이미지 생성에는 프롬프트 노드 ID가 필요합니다.", + "1 hour before": "", "1 Source": "소스1", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "새로운 버전 (v{{LATEST_VERSION}})을 사용할 수 있습니다.", @@ -201,6 +206,7 @@ "Ask a question": "질문하기", "Assistant": "어시스턴트", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "지식 기반에서 파일 첨부", "Attach Files": "", "Attach Knowledge": "지식 기반 첨부", @@ -275,6 +281,7 @@ "Bypass Web Loader": "웹 콘텐츠 불러오기 생략", "Cache Base Model List": "기본 모델 목록 캐시", "Calendar": "캘린더", + "Calendar deleted": "", "Calendars": "", "Call": "음성 기능", "Call feature is not supported when using Web STT engine": "웹 STT 엔진 사용 시, 음성 기능은 지원되지 않습니다.", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "OpenAPI 호환 외부 도구 서버에 연결합니다.", "Connected ({{type}})": "", "Connection failed": "연결 실패", + "Connection lost. Reconnecting...": "", "Connection successful": "연결 성공", "Connection Type": "연결 방식", "Connections": "연결", @@ -524,6 +532,8 @@ "Delete All Chats": "모든 채팅 삭제", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "채팅 삭제", "Delete chat?": "채팅을 삭제하시겠습니까?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "링크 복사 실패", "Failed to create API Key.": "API 키 생성에 실패했습니다.", + "Failed to delete calendar": "", "Failed to delete note": "노트 삭제 실패", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "파일 내용 추출 실패: {{error}}", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "추론 난이도", "Reasoning Tags": "추론 태그", "Recently Used": "", + "Reconnected": "", "Record": "녹음", "Record voice": "음성 녹음", "Redirecting you to Open WebUI Community": "OpenWebUI 커뮤니티로 리디렉션 중", @@ -1647,6 +1659,7 @@ "Relevance": "관련도", "Relevance Threshold": "관련성 임계값", "Remember Dismissal": "다시 보지 않기", + "Reminder": "", "Remove": "삭제", "Remove {{MODELID}} from list.": "{{MODELID}}를 목록에서 제거.", "Remove action": "", @@ -1892,7 +1905,10 @@ "Start a new conversation": "새 대화 시작", "Start of the channel": "채널 시작", "Start Tag": "시작 태그", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "상태", "Status cleared successfully": "상태 초기화에 성공했습니다", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "{{NAME}}모든 내용을 삭제합니다.", "This will delete all models including custom models": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제됩니다", "This will delete all models including custom models and cannot be undone.": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제되며 실행 취소할 수 없습니다.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "지식 기반과 모든 파일 연동을 초기화합니다. 계속 하시겠습니까?", "Thorough explanation": "완전한 설명", "Thought": "", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} 언로드", "Unlock mysteries": "미스터리 풀기", "Unpin": "고정 해제", + "Unpin from Sidebar": "", "Unravel secrets": "비밀 풀기", "Unshare Chat": "", "Unsupported file type.": "지원하지 않는 파일 형식", diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json index 0f2df1e48d..784832cde7 100644 --- a/src/lib/i18n/locales/lt-LT/translation.json +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "{{user}} susirašinėjimai", "{{webUIName}} Backend Required": "{{webUIName}} būtinas serveris", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -204,6 +209,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -278,6 +284,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Skambinti", "Call feature is not supported when using Web STT engine": "Skambučio funkcionalumas neleidžiamas naudojant Web STT variklį", @@ -415,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Ryšiai", @@ -527,6 +535,8 @@ "Delete All Chats": "Ištrinti visus pokalbius", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Ištrinti pokalbį", "Delete chat?": "Ištrinti pokalbį?", "Delete Event": "", @@ -888,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Nepavyko sukurti API rakto", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1627,6 +1638,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Įrašyti balsą", "Redirecting you to Open WebUI Community": "Perkeliam Jus į OpenWebUI bendruomenę", @@ -1650,6 +1662,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Pašalinti", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1898,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Kanalo pradžia", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2011,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "Platus paaiškinimas", "Thought": "", @@ -2097,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Atsemigti", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/lv-LV/translation.json b/src/lib/i18n/locales/lv-LV/translation.json index 9b28e934cf..09ae34c6a3 100644 --- a/src/lib/i18n/locales/lv-LV/translation.json +++ b/src/lib/i18n/locales/lv-LV/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "{{user}} tērzēšanas", "{{webUIName}} Backend Required": "Nepieciešama {{webUIName}} aizmugursistēma", "*Prompt node ID(s) are required for image generation": "*Attēla ģenerēšanai nepieciešami uzvednes mezgla ID", + "1 hour before": "", "1 Source": "1 avots", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Sadarbības kanāls, kurā cilvēki pievienojas kā dalībnieki", "A discussion channel where access is controlled by groups and permissions": "Diskusiju kanāls, kur piekļuvi kontrolē grupas un atļaujas", "A new version (v{{LATEST_VERSION}}) is now available.": "Ir pieejama jauna versija (v{{LATEST_VERSION}}).", @@ -203,6 +208,7 @@ "Ask a question": "Uzdot jautājumu", "Assistant": "Asistents", "Async Embedding Processing": "Asinhronā iegulšanas apstrāde", + "At time of event": "", "Attach File From Knowledge": "Pievienot failu no zināšanām", "Attach Files": "", "Attach Knowledge": "Pievienot zināšanau bāzi", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Apiet tīmekļa ielādētāju", "Cache Base Model List": "Kešot bāzes modeļu sarakstu", "Calendar": "Kalendārs", + "Calendar deleted": "", "Calendars": "", "Call": "Zvans", "Call feature is not supported when using Web STT engine": "Zvana funkcija nav atbalstīta, izmantojot Web STT dzinēju", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Savienojieties ar saviem OpenAPI saderīgajiem ārējo rīku serveriem.", "Connected ({{type}})": "", "Connection failed": "Savienojums neizdevās", + "Connection lost. Reconnecting...": "", "Connection successful": "Savienojums veiksmīgs", "Connection Type": "Savienojuma tips", "Connections": "Savienojumi", @@ -526,6 +534,8 @@ "Delete All Chats": "Dzēst visas tērzēšanas", "Delete all contents inside this folder": "Dzēst visu saturu šajā mapē", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Dzēst tērzēšanu", "Delete chat?": "Dzēst tērzēšanu?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Neizdevās nokopēt saiti", "Failed to create API Key.": "Neizdevās izveidot API atslēgu.", + "Failed to delete calendar": "", "Failed to delete note": "Neizdevās dzēst piezīmi", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Neizdevās ekstrahēt saturu no faila: {{error}}", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Spriedumu pūles", "Reasoning Tags": "Spriedumu tagi", "Recently Used": "", + "Reconnected": "", "Record": "Ierakstīt", "Record voice": "Ierakstīt balsi", "Redirecting you to Open WebUI Community": "Novirza jūs uz Open WebUI kopienu", @@ -1649,6 +1661,7 @@ "Relevance": "Atbilstība", "Relevance Threshold": "Atbilstības slieksnis", "Remember Dismissal": "Atcerēties noraidījumu", + "Reminder": "", "Remove": "Noņemt", "Remove {{MODELID}} from list.": "Noņemt {{MODELID}} no saraksta.", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "Sākt jaunu sarunu", "Start of the channel": "Kanāla sākums", "Start Tag": "Sākuma tags", + "Starting in {{count}} minutes_zero": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "Statuss", "Status cleared successfully": "Statuss veiksmīgi notīrīts", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Tas dzēsīs {{NAME}} un visu tā saturu.", "This will delete all models including custom models": "Tas dzēsīs visus modeļus, ieskaitot pielāgotos modeļus", "This will delete all models including custom models and cannot be undone.": "Tas dzēsīs visus modeļus, ieskaitot pielāgotos modeļus, un to nevar atsaukt.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Tas atiestatīs zināšanu bāzi un sinhronizēs visus failus. Vai vēlaties turpināt?", "Thorough explanation": "Pamatīgs skaidrojums", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Izlādēs {{FROM_NOW}}", "Unlock mysteries": "Atklājiet noslēpumus", "Unpin": "Atspraust", + "Unpin from Sidebar": "", "Unravel secrets": "Atšķetiniet noslēpumus", "Unshare Chat": "", "Unsupported file type.": "Neatbalstīts faila tips.", diff --git a/src/lib/i18n/locales/ms-MY/translation.json b/src/lib/i18n/locales/ms-MY/translation.json index 7f23e7ed77..8dd75ac052 100644 --- a/src/lib/i18n/locales/ms-MY/translation.json +++ b/src/lib/i18n/locales/ms-MY/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "Perbualan {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend diperlukan", "*Prompt node ID(s) are required for image generation": "*ID nod Prompt diperlukan untuk penjanaan imej", + "1 hour before": "", "1 Source": "1 Sumber", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m_masa_lalu", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Saluran kolaborasi di mana orang ramai menyertai sebagai ahli", "A discussion channel where access is controlled by groups and permissions": "Saluran perbincangan di mana akses dikawal oleh kumpulan dan kebenaran", "A new version (v{{LATEST_VERSION}}) is now available.": "Versi baru (v{{LATEST_VERSION}}) kini tersedia.", @@ -201,6 +206,7 @@ "Ask a question": "Tanya soalan", "Assistant": "Pembantu", "Async Embedding Processing": "Pemprosesan Embedding Tak Segerak", + "At time of event": "", "Attach File From Knowledge": "Lampirkan Fail Daripada Pengetahuan", "Attach Files": "", "Attach Knowledge": "Lampirkan Pengetahuan", @@ -275,6 +281,7 @@ "Bypass Web Loader": "Langkau Pemuat Web", "Cache Base Model List": "Senarai Model Asas Cache", "Calendar": "Kalendar", + "Calendar deleted": "", "Calendars": "", "Call": "Hubungi", "Call feature is not supported when using Web STT engine": "Ciri panggilan tidak disokong apabila menggunakan enjin Web STT", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Sambung ke pelayan alat luaran yang serasi dengan OpenAPI anda sendiri.", "Connected ({{type}})": "", "Connection failed": "Sambungan gagal", + "Connection lost. Reconnecting...": "", "Connection successful": "Sambungan berjaya", "Connection Type": "Jenis Sambungan", "Connections": "Sambungan", @@ -524,6 +532,8 @@ "Delete All Chats": "Padam Semua Perbualan", "Delete all contents inside this folder": "Padam semua kandungan dalam folder ini", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Padam Perbualan", "Delete chat?": "Padam perbualan?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "Gagal menyambung ke pelayan terminal {{URL}}", "Failed to copy link": "Gagal menyalin pautan", "Failed to create API Key.": "Gagal mencipta kekunci API", + "Failed to delete calendar": "", "Failed to delete note": "Gagal memadamkan nota", "Failed to download image": "Gagal memuat turun imej", "Failed to extract content from the file: {{error}}": "Gagal mengekstrak kandungan daripada fail: {{error}}", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "Usaha Penaakulan", "Reasoning Tags": "Tag Penaakulan", "Recently Used": "", + "Reconnected": "", "Record": "Rakaman", "Record voice": "Rakam suara", "Redirecting you to Open WebUI Community": "Membawa anda ke Komuniti OpenWebUI", @@ -1647,6 +1659,7 @@ "Relevance": "Perkaitan", "Relevance Threshold": "Ambang Perkaitan", "Remember Dismissal": "Ingat Penutupan", + "Reminder": "", "Remove": "Hapuskan", "Remove {{MODELID}} from list.": "Keluarkan {{MODELID}} daripada senarai.", "Remove action": "Keluarkan tindakan", @@ -1892,7 +1905,10 @@ "Start a new conversation": "Mulai perbualan baru", "Start of the channel": "Permulaan saluran", "Start Tag": "Tag Permulaan", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kernel sedang dimulakan...", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status telah dihapus dengan berjaya", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "Ini akan memadam {{NAME}} dan semua kandungannya.", "This will delete all models including custom models": "Ini akan memadam semua model termasuk model tersuai", "This will delete all models including custom models and cannot be undone.": "Ini akan memadam semua model termasuk model tersuai dan tidak boleh dibuat asal.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Ini akan menetapkan semula pangkalan pengetahuan dan menyegerakkan semua fail. Adakah anda ingin meneruskan?", "Thorough explanation": "Penjelasan menyeluruh", "Thought": "", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "Membuang {{FROM_NOW}}", "Unlock mysteries": "Buka Misteri", "Unpin": "Nyahsematkan", + "Unpin from Sidebar": "", "Unravel secrets": "Ungkap Rahsia", "Unshare Chat": "Batalkan Perkongsian Sembang", "Unsupported file type.": "Jenis fail tidak disokong.", diff --git a/src/lib/i18n/locales/nb-NO/translation.json b/src/lib/i18n/locales/nb-NO/translation.json index ebfff87340..7f45c82157 100644 --- a/src/lib/i18n/locales/nb-NO/translation.json +++ b/src/lib/i18n/locales/nb-NO/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} sine samtaler", "{{webUIName}} Backend Required": "Backend til {{webUIName}} kreves", "*Prompt node ID(s) are required for image generation": "Node-ID-er for ledetekst kreves for generering av bilder", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "En ny versjon (v{{LATEST_VERSION}}) er nå tilgjengelig.", @@ -202,6 +207,7 @@ "Ask a question": "Still et spørsmål", "Assistant": "Assistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Kalender", + "Calendar deleted": "", "Calendars": "", "Call": "Ring", "Call feature is not supported when using Web STT engine": "Ringefunksjonen støttes ikke når du bruker Web STT-motoren", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Tilkoblinger", @@ -525,6 +533,8 @@ "Delete All Chats": "Slett alle chatter", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Slett chat", "Delete chat?": "Slette chat?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Kan ikke opprette en API-nøkkel.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Resonneringsinnsats", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Ta opp tale", "Redirecting you to Open WebUI Community": "Omdirigerer deg til OpenWebUI-fellesskapet", @@ -1648,6 +1660,7 @@ "Relevance": "Relevans", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Fjern", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Starten av kanalen", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dette sletter {{NAME}} og alt innholdet.", "This will delete all models including custom models": "Dette sletter alle modeller, inkludert tilpassede modeller", "This will delete all models including custom models and cannot be undone.": "Dette sletter alle modeller, inkludert tilpassede modeller, og kan ikke angres.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dette tilbakestiller kunnskapsbasen og synkroniserer alle filer. Vil du fortsette?", "Thorough explanation": "Grundig forklaring", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Lås opp mysterier", "Unpin": "Løsne", + "Unpin from Sidebar": "", "Unravel secrets": "Avslør hemmeligheter", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index 3458ccf314..4651d33fc5 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'s chats", "{{webUIName}} Backend Required": "{{webUIName}} Backend verplicht", "*Prompt node ID(s) are required for image generation": "*Prompt node ID('s) zijn vereist voor het genereren van afbeeldingen", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Een nieuwe versie (v{{LATEST_VERSION}}) is nu beschikbaar", @@ -202,6 +207,7 @@ "Ask a question": "Stel een vraag", "Assistant": "Assistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Agenda", + "Calendar deleted": "", "Calendars": "", "Call": "Oproep", "Call feature is not supported when using Web STT engine": "Belfunctie wordt niet ondersteund bij gebruik van de Web STT engine", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Verbind met je eigen OpenAPI-compatibele externe gereedschapservers", "Connected ({{type}})": "", "Connection failed": "Connectie mislukt", + "Connection lost. Reconnecting...": "", "Connection successful": "Connectie succesvol", "Connection Type": "Connectie type", "Connections": "Verbindingen", @@ -525,6 +533,8 @@ "Delete All Chats": "Verwijder alle chats", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Verwijder chat", "Delete chat?": "Verwijder chat?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Kan API Key niet aanmaken.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Redeneerinspanning", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Neem stem op", "Redirecting you to Open WebUI Community": "Je wordt doorgestuurd naar OpenWebUI Community", @@ -1648,6 +1660,7 @@ "Relevance": "Relevantie", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Verwijderen", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Begin van het kanaal", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Dit zal {{NAME}} verwijderen en al zijn inhoud.", "This will delete all models including custom models": "Dit zal alle modellen, ook aangepaste modellen, verwijderen", "This will delete all models including custom models and cannot be undone.": "Dit zal alle modellen, ook aangepaste modellen, verwijderen en kan niet ongedaan worden gemaakt", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dit zal de kennisdatabase resetten en alle bestanden synchroniseren. Wilt u doorgaan?", "Thorough explanation": "Grondige uitleg", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Ontsleutel mysteries", "Unpin": "Losmaken", + "Unpin from Sidebar": "", "Unravel secrets": "Ontrafel geheimen", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/pa-IN/translation.json b/src/lib/i18n/locales/pa-IN/translation.json index c6d006cb1a..d29adc4b55 100644 --- a/src/lib/i18n/locales/pa-IN/translation.json +++ b/src/lib/i18n/locales/pa-IN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} ਦੀਆਂ ਗੱਲਾਂ", "{{webUIName}} Backend Required": "{{webUIName}} ਬੈਕਐਂਡ ਲੋੜੀਂਦਾ ਹੈ", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "ਕਨੈਕਸ਼ਨ", @@ -525,6 +533,8 @@ "Delete All Chats": "ਸਾਰੀਆਂ ਚੈਟਾਂ ਨੂੰ ਮਿਟਾਓ", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "ਗੱਲਬਾਤ ਮਿਟਾਓ", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API ਕੁੰਜੀ ਬਣਾਉਣ ਵਿੱਚ ਅਸਫਲ।", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "ਆਵਾਜ਼ ਰਿਕਾਰਡ ਕਰੋ", "Redirecting you to Open WebUI Community": "ਤੁਹਾਨੂੰ ਓਪਨਵੈਬਯੂਆਈ ਕਮਿਊਨਿਟੀ ਵੱਲ ਰੀਡਾਇਰੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "ਹਟਾਓ", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "ਚੈਨਲ ਦੀ ਸ਼ੁਰੂਆਤ", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "ਵਿਸਥਾਰ ਨਾਲ ਵਿਆਖਿਆ", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index 1dff552813..7143c47bc7 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Czaty użytkownika {{user}}", "{{webUIName}} Backend Required": "Wymagany backend {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Do generowania obrazów wymagane jest ID węzła promptu", + "1 hour before": "", "1 Source": "1 źródło", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Kanał współpracy, do którego użytkownicy dołączają jako członkowie", "A discussion channel where access is controlled by groups and permissions": "Kanał dyskusyjny, do którego dostęp jest kontrolowany przez grupy i uprawnienia", "A new version (v{{LATEST_VERSION}}) is now available.": "Dostępna jest nowa wersja (v{{LATEST_VERSION}}).", @@ -204,6 +209,7 @@ "Ask a question": "Zadaj pytanie", "Assistant": "Asystent", "Async Embedding Processing": "Asynchroniczne przetwarzanie embeddingów", + "At time of event": "", "Attach File From Knowledge": "Dołącz plik z bazy wiedzy", "Attach Files": "", "Attach Knowledge": "Dołącz bazę wiedzy", @@ -278,6 +284,7 @@ "Bypass Web Loader": "Pomiń Web Loader", "Cache Base Model List": "Cachuj listę modeli bazowych", "Calendar": "Kalendarz", + "Calendar deleted": "", "Calendars": "", "Call": "Rozmowa", "Call feature is not supported when using Web STT engine": "Funkcja rozmowy nie jest obsługiwana przy użyciu przeglądarkowego silnika STT", @@ -415,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Połącz z własnymi serwerami narzędzi zgodnymi z OpenAPI.", "Connected ({{type}})": "", "Connection failed": "Połączenie nieudane", + "Connection lost. Reconnecting...": "", "Connection successful": "Połączenie udane", "Connection Type": "Typ połączenia", "Connections": "Połączenia", @@ -527,6 +535,8 @@ "Delete All Chats": "Usuń wszystkie czaty", "Delete all contents inside this folder": "Usuń całą zawartość tego folderu", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Usuń czat", "Delete chat?": "Usunąć czat?", "Delete Event": "", @@ -888,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Nie udało się skopiować linku", "Failed to create API Key.": "Nie udało się utworzyć klucza API.", + "Failed to delete calendar": "", "Failed to delete note": "Nie udało się usunąć notatki", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Nie udało się wyodrębnić treści z pliku: {{error}}", @@ -1627,6 +1638,7 @@ "Reasoning Effort": "Reasoning Effort", "Reasoning Tags": "Reasoning Tags", "Recently Used": "", + "Reconnected": "", "Record": "Nagraj", "Record voice": "Nagraj głos", "Redirecting you to Open WebUI Community": "Przekierowanie do społeczności Open WebUI", @@ -1650,6 +1662,7 @@ "Relevance": "Trafność", "Relevance Threshold": "Próg trafności", "Remember Dismissal": "Zapamiętaj odrzucenie", + "Reminder": "", "Remove": "Usuń", "Remove {{MODELID}} from list.": "Usuń {{MODELID}} z listy.", "Remove action": "", @@ -1898,7 +1911,13 @@ "Start a new conversation": "Rozpocznij nową rozmowę", "Start of the channel": "Początek kanału", "Start Tag": "Tag startowy", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "Status", "Status cleared successfully": "Status wyczyszczony pomyślnie", @@ -2011,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "To usunie {{NAME}} i całą zawartość.", "This will delete all models including custom models": "To usunie wszystkie modele (w tym własne).", "This will delete all models including custom models and cannot be undone.": "To usunie wszystkie modele i jest nieodwracalne.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "To zresetuje bazę wiedzy i zsynchronizuje pliki. Kontynuować?", "Thorough explanation": "Dokładne wyjaśnienie", "Thought": "", @@ -2097,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "Odładowuje za {{FROM_NOW}}", "Unlock mysteries": "Odkrywaj tajemnice", "Unpin": "Odepnij", + "Unpin from Sidebar": "", "Unravel secrets": "Rozwiązuj zagadki", "Unshare Chat": "", "Unsupported file type.": "Nieobsługiwany typ pliku.", diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index 0954c0a91a..bde1024811 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} necessário", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) são obrigatórios para gerar imagens", + "1 hour before": "", "1 Source": "1 Origem", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1m atrás", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Um canal de colaboração onde as pessoas se juntam como membros.", "A discussion channel where access is controlled by groups and permissions": "Um canal de discussão onde o acesso é controlado por grupos e permissões.", "A new version (v{{LATEST_VERSION}}) is now available.": "Uma nova versão (v{{LATEST_VERSION}}) está disponível.", @@ -203,6 +208,7 @@ "Ask a question": "Faça uma pergunta", "Assistant": "Assistente", "Async Embedding Processing": "Processamento de Embedding assíncrono", + "At time of event": "", "Attach File From Knowledge": "Anexar arquivo da base de conhecimento", "Attach Files": "Anexar arquivos", "Attach Knowledge": "Anexar Base de Conhecimento", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Ignorar carregador da Web", "Cache Base Model List": "Lista de modelos base de cache", "Calendar": "Calendário", + "Calendar deleted": "", "Calendars": "", "Call": "Chamada", "Call feature is not supported when using Web STT engine": "O recurso de chamada não é suportado ao usar o mecanismo Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Conecte-se aos seus próprios servidores de ferramentas externas compatíveis com OpenAPI.", "Connected ({{type}})": "Conectado ({{type}})", "Connection failed": "Falha na conexão", + "Connection lost. Reconnecting...": "", "Connection successful": "Conexão bem-sucedida", "Connection Type": "Tipo de conexão", "Connections": "Conexões", @@ -526,6 +534,8 @@ "Delete All Chats": "Excluir Todos os Chats", "Delete all contents inside this folder": "Apague todo o conteúdo desta pasta.", "Delete automation?": "Excluir automação?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Excluir Chat", "Delete chat?": "Excluir chat?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Falha ao conectar ao servidor de terminal {{URL}}", "Failed to copy link": "Falha ao copiar o link", "Failed to create API Key.": "Falha ao criar a Chave API.", + "Failed to delete calendar": "", "Failed to delete note": "Falha ao excluir a nota", "Failed to download image": "Falha ao baixar a imagem", "Failed to extract content from the file: {{error}}": "Falha ao extrair conteúdo do arquivo: {{error}}", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Esforço de raciocínio", "Reasoning Tags": "Tags de raciocínio", "Recently Used": "Usado recentemente", + "Reconnected": "", "Record": "Gravar", "Record voice": "Gravar voz", "Redirecting you to Open WebUI Community": "Redirecionando você para a Comunidade OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Relevância", "Relevance Threshold": "Limiar de Relevância", "Remember Dismissal": "Lembrar da dispensa", + "Reminder": "", "Remove": "Remover", "Remove {{MODELID}} from list.": "Remover {{MODELID}} da lista.", "Remove action": "Remover ação", @@ -1896,7 +1909,12 @@ "Start a new conversation": "Iniciar uma nova conversa", "Start of the channel": "Início do canal", "Start Tag": "Tag inicial", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciando kernel...", + "Starting now": "", "State": "Estado", "Status": "Status", "Status cleared successfully": "Status liberado com sucesso", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Esta ação excluirá {{NAME}} e todos seus conteúdos.", "This will delete all models including custom models": "Isto vai excluir todos os modelos, incluindo personalizados", "This will delete all models including custom models and cannot be undone.": "Isto vai excluir todos os modelos, incluindo personalizados e não pode ser desfeito.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Esta ação resetará a base de conhecimento e sincronizará todos os arquivos. Deseja continuar?", "Thorough explanation": "Explicação detalhada", "Thought": "Pensamento", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Descarrega {{FROM_NOW}}", "Unlock mysteries": "Desvendar mistérios", "Unpin": "Desfixar", + "Unpin from Sidebar": "", "Unravel secrets": "Desvendar segredos", "Unshare Chat": "Cancelar compartilhamento do chat", "Unsupported file type.": "Tipo de arquivo não suportado.", diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index c8f23d1dea..1b9c2e7e48 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} Necessário", "*Prompt node ID(s) are required for image generation": "*ID(s) do nó de prompt são necessários para a geração de imagem", + "1 hour before": "", "1 Source": "Uma Fonte", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "há 1 minuto", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Um canal de colaboração onde as pessoas entram como membros", "A discussion channel where access is controlled by groups and permissions": "Um canal de discussão onde o acesso é controlado por grupos e permissões", "A new version (v{{LATEST_VERSION}}) is now available.": "Uma nova versão (v{{LATEST_VERSION}}) está agora disponível.", @@ -203,6 +208,7 @@ "Ask a question": "Fazer uma pergunta", "Assistant": "Assistente", "Async Embedding Processing": "Incorporação de Processamento Assíncrono", + "At time of event": "", "Attach File From Knowledge": "Anexar Ficheiro do Conhecimento", "Attach Files": "", "Attach Knowledge": "Anexar Conhecimento", @@ -277,6 +283,7 @@ "Bypass Web Loader": "Ignorar Carregador Web", "Cache Base Model List": "Cache da Lista de Modelos Base", "Calendar": "Calendário", + "Calendar deleted": "", "Calendars": "", "Call": "Chamar", "Call feature is not supported when using Web STT engine": "A funcionalide de Chamar não é suportada quando usa um motor Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Ligar ao seu próprio servidor de ferramentas externo compatível com a OpenAI.", "Connected ({{type}})": "", "Connection failed": "Ligação falhou", + "Connection lost. Reconnecting...": "", "Connection successful": "Ligação bem sucedida", "Connection Type": "Tipo de ligação", "Connections": "Ligações", @@ -526,6 +534,8 @@ "Delete All Chats": "Apagar todas as conversas", "Delete all contents inside this folder": "Apagar todo o conteúdo dentro desta pasta", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Apagar Conversa", "Delete chat?": "Apagar conversa?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Falha na ligação ao terminal de servidores {{URL}}", "Failed to copy link": "Falha ao copiar a hiperligação", "Failed to create API Key.": "Falha ao criar a Chave da API.", + "Failed to delete calendar": "", "Failed to delete note": "Falha ao apagar a nota", "Failed to download image": "Falha ao transferir a imagem", "Failed to extract content from the file: {{error}}": "Falha ao extrair conteúdo do ficheiro: {{error}}", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Esforço de Raciocínio", "Reasoning Tags": "Etiquetas de Raciocínio", "Recently Used": "", + "Reconnected": "", "Record": "Gravar", "Record voice": "Gravar voz", "Redirecting you to Open WebUI Community": "Redirecionando-o para a Comunidade OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Relevância", "Relevance Threshold": "Limite de Relevância", "Remember Dismissal": "Lembrar Descartar", + "Reminder": "", "Remove": "Remover", "Remove {{MODELID}} from list.": "Remover {{MODELID}} da lista.", "Remove action": "Remover ação", @@ -1896,7 +1909,12 @@ "Start a new conversation": "Iniciar uma nova conversa", "Start of the channel": "Início do canal", "Start Tag": "Início da Tag", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Iniciando kernel...", + "Starting now": "", "State": "", "Status": "Estado", "Status cleared successfully": "Estado limpo com sucesso", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Isto irá excluir {{NAME}} e todo o seu conteúdo.", "This will delete all models including custom models": "Isto irá excluir todos os modelos, incluindo os modelos personalizados", "This will delete all models including custom models and cannot be undone.": "Isto irá excluir todos os modelos, incluindo os modelos personalizados, e não pode ser desfeito.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Isto irá redefinir a base de conhecimento e sincronizar todos os arquivos. Deseja continuar?", "Thorough explanation": "Explicação Minuciosa", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "Descarreva {{FROM_NOW}}", "Unlock mysteries": "Desbloquear Mistérios", "Unpin": "Desafixar", + "Unpin from Sidebar": "", "Unravel secrets": "Desvendar segredos", "Unshare Chat": "Parar partilha de conversa", "Unsupported file type.": "Tipo de ficheiro não suportado", diff --git a/src/lib/i18n/locales/ro-RO/translation.json b/src/lib/i18n/locales/ro-RO/translation.json index 0215a6eacc..3028840716 100644 --- a/src/lib/i18n/locales/ro-RO/translation.json +++ b/src/lib/i18n/locales/ro-RO/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Conversațiile lui {{user}}", "{{webUIName}} Backend Required": "Este necesar backend-ul {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Sunt necesare ID-urile nodurilor de solicitare pentru generarea imaginii*", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "O nouă versiune (v{{LATEST_VERSION}}) este acum disponibilă.", @@ -203,6 +208,7 @@ "Ask a question": "Pune o întrebare", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -277,6 +283,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Apel", "Call feature is not supported when using Web STT engine": "Funcția de apel nu este suportată când se utilizează motorul Web STT", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "Conexiune eșuată", + "Connection lost. Reconnecting...": "", "Connection successful": "Conexiune reușită", "Connection Type": "Tip conexiune", "Connections": "Conexiuni", @@ -526,6 +534,8 @@ "Delete All Chats": "Șterge Toate Conversațiile", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Șterge Conversația", "Delete chat?": "Șterge conversația?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Crearea cheii API a eșuat.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Înregistrează vocea", "Redirecting you to Open WebUI Community": "Vă redirecționăm către Comunitatea OpenWebUI", @@ -1649,6 +1661,7 @@ "Relevance": "Relevanță", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Înlătură", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Începutul canalului", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Acest lucru va șterge {{NAME}} și toate conținuturile sale.", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Aceasta va reseta baza de cunoștințe și va sincroniza toate fișierele. Doriți să continuați?", "Thorough explanation": "Explicație detaliată", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Anulează Fixarea", + "Unpin from Sidebar": "", "Unravel secrets": "Dezvăluie secretele", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index 15663aecc0..954d8f7f4e 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Чаты {{user}}'а", "{{webUIName}} Backend Required": "Необходимо подключение к серверу {{webUIName}}", "*Prompt node ID(s) are required for image generation": "ID узлов промптов обязательны для генерации изображения", + "1 hour before": "", "1 Source": "1 Источник", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 мин назад", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "Канал для совместной работы с присоединением участников", "A discussion channel where access is controlled by groups and permissions": "Обсуждение канала, где доступ контролируется группами и разрешениями", "A new version (v{{LATEST_VERSION}}) is now available.": "Новая версия (v{{LATEST_VERSION}}) теперь доступна.", @@ -204,6 +209,7 @@ "Ask a question": "Задать вопрос", "Assistant": "Ассистент", "Async Embedding Processing": "Асинхронная обработка эмбеддингов", + "At time of event": "", "Attach File From Knowledge": "Прикрепить файл из знаний", "Attach Files": "", "Attach Knowledge": "Прикрепить знания", @@ -278,6 +284,7 @@ "Bypass Web Loader": "Обход веб-загрузчика", "Cache Base Model List": "Кэшировать список базовых моделей", "Calendar": "Календарь", + "Calendar deleted": "", "Calendars": "", "Call": "Вызов", "Call feature is not supported when using Web STT engine": "Функция вызова не поддерживается при использовании Web STT (распознавание речи) движка", @@ -415,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Подключитесь к вашим собственным внешним инструментальным серверам, совместимым с OpenAPI.", "Connected ({{type}})": "Подключено ({{type}})", "Connection failed": "Подключение не удалось", + "Connection lost. Reconnecting...": "", "Connection successful": "Успешное подключение", "Connection Type": "Тип подключения", "Connections": "Подключения", @@ -527,6 +535,8 @@ "Delete All Chats": "Удалить ВСЕ Чаты", "Delete all contents inside this folder": "Удалить все содержимое внутри этой папки", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Удалить Чат", "Delete chat?": "Удалить чат?", "Delete Event": "", @@ -888,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "Не удалось подключиться к серверу терминала {{URL}}", "Failed to copy link": "Не удалось скопировать ссылку", "Failed to create API Key.": "Не удалось создать ключ API.", + "Failed to delete calendar": "", "Failed to delete note": "Не удалось удалить заметку", "Failed to download image": "Не удалось загрузить изображение", "Failed to extract content from the file: {{error}}": "Не удалось извлечь содержимое из файла: {{error}}", @@ -1627,6 +1638,7 @@ "Reasoning Effort": "Усилия для рассуждения", "Reasoning Tags": "Теги рассуждения", "Recently Used": "", + "Reconnected": "", "Record": "Запись", "Record voice": "Записать голос", "Redirecting you to Open WebUI Community": "Перенаправляем вас в сообщество OpenWebUI", @@ -1650,6 +1662,7 @@ "Relevance": "Релевантность", "Relevance Threshold": "Порог релевантности", "Remember Dismissal": "Запомнить отклонение", + "Reminder": "", "Remove": "Удалить", "Remove {{MODELID}} from list.": "Удалить {{MODELID}} из списка.", "Remove action": "Удалить действие", @@ -1898,7 +1911,13 @@ "Start a new conversation": "Начать новый разговор", "Start of the channel": "Начало канала", "Start Tag": "Начальный тег", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Запуск ядра...", + "Starting now": "", "State": "", "Status": "Статус", "Status cleared successfully": "Статус успешно очищен", @@ -2011,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "При этом будет удален {{NAME}} и все его содержимое.", "This will delete all models including custom models": "Это приведет к удалению всех моделей, включая пользовательские модели.", "This will delete all models including custom models and cannot be undone.": "При этом будут удалены все модели, включая пользовательские, и это действие нельзя будет отменить.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Это сбросит базу знаний и синхронизирует все файлы. Хотите продолжить?", "Thorough explanation": "Подробное объяснение", "Thought": "Рассуждение", @@ -2097,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "Выгрузка из памяти {{FROM_NOW}}", "Unlock mysteries": "Разблокируйте тайны", "Unpin": "Открепить", + "Unpin from Sidebar": "", "Unravel secrets": "Разгадать секреты", "Unshare Chat": "Отменить публикацию чата", "Unsupported file type.": "Неподдерживаемый тип файла.", diff --git a/src/lib/i18n/locales/sk-SK/translation.json b/src/lib/i18n/locales/sk-SK/translation.json index 74d16d847c..0ecf193014 100644 --- a/src/lib/i18n/locales/sk-SK/translation.json +++ b/src/lib/i18n/locales/sk-SK/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "{{user}}'s konverzácie", "{{webUIName}} Backend Required": "Vyžaduje sa {{webUIName}} Backend", "*Prompt node ID(s) are required for image generation": "*Sú potrebné IDs pre prompt node na generovanie obrázkov", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Nová verzia (v{{LATEST_VERSION}}) je teraz k dispozícii.", @@ -204,6 +209,7 @@ "Ask a question": "Opýtajte sa otázku", "Assistant": "Asistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Pripojiť znalosti", @@ -278,6 +284,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Volanie", "Call feature is not supported when using Web STT engine": "Funkcia volania nie je podporovaná pri použití Web STT engine.", @@ -415,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Pripojenia", @@ -527,6 +535,8 @@ "Delete All Chats": "Odstrániť všetky konverzácie", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Odstrániť chat", "Delete chat?": "Odstrániť konverzáciu?", "Delete Event": "", @@ -888,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Nepodarilo sa vytvoriť API kľúč.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1627,6 +1638,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Nahrať hlas", "Redirecting you to Open WebUI Community": "Presmerovanie na komunitu OpenWebUI", @@ -1650,6 +1662,7 @@ "Relevance": "Relevancia", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Odstrániť", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1898,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Začiatok kanála", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2011,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "Týmto dôjde k odstráneniu {{NAME}} a všetkých jeho obsahov.", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Toto obnoví znalostnú databázu a synchronizuje všetky súbory. Prajete si pokračovať?", "Thorough explanation": "Obsiahle vysvetlenie", "Thought": "", @@ -2097,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "Odopnúť", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/sr-RS/translation.json b/src/lib/i18n/locales/sr-RS/translation.json index fd5e72e1fb..647eb187b5 100644 --- a/src/lib/i18n/locales/sr-RS/translation.json +++ b/src/lib/i18n/locales/sr-RS/translation.json @@ -34,8 +34,13 @@ "{{user}}'s Chats": "Ћаскања корисника {{user}}", "{{webUIName}} Backend Required": "Захтева се {{webUIName}} позадинац", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -203,6 +208,7 @@ "Ask a question": "Постави питање", "Assistant": "Помоћник", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -277,6 +283,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "Позив", "Call feature is not supported when using Web STT engine": "", @@ -414,6 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Везе", @@ -526,6 +534,8 @@ "Delete All Chats": "Обриши сва ћаскања", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Обриши ћаскање", "Delete chat?": "Обрисати ћаскање?", "Delete Event": "", @@ -887,6 +897,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Неуспешно стварање API кључа.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1626,6 +1637,7 @@ "Reasoning Effort": "Јачина размишљања", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Сними глас", "Redirecting you to Open WebUI Community": "Преусмеравање на OpenWebUI заједницу", @@ -1649,6 +1661,7 @@ "Relevance": "Примењивост", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Уклони", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1896,7 +1909,12 @@ "Start a new conversation": "", "Start of the channel": "Почетак канала", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2009,6 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Ово ће обрисати {{NAME}} и сав садржај унутар.", "This will delete all models including custom models": "Ово ће обрисати све моделе укључујући прилагођене моделе", "This will delete all models including custom models and cannot be undone.": "Ово ће обрисати све моделе укључујући прилагођене моделе и не може се опозвати.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Ово ће обрисати базу знања и ускладити све датотеке. Да ли желите наставити?", "Thorough explanation": "Детаљно објашњење", "Thought": "", @@ -2095,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Реши мистерије", "Unpin": "Откачи", + "Unpin from Sidebar": "", "Unravel secrets": "Разоткриј тајне", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index d75b41b928..9915d73f25 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}s Chattar", "{{webUIName}} Backend Required": "{{webUIName}} Backend krävs", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) krävs för bildgenerering", + "1 hour before": "", "1 Source": "1 källa", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "En ny version (v{{LATEST_VERSION}}) är nu tillgänglig.", @@ -202,6 +207,7 @@ "Ask a question": "Ställ en fråga", "Assistant": "Assistent", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "Bifoga kunskap", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Kringgå webbläsare", "Cache Base Model List": "", "Calendar": "Kalender", + "Calendar deleted": "", "Calendars": "", "Call": "Samtal", "Call feature is not supported when using Web STT engine": "Samtalsfunktionen är inte kompatibel med Web Tal-till-text motor", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Anslut till dina egna OpenAPI-kompatibla externa verktygsservrar.", "Connected ({{type}})": "", "Connection failed": "Anslutning misslyckades", + "Connection lost. Reconnecting...": "", "Connection successful": "Anslutning lyckades", "Connection Type": "Anslutningstyp", "Connections": "Anslutningar", @@ -525,6 +533,8 @@ "Delete All Chats": "Ta bort alla chattar", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Radera chatt", "Delete chat?": "Radera chatt?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Misslyckades med att kopiera länk", "Failed to create API Key.": "Misslyckades med att skapa API-nyckel.", + "Failed to delete calendar": "", "Failed to delete note": "Misslyckades med att ta bort anteckning", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Resonemangsinsats", "Reasoning Tags": "Resonemangs-taggar (tags)", "Recently Used": "", + "Reconnected": "", "Record": "Spela in", "Record voice": "Spela in röst", "Redirecting you to Open WebUI Community": "Omdirigerar dig till OpenWebUI Community", @@ -1648,6 +1660,7 @@ "Relevance": "Relevans", "Relevance Threshold": "Relevanströskel", "Remember Dismissal": "Kom ihåg avvisning", + "Reminder": "", "Remove": "Ta bort", "Remove {{MODELID}} from list.": "Ta bort {{MODELID}} från listan.", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Starta en ny konversation", "Start of the channel": "Början av kanalen", "Start Tag": "Starta en tagg", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Detta kommer att radera {{NAME}} och allt dess innehåll.", "This will delete all models including custom models": "Detta kommer att radera alla modeller inklusive anpassade modeller", "This will delete all models including custom models and cannot be undone.": "Detta kommer att radera alla modeller inklusive anpassade modeller och kan inte ångras.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Detta kommer att återställa kunskapsbasen och synkronisera alla filer. Vill du fortsätta?", "Thorough explanation": "Djupare förklaring", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "Avlastar {{FROM_NOW}}", "Unlock mysteries": "Lås upp mysterier", "Unpin": "Ta bort fästning", + "Unpin from Sidebar": "", "Unravel secrets": "Avslöja hemligheter", "Unshare Chat": "", "Unsupported file type.": "Filtypen stöds inte.", diff --git a/src/lib/i18n/locales/ta-IN/translation.json b/src/lib/i18n/locales/ta-IN/translation.json index 8e5af4f6e2..646aec1471 100644 --- a/src/lib/i18n/locales/ta-IN/translation.json +++ b/src/lib/i18n/locales/ta-IN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} இன் அரட்டைகள்", "{{webUIName}} Backend Required": "{{webUIName}} பின்தளம் தேவை", "*Prompt node ID(s) are required for image generation": "*பட உருவாக்கத்திற்கு உடனடி முனை ID(கள்) தேவை", + "1 hour before": "", "1 Source": "1 ஆதாரம்", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 நிமிடம் முன்", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "மக்கள் உறுப்பினர்களாக சேரும் ஒத்துழைப்பு சேனல்", "A discussion channel where access is controlled by groups and permissions": "குழுக்கள் மற்றும் அனுமதிகளால் அணுகல் கட்டுப்படுத்தப்படும் விவாத சேனல்", "A new version (v{{LATEST_VERSION}}) is now available.": "புதிய பதிப்பு (v{{LATEST_VERSION}}) இப்போது கிடைக்கிறது.", @@ -202,6 +207,7 @@ "Ask a question": "ஒரு கேள்வி கேளுங்கள்", "Assistant": "உதவியாளர்", "Async Embedding Processing": "ஒத்திசைவு உட்பொதித்தல் செயலாக்கம்", + "At time of event": "", "Attach File From Knowledge": "அறிவிலிருந்து கோப்பை இணைக்கவும்", "Attach Files": "கோப்புகளை இணைக்கவும்", "Attach Knowledge": "அறிவை இணைக்கவும்", @@ -276,6 +282,7 @@ "Bypass Web Loader": "பைபாஸ் இணைய ஏற்றி", "Cache Base Model List": "கேச் அடிப்படை மாதிரி பட்டியல்", "Calendar": "நாட்காட்டி", + "Calendar deleted": "", "Calendars": "", "Call": "அழைக்கவும்", "Call feature is not supported when using Web STT engine": "Web STT இன்ஜினைப் பயன்படுத்தும் போது அழைப்பு அம்சம் ஆதரிக்கப்படாது", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "உங்கள் சொந்த OpenAPI இணக்கமான வெளிப்புற கருவி சேவையகங்களுடன் இணைக்கவும்.", "Connected ({{type}})": "இணைக்கப்பட்டது ({{type}})", "Connection failed": "இணைப்பு தோல்வியடைந்தது", + "Connection lost. Reconnecting...": "", "Connection successful": "இணைப்பு வெற்றிகரமாக உள்ளது", "Connection Type": "இணைப்பு வகை", "Connections": "இணைப்புகள்", @@ -525,6 +533,8 @@ "Delete All Chats": "அனைத்து அரட்டைகளையும் நீக்கு", "Delete all contents inside this folder": "இந்தக் கோப்புறையில் உள்ள அனைத்து உள்ளடக்கங்களையும் நீக்கவும்", "Delete automation?": "தானியக்கத்தை நீக்கவா?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "அரட்டையை நீக்கு", "Delete chat?": "அரட்டையை நீக்கவா?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "{{URL}} டெர்மினல் சர்வருடன் இணைக்க முடியவில்லை", "Failed to copy link": "இணைப்பை நகலெடுக்க முடியவில்லை", "Failed to create API Key.": "API விசையை உருவாக்குவதில் தோல்வி.", + "Failed to delete calendar": "", "Failed to delete note": "குறிப்பை நீக்க முடியவில்லை", "Failed to download image": "படத்தைப் பதிவிறக்க முடியவில்லை", "Failed to extract content from the file: {{error}}": "கோப்பிலிருந்து உள்ளடக்கத்தைப் பிரித்தெடுக்க முடியவில்லை: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "பகுத்தறிவு முயற்சி", "Reasoning Tags": "பகுத்தறிவு குறிச்சொற்கள்", "Recently Used": "சமீபத்தில் பயன்படுத்தப்பட்டது", + "Reconnected": "", "Record": "பதிவு", "Record voice": "குரல் பதிவு", "Redirecting you to Open WebUI Community": "உங்களை Open WebUI சமூகத்திற்கு திருப்பி விடுகிறோம்", @@ -1648,6 +1660,7 @@ "Relevance": "சம்பந்தம்", "Relevance Threshold": "சம்பந்தமான வரம்பு", "Remember Dismissal": "பணிநீக்கம் என்பதை நினைவில் கொள்க", + "Reminder": "", "Remove": "அகற்று", "Remove {{MODELID}} from list.": "பட்டியலில் இருந்து {{MODELID}} ஐ அகற்று.", "Remove action": "செயலை அகற்று", @@ -1894,7 +1907,11 @@ "Start a new conversation": "புதிய உரையாடலைத் தொடங்கவும்", "Start of the channel": "சேனலின் ஆரம்பம்", "Start Tag": "தொடக்க குறிச்சொல்", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "கர்னலைத் தொடங்குகிறது...", + "Starting now": "", "State": "நிலை", "Status": "நிலை", "Status cleared successfully": "நிலை வெற்றிகரமாக அழிக்கப்பட்டது", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "இது {{NAME}} மற்றும் அதன் அனைத்து உள்ளடக்கங்களையும் நீக்கும்.", "This will delete all models including custom models": "இது தனிப்பயன் மாதிரிகள் உட்பட அனைத்து மாடல்களையும் நீக்கும்", "This will delete all models including custom models and cannot be undone.": "இது தனிப்பயன் மாதிரிகள் உட்பட அனைத்து மாடல்களையும் நீக்கிவிடும், மேலும் செயல்தவிர்க்க முடியாது.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "இது அறிவுத் தளத்தை மீட்டமைத்து அனைத்து கோப்புகளையும் ஒத்திசைக்கும். நீங்கள் தொடர விரும்புகிறீர்களா?", "Thorough explanation": "விரிவான விளக்கம்", "Thought": "சிந்தனை", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} இறக்குகிறது", "Unlock mysteries": "மர்மங்களைத் திறக்கவும்", "Unpin": "அன்பின்", + "Unpin from Sidebar": "", "Unravel secrets": "இரகசியங்களை அவிழ்த்து விடுங்கள்", "Unshare Chat": "அரட்டையைப் பகிர்வதை நீக்கு", "Unsupported file type.": "ஆதரிக்கப்படாத கோப்பு வகை.", diff --git a/src/lib/i18n/locales/th-TH/translation.json b/src/lib/i18n/locales/th-TH/translation.json index 733bd77d5e..17dd64ef45 100644 --- a/src/lib/i18n/locales/th-TH/translation.json +++ b/src/lib/i18n/locales/th-TH/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "การแชทของ {{user}}", "{{webUIName}} Backend Required": "ต้องใช้ Backend ของ {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*ต้องระบุ ID ของ prompt node สำหรับการสร้างภาพ", + "1 hour before": "", "1 Source": "1 แหล่งที่มา", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "เวอร์ชันใหม่ (v{{LATEST_VERSION}}) พร้อมให้ใช้งานแล้ว", @@ -201,6 +206,7 @@ "Ask a question": "ถามคำถาม", "Assistant": "ผู้ช่วย", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "แนบไฟล์จากฐานความรู้", "Attach Files": "", "Attach Knowledge": "แนบฐานความรู้", @@ -275,6 +281,7 @@ "Bypass Web Loader": "ข้ามตัวโหลดเว็บไซต์", "Cache Base Model List": "แคชรายการโมเดลพื้นฐาน", "Calendar": "ปฏิทิน", + "Calendar deleted": "", "Calendars": "", "Call": "โทร", "Call feature is not supported when using Web STT engine": "ไม่รองรับฟีเจอร์การโทรเมื่อใช้เอนจิน Web STT", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "เชื่อมต่อกับเซิร์ฟเวอร์เครื่องมือภายนอกของคุณที่รองรับ OpenAPI", "Connected ({{type}})": "", "Connection failed": "การเชื่อมต่อล้มเหลว", + "Connection lost. Reconnecting...": "", "Connection successful": "เชื่อมต่อสำเร็จ", "Connection Type": "ประเภทการเชื่อมต่อ", "Connections": "การเชื่อมต่อ", @@ -524,6 +532,8 @@ "Delete All Chats": "ลบการแชททั้งหมด", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "ลบแชท", "Delete chat?": "ลบแชท?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "คัดลอกลิงก์ไม่สำเร็จ", "Failed to create API Key.": "สร้าง API Key ล้มเหลว", + "Failed to delete calendar": "", "Failed to delete note": "ลบบันทึกไม่สำเร็จ", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "ไม่สามารถดึงเนื้อหาจากไฟล์ได้: {{error}}", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "ระดับการใช้เหตุผล", "Reasoning Tags": "ป้ายกำกับการให้เหตุผล", "Recently Used": "", + "Reconnected": "", "Record": "บันทึก", "Record voice": "บันทึกเสียง", "Redirecting you to Open WebUI Community": "กำลังเปลี่ยนเส้นทางคุณไปยังชุมชน Open WebUI", @@ -1647,6 +1659,7 @@ "Relevance": "ความเกี่ยวข้อง", "Relevance Threshold": "เกณฑ์ความเกี่ยวข้อง", "Remember Dismissal": "จำการปิดข้อความ", + "Reminder": "", "Remove": "ลบ", "Remove {{MODELID}} from list.": "ลบ {{MODELID}} ออกจากรายการ", "Remove action": "", @@ -1892,7 +1905,10 @@ "Start a new conversation": "เริ่มการสนทนาใหม่", "Start of the channel": "จุดเริ่มต้นของช่อง", "Start Tag": "แท็กเริ่มต้น", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "การดำเนินการนี้จะลบ {{NAME}} และเนื้อหาทั้งหมด", "This will delete all models including custom models": "การดำเนินการนี้จะลบโมเดลทั้งหมด รวมถึงโมเดลแบบกำหนดเอง", "This will delete all models including custom models and cannot be undone.": "การดำเนินการนี้จะลบโมเดลทั้งหมดรวมถึงโมเดลที่กำหนดเอง และไม่สามารถยกเลิกได้", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "การดำเนินการนี้จะรีเซ็ตฐานความรู้และซิงค์ไฟล์ทั้งหมด คุณต้องการดำเนินการต่อหรือไม่?", "Thorough explanation": "คำอธิบายอย่างละเอียด", "Thought": "", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "ยกเลิกการใช้งาน {{FROM_NOW}}", "Unlock mysteries": "ไขปริศนา", "Unpin": "ยกเลิกการปักหมุด", + "Unpin from Sidebar": "", "Unravel secrets": "เปิดเผยความลับ", "Unshare Chat": "", "Unsupported file type.": "ไม่รองรับไฟล์ประเภทนี้", diff --git a/src/lib/i18n/locales/tk-TM/translation.json b/src/lib/i18n/locales/tk-TM/translation.json index 7fb04a3227..6783a0222a 100644 --- a/src/lib/i18n/locales/tk-TM/translation.json +++ b/src/lib/i18n/locales/tk-TM/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'iň Çatlary", "{{webUIName}} Backend Required": "{{webUIName}} Backend Zerur", "*Prompt node ID(s) are required for image generation": "", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "", @@ -202,6 +207,7 @@ "Ask a question": "", "Assistant": "", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "", "Call feature is not supported when using Web STT engine": "", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "Baglanyşyklar", @@ -525,6 +533,8 @@ "Delete All Chats": "Ähli Çatlary Öçür", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "", "Delete chat?": "", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "", "Redirecting you to Open WebUI Community": "", @@ -1648,6 +1660,7 @@ "Relevance": "", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Aýyr", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Kanal başy", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "", "Thorough explanation": "", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index 8d9e63ce85..5b31954239 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}}'ın Sohbetleri", "{{webUIName}} Backend Required": "{{webUIName}} Arka-uç Gerekli", "*Prompt node ID(s) are required for image generation": "*Görüntü oluşturma için düğüm ID'leri gereklidir", + "1 hour before": "", "1 Source": "1 Kaynak", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1 dk önce", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "İnsanların üye olarak katıldığı bir iş birliği kanalı", "A discussion channel where access is controlled by groups and permissions": "Erişimin gruplar ve izinlerle kontrol edildiği bir tartışma kanalı", "A new version (v{{LATEST_VERSION}}) is now available.": "Yeni bir sürüm (v{{LATEST_VERSION}}) artık mevcut.", @@ -202,6 +207,7 @@ "Ask a question": "Bir soru sorun", "Assistant": "Asistan", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "Bilgi Tabanından Dosya Ekle", "Attach Files": "", "Attach Knowledge": "Bilgi Tabanı Ekle", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Web Yükleyicisini Atla", "Cache Base Model List": "Temel Model Listesini Önbelleğe Al", "Calendar": "Takvim", + "Calendar deleted": "", "Calendars": "", "Call": "Arama", "Call feature is not supported when using Web STT engine": "Web STT motoru kullanılırken arama özelliği desteklenmiyor", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Kendi OpenAPI uyumlu harici araç sunucularınıza bağlanın.", "Connected ({{type}})": "", "Connection failed": "Bağlantı başarısız", + "Connection lost. Reconnecting...": "", "Connection successful": "Bağlantı başarılı", "Connection Type": "Bağlantı Tipi", "Connections": "Bağlantılar", @@ -525,6 +533,8 @@ "Delete All Chats": "Tüm Sohbetleri Sil", "Delete all contents inside this folder": "Bu klasördeki tüm içerikleri sil", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Sohbeti Sil", "Delete chat?": "Sohbeti sil?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "{{URL}} terminal sunucusuna bağlanılamadı", "Failed to copy link": "Bağlantı kopyalanamadı", "Failed to create API Key.": "API Anahtarı oluşturulamadı.", + "Failed to delete calendar": "", "Failed to delete note": "Not silinemedi", "Failed to download image": "Görsel indirilemedi", "Failed to extract content from the file: {{error}}": "Dosyadan içerik çıkarılamadı: {{error}}", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Kaydet", "Record voice": "Ses kaydı yap", "Redirecting you to Open WebUI Community": "OpenWebUI Topluluğuna yönlendiriliyorsunuz", @@ -1648,6 +1660,7 @@ "Relevance": "İlgili", "Relevance Threshold": "İlgi Eşiği", "Remember Dismissal": "", + "Reminder": "", "Remove": "Kaldır", "Remove {{MODELID}} from list.": "{{MODELID}} modelini listeden kaldır.", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "Yeni bir konuşma başlat", "Start of the channel": "Kanalın başlangıcı", "Start Tag": "Başlangıç Etiketi", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "Kernel başlatılıyor...", + "Starting now": "", "State": "", "Status": "Durum", "Status cleared successfully": "Durum başarıyla temizlendi", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "{{NAME}} ve tüm içeriği silinecek.", "This will delete all models including custom models": "Bu, özel modeller dahil olmak üzere tüm modelleri silecek", "This will delete all models including custom models and cannot be undone.": "Bu, özel modeller dahil olmak üzere tüm modelleri silecek ve geri alınamaz.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Bu, bilgi tabanını sıfırlayacak ve tüm dosyaları senkronize edecek. Devam etmek istiyor musunuz?", "Thorough explanation": "Kapsamlı açıklama", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} sonra modeli bellekten boşaltır", "Unlock mysteries": "", "Unpin": "Sabitlemeyi Kaldır", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/ug-CN/translation.json b/src/lib/i18n/locales/ug-CN/translation.json index ea8c92b507..ba0727be45 100644 --- a/src/lib/i18n/locales/ug-CN/translation.json +++ b/src/lib/i18n/locales/ug-CN/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} نىڭ سۆھبەتلىرى", "{{webUIName}} Backend Required": "{{webUIName}} ئارقا سۇپا زۆرۈر", "*Prompt node ID(s) are required for image generation": "رەسىم ھاسىل قىلىش ئۈچۈن تۈرتكە نۇسخا ئۇچۇر ID(لىرى) زۆرۈر", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "يېڭى نەشرى (v{{LATEST_VERSION}}) مەۋجۇت.", @@ -202,6 +207,7 @@ "Ask a question": "سؤئال سوراڭ", "Assistant": "ياردەمچى", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "تور يۈكلىگۈچتىن ئۆتۈپ كېتىش", "Cache Base Model List": "", "Calendar": "كالىندار", + "Calendar deleted": "", "Calendars": "", "Call": "چاقىرىش", "Call feature is not supported when using Web STT engine": "تور STT ماتورى ئىشلىتىلگەندە چاقىرىش ئىقتىدارى قوللىنىلمايدۇ", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "OpenAPI ماس كېلىدىغان سىرتقى قورال مۇلازىمېتىرلىرىغا باغلىنىڭ.", "Connected ({{type}})": "", "Connection failed": "ئۇلىنىش مەغلۇپ بولدى", + "Connection lost. Reconnecting...": "", "Connection successful": "ئۇلىنىش مۇۋەپپەقىيەتلىك", "Connection Type": "ئۇلىنىش تىپى", "Connections": "ئۇلىنىشلەر", @@ -525,6 +533,8 @@ "Delete All Chats": "بارلىق سۆھبەتلەرنى ئۆچۈرۈش", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "سۆھبەت ئۆچۈرۈش", "Delete chat?": "سۆھبەت ئۆچۈرەمسىز؟", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "ئۇلانما كۆچۈرۈش مەغلۇپ بولدى", "Failed to create API Key.": "API ئاچقۇچى قۇرۇش مەغلۇپ بولدى.", + "Failed to delete calendar": "", "Failed to delete note": "خاتىرە ئۆچۈرۈش مەغلۇپ بولدى", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "چۈشەندۈرۈش كۈچى", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "خاتىرىلەش", "Record voice": "ئاۋاز خاتىرىلەش", "Redirecting you to Open WebUI Community": "Open WebUI جەمئىيىتىگە يوللاندى", @@ -1648,6 +1660,7 @@ "Relevance": "مۇناسىۋەتلىكلىك", "Relevance Threshold": "مۇناسىۋەتلىكلىك چەك قىممىتى", "Remember Dismissal": "", + "Reminder": "", "Remove": "چىقىرىۋېتىش", "Remove {{MODELID}} from list.": "تىزىمدىن {{MODELID}} چىقىرىۋېتىش.", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "قانالنىڭ باشلانغىنى", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "{{NAME}} ۋە بارلىق مەزمۇنى ئۆچۈرۈلىدۇ.", "This will delete all models including custom models": "بۇ بارلىق مودېللارنى ئۆچۈرۈدۇ (ئۆزلۈك مودېللارنىمۇ ئۆز ئىچىگە ئالىدۇ)", "This will delete all models including custom models and cannot be undone.": "بۇ بارلىق مودېللارنى ئۆچۈرۈدۇ (ئۆزلۈك مودېللارنىمۇ ئۆز ئىچىگە ئالىدۇ) ۋە ئەسلىگە كەلتۈرگىلى بولمايدۇ.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "بىلىم ئاساسى قايتا تەڭشىلىپ بارلىق ھۆججەتلەر ماس-قەدەملىنىدۇ. داۋاملاشامسىز؟", "Thorough explanation": "تەپسىلىي چۈشەندۈرۈش", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} چىقىرىلىدۇ", "Unlock mysteries": "سىرلارنى ئاچ", "Unpin": "مۇقىملانمىغان قىلىش", + "Unpin from Sidebar": "", "Unravel secrets": "سىرنى ئاچ", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/uk-UA/translation.json b/src/lib/i18n/locales/uk-UA/translation.json index 5dde246b1f..46de023a39 100644 --- a/src/lib/i18n/locales/uk-UA/translation.json +++ b/src/lib/i18n/locales/uk-UA/translation.json @@ -35,8 +35,13 @@ "{{user}}'s Chats": "Чати {{user}}а", "{{webUIName}} Backend Required": "Необхідно підключення бекенду {{webUIName}}", "*Prompt node ID(s) are required for image generation": "*Для генерації зображення потрібно вказати ідентифікатор(и) вузла(ів)", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Нова версія (v{{LATEST_VERSION}}) зараз доступна.", @@ -204,6 +209,7 @@ "Ask a question": "Задати питання", "Assistant": "Асистент", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -278,6 +284,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Календар", + "Calendar deleted": "", "Calendars": "", "Call": "Виклик", "Call feature is not supported when using Web STT engine": "Функція виклику не підтримується при використанні Web STT (розпізнавання мовлення) рушія", @@ -415,6 +422,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Підключіться до своїх власних зовнішніх серверів інструментів, сумісних з OpenAPI.", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "З'єднання", @@ -527,6 +535,8 @@ "Delete All Chats": "Видалити усі чати", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Видалити чат", "Delete chat?": "Видалити чат?", "Delete Event": "", @@ -888,6 +898,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Не вдалося створити API ключ.", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1627,6 +1638,7 @@ "Reasoning Effort": "Зусилля на міркування", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Записати голос", "Redirecting you to Open WebUI Community": "Перенаправляємо вас до спільноти OpenWebUI", @@ -1650,6 +1662,7 @@ "Relevance": "Актуальність", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Видалити", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1898,7 +1911,13 @@ "Start a new conversation": "", "Start of the channel": "Початок каналу", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_few": "", + "Starting in {{count}} minutes_many": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2011,6 +2030,7 @@ "This will delete {{NAME}} and all its contents.": "Це видалить {{NAME}} та усі його вмісти.", "This will delete all models including custom models": "Це видалить усі моделі, включаючи користувацькі моделі", "This will delete all models including custom models and cannot be undone.": "Це видалить усі моделі, включаючи користувацькі моделі, і не може бути скасовано.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Це скине базу знань і синхронізує усі файли. Ви бажаєте продовжити?", "Thorough explanation": "Детальне пояснення", "Thought": "", @@ -2097,6 +2117,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Розкрийте таємниці", "Unpin": "Відчепити", + "Unpin from Sidebar": "", "Unravel secrets": "Розплутуйте секрети", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/ur-PK/translation.json b/src/lib/i18n/locales/ur-PK/translation.json index bc6d4912e0..967dd471db 100644 --- a/src/lib/i18n/locales/ur-PK/translation.json +++ b/src/lib/i18n/locales/ur-PK/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{ صارف }} کی بات چیت", "{{webUIName}} Backend Required": "{{webUIName}} بیک اینڈ درکار ہے", "*Prompt node ID(s) are required for image generation": "تصویر کی تخلیق کے لیے *پرومپٹ نوڈ آئی ڈی(ز) کی ضرورت ہے", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "نیا ورژن (v{{LATEST_VERSION}}) اب دستیاب ہے", @@ -202,6 +207,7 @@ "Ask a question": "سوال پوچھیں", "Assistant": "اسسٹنٹ", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "", + "Calendar deleted": "", "Calendars": "", "Call": "کال کریں", "Call feature is not supported when using Web STT engine": "کال کی خصوصیت ویب STT انجن استعمال کرتے وقت معاونت یافتہ نہیں ہے", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "", "Connected ({{type}})": "", "Connection failed": "", + "Connection lost. Reconnecting...": "", "Connection successful": "", "Connection Type": "", "Connections": "کنکشنز", @@ -525,6 +533,8 @@ "Delete All Chats": "تمام چیٹس حذف کریں", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "چیٹ حذف کریں", "Delete chat?": "چیٹ حذف کریں؟", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "API کلید بنانے میں ناکام", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "صوت ریکارڈ کریں", "Redirecting you to Open WebUI Community": "آپ کو اوپن ویب یو آئی کمیونٹی کی طرف ری ڈائریکٹ کیا جا رہا ہے", @@ -1648,6 +1660,7 @@ "Relevance": "موزونیت", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "ہٹا دیں", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "چینل کی شروعات", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "یہ {{NAME}} اور اس کے تمام مواد کو حذف کر دے گا", "This will delete all models including custom models": "", "This will delete all models including custom models and cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "یہ علمی بنیاد کو دوبارہ ترتیب دے گا اور تمام فائلز کو متوازن کرے گا کیا آپ جاری رکھنا چاہتے ہیں؟", "Thorough explanation": "مکمل وضاحت", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "", "Unpin": "ان پن کریں", + "Unpin from Sidebar": "", "Unravel secrets": "", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json index b4193be7b8..fe4f5b1da1 100644 --- a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json +++ b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} нинг чатлари", "{{webUIName}} Backend Required": "{{webUIName}} Баcкенд талаб қилинади", "*Prompt node ID(s) are required for image generation": "*Расм яратиш учун тезкор тугун идентификаторлари талаб қилинади", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Энди янги версия (v{{LATEST_VERSION}}) мавжуд.", @@ -202,6 +207,7 @@ "Ask a question": "Савол беринг", "Assistant": "Ёрдамчи", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Веб юклагични четлаб ўтиш", "Cache Base Model List": "", "Calendar": "Календар", + "Calendar deleted": "", "Calendars": "", "Call": "Қўнғироқ қилинг", "Call feature is not supported when using Web STT engine": "Wеб СТТ механизмидан фойдаланилганда қўнғироқ функсияси қўллаб-қувватланмайди", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Ўзингизнинг OpenAIга мос келадиган ташқи асбоблар серверларига уланинг.", "Connected ({{type}})": "", "Connection failed": "Уланиш амалга ошмади", + "Connection lost. Reconnecting...": "", "Connection successful": "Уланиш муваффақиятли", "Connection Type": "Уланиш тури", "Connections": "Уланишлар", @@ -525,6 +533,8 @@ "Delete All Chats": "Барча суҳбатларни ўчириш", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Чатни ўчириш", "Delete chat?": "Чат ўчирилсинми?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Ҳаволани нусхалаб бўлмади", "Failed to create API Key.": "АПИ калитини яратиб бўлмади.", + "Failed to delete calendar": "", "Failed to delete note": "Қайдни ўчириб бўлмади", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Мулоҳаза юритиш ҳаракатлари", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Ёзиб олиш", "Record voice": "Овозни ёзиб олинг", "Redirecting you to Open WebUI Community": "Сизни Опен WебУИ ҳамжамиятига йўналтирмоқда", @@ -1648,6 +1660,7 @@ "Relevance": "Мувофиқлик", "Relevance Threshold": "Мувофиқлик чегараси", "Remember Dismissal": "", + "Reminder": "", "Remove": "Ўчириш", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Канал боши", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Бу <стронг>{{NAME}} ва <стронг>барча мазмунини ўчириб ташлайди.", "This will delete all models including custom models": "Бу барча моделларни, шу жумладан махсус моделларни ўчириб ташлайди", "This will delete all models including custom models and cannot be undone.": "Бу барча моделларни, жумладан, махсус моделларни ҳам ўчириб ташлайди ва уларни ортга қайтариб бўлмайди.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Бу билимлар базасини қайта тиклайди ва барча файлларни синхронлаштиради. Давом этишни хоҳлайсизми?", "Thorough explanation": "Тўлиқ тушунтириш", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} юклайди", "Unlock mysteries": "Сирларни очинг", "Unpin": "Ечиш", + "Unpin from Sidebar": "", "Unravel secrets": "Сирларни очинг", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/uz-Latn-Uz/translation.json b/src/lib/i18n/locales/uz-Latn-Uz/translation.json index b7c12ae135..2ffada0eab 100644 --- a/src/lib/i18n/locales/uz-Latn-Uz/translation.json +++ b/src/lib/i18n/locales/uz-Latn-Uz/translation.json @@ -33,8 +33,13 @@ "{{user}}'s Chats": "{{user}} ning chatlari", "{{webUIName}} Backend Required": "{{webUIName}} Backend talab qilinadi", "*Prompt node ID(s) are required for image generation": "*Rasm yaratish uchun tezkor tugun identifikatorlari talab qilinadi", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Endi yangi versiya (v{{LATEST_VERSION}}) mavjud.", @@ -202,6 +207,7 @@ "Ask a question": "Savol bering", "Assistant": "Yordamchi", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -276,6 +282,7 @@ "Bypass Web Loader": "Veb yuklagichni chetlab o'tish", "Cache Base Model List": "", "Calendar": "Kalendar", + "Calendar deleted": "", "Calendars": "", "Call": "Qo'ng'iroq qiling", "Call feature is not supported when using Web STT engine": "Web STT mexanizmidan foydalanilganda qo'ng'iroq funksiyasi qo'llab-quvvatlanmaydi", @@ -413,6 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "O'zingizning OpenAPI-ga mos keladigan tashqi asboblar serverlariga ulaning.", "Connected ({{type}})": "", "Connection failed": "Ulanish amalga oshmadi", + "Connection lost. Reconnecting...": "", "Connection successful": "Ulanish muvaffaqiyatli", "Connection Type": "Ulanish turi", "Connections": "Ulanishlar", @@ -525,6 +533,8 @@ "Delete All Chats": "Barcha suhbatlarni o'chirish", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Chatni oʻchirish", "Delete chat?": "Chat oʻchirilsinmi?", "Delete Event": "", @@ -886,6 +896,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "Havolani nusxalab bo‘lmadi", "Failed to create API Key.": "API kalitini yaratib bo‘lmadi.", + "Failed to delete calendar": "", "Failed to delete note": "Qaydni o‘chirib bo‘lmadi", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1625,6 +1636,7 @@ "Reasoning Effort": "Mulohaza yuritish harakatlari", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "Yozib olish", "Record voice": "Ovozni yozib oling", "Redirecting you to Open WebUI Community": "Sizni Open WebUI hamjamiyatiga yoʻnaltirmoqda", @@ -1648,6 +1660,7 @@ "Relevance": "Muvofiqlik", "Relevance Threshold": "Muvofiqlik chegarasi", "Remember Dismissal": "", + "Reminder": "", "Remove": "O'chirish", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1894,7 +1907,11 @@ "Start a new conversation": "", "Start of the channel": "Kanal boshlanishi", "Start Tag": "", + "Starting in {{count}} minutes_one": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2007,6 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Bu {{NAME}} va barcha mazmunini o‘chirib tashlaydi.", "This will delete all models including custom models": "Bu barcha modellarni, shu jumladan maxsus modellarni o'chirib tashlaydi", "This will delete all models including custom models and cannot be undone.": "Bu barcha modellarni, jumladan, maxsus modellarni ham o‘chirib tashlaydi va ularni ortga qaytarib bo‘lmaydi.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Bu bilimlar bazasini qayta tiklaydi va barcha fayllarni sinxronlashtiradi. Davom etishni xohlaysizmi?", "Thorough explanation": "To'liq tushuntirish", "Thought": "", @@ -2093,6 +2111,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} yuklaydi", "Unlock mysteries": "Sirlarni oching", "Unpin": "Yechish", + "Unpin from Sidebar": "", "Unravel secrets": "Sirlarni oching", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index 9296b8b57c..6810eb909a 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "Các cuộc trò chuyện của {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Yêu cầu Backend", "*Prompt node ID(s) are required for image generation": "*ID nút Prompt là bắt buộc để tạo ảnh", + "1 hour before": "", "1 Source": "", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "", "A discussion channel where access is controlled by groups and permissions": "", "A new version (v{{LATEST_VERSION}}) is now available.": "Một phiên bản mới (v{{LATEST_VERSION}}) đã có sẵn.", @@ -201,6 +206,7 @@ "Ask a question": "Đặt câu hỏi", "Assistant": "Trợ lý", "Async Embedding Processing": "", + "At time of event": "", "Attach File From Knowledge": "", "Attach Files": "", "Attach Knowledge": "", @@ -275,6 +281,7 @@ "Bypass Web Loader": "", "Cache Base Model List": "", "Calendar": "Lịch", + "Calendar deleted": "", "Calendars": "", "Call": "Gọi", "Call feature is not supported when using Web STT engine": "Tính năng gọi điện không được hỗ trợ khi sử dụng công cụ Web STT", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Kết nối với các máy chủ công cụ bên ngoài tương thích OpenAPI của riêng bạn.", "Connected ({{type}})": "", "Connection failed": "Kết nối thất bại", + "Connection lost. Reconnecting...": "", "Connection successful": "Kết nối thành công", "Connection Type": "", "Connections": "Kết nối", @@ -524,6 +532,8 @@ "Delete All Chats": "Xóa mọi cuộc Chat", "Delete all contents inside this folder": "", "Delete automation?": "", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "Xóa chat", "Delete chat?": "Xóa chat?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "", "Failed to copy link": "", "Failed to create API Key.": "Lỗi khởi tạo API Key", + "Failed to delete calendar": "", "Failed to delete note": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "Nỗ lực Suy luận", "Reasoning Tags": "", "Recently Used": "", + "Reconnected": "", "Record": "", "Record voice": "Ghi âm", "Redirecting you to Open WebUI Community": "Đang chuyển hướng bạn đến Cộng đồng OpenWebUI", @@ -1647,6 +1659,7 @@ "Relevance": "Mức độ liên quan", "Relevance Threshold": "", "Remember Dismissal": "", + "Reminder": "", "Remove": "Xóa", "Remove {{MODELID}} from list.": "", "Remove action": "", @@ -1892,7 +1905,10 @@ "Start a new conversation": "", "Start of the channel": "Đầu kênh", "Start Tag": "", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "", + "Starting now": "", "State": "", "Status": "", "Status cleared successfully": "", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "Hành động này sẽ xóa {{NAME}}tất cả nội dung của nó.", "This will delete all models including custom models": "Hành động này sẽ xóa tất cả các mô hình bao gồm cả các mô hình tùy chỉnh", "This will delete all models including custom models and cannot be undone.": "Hành động này sẽ xóa tất cả các mô hình bao gồm cả các mô hình tùy chỉnh và không thể hoàn tác.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Hành động này sẽ đặt lại cơ sở kiến thức và đồng bộ hóa tất cả các tệp. Bạn có muốn tiếp tục không?", "Thorough explanation": "Giải thích kỹ lưỡng", "Thought": "", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "", "Unlock mysteries": "Mở khóa những bí ẩn", "Unpin": "Bỏ ghim", + "Unpin from Sidebar": "", "Unravel secrets": "Làm sáng tỏ những bí mật", "Unshare Chat": "", "Unsupported file type.": "", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index c8e04258c2..ce09ad948c 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} 的对话记录", "{{webUIName}} Backend Required": "{{webUIName}} 需要后端服务", "*Prompt node ID(s) are required for image generation": "*图片生成需要提示词节点 ID", + "1 hour before": "", "1 Source": "1 个引用来源", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "刚刚", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "成员可加入的协作频道", "A discussion channel where access is controlled by groups and permissions": "由用户组控制的讨论频道", "A new version (v{{LATEST_VERSION}}) is now available.": "新版本(v{{LATEST_VERSION}})现已发布", @@ -201,6 +206,7 @@ "Ask a question": "提问", "Assistant": "助手", "Async Embedding Processing": "异步嵌入处理", + "At time of event": "", "Attach File From Knowledge": "引用知识库中的文件", "Attach Files": "添加文件", "Attach Knowledge": "引用知识库", @@ -275,6 +281,7 @@ "Bypass Web Loader": "绕过网页加载器", "Cache Base Model List": "缓存基础模型列表", "Calendar": "日历", + "Calendar deleted": "", "Calendars": "", "Call": "语音通话", "Call feature is not supported when using Web STT engine": "使用 Web 语音转文字引擎时不支持语音通话功能", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "连接到符合 OpenAPI 规范的外部工具服务器", "Connected ({{type}})": "已连接({{type}})", "Connection failed": "连接失败", + "Connection lost. Reconnecting...": "", "Connection successful": "连接成功", "Connection Type": "连接类型", "Connections": "外部连接", @@ -524,6 +532,8 @@ "Delete All Chats": "删除所有对话记录", "Delete all contents inside this folder": "删除此分组内的所有内容", "Delete automation?": "要删除此自动化吗?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "删除对话记录", "Delete chat?": "要删除此对话记录吗?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "无法连接到终端服务器:{{URL}}", "Failed to copy link": "复制链接失败", "Failed to create API Key.": "创建接口密钥失败", + "Failed to delete calendar": "", "Failed to delete note": "删除笔记失败", "Failed to download image": "图片下载失败", "Failed to extract content from the file: {{error}}": "文件内容提取失败:{{error}}", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "推理努力 (Reasoning Effort)", "Reasoning Tags": "推理过程标签", "Recently Used": "最近使用", + "Reconnected": "", "Record": "录制", "Record voice": "录音", "Redirecting you to Open WebUI Community": "正在将您重定向到 Open WebUI 社区", @@ -1647,6 +1659,7 @@ "Relevance": "相关性", "Relevance Threshold": "相关性阈值", "Remember Dismissal": "记住关闭状态", + "Reminder": "", "Remove": "移除", "Remove {{MODELID}} from list.": "从列表中移除 {{MODELID}}", "Remove action": "删除当前操作", @@ -1892,7 +1905,10 @@ "Start a new conversation": "开始新对话", "Start of the channel": "频道起点", "Start Tag": "起始标签", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "正在启动内核...", + "Starting now": "", "State": "状态", "Status": "状态", "Status cleared successfully": "状态已清除", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "这将删除{{NAME}}及其所有内容。", "This will delete all models including custom models": "这将删除所有模型,包括自定义模型", "This will delete all models including custom models and cannot be undone.": "这将删除所有模型,包括自定义模型,且无法撤销。", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "这将重置知识库并同步所有文件。确认继续?", "Thorough explanation": "解释详尽", "Thought": "思考过程", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} 后卸载", "Unlock mysteries": "解码未知", "Unpin": "取消置顶", + "Unpin from Sidebar": "", "Unravel secrets": "冲破奥秘", "Unshare Chat": "取消分享对话", "Unsupported file type.": "不支持的文件类型", diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index f98a2bdb76..50d352a96f 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}} 的對話", "{{webUIName}} Backend Required": "需要提供 {{webUIName}} 後端", "*Prompt node ID(s) are required for image generation": "* 產生圖片需要提示詞節點 ID", + "1 hour before": "", "1 Source": "1 個來源", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "剛剛", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "成員可加入的協作頻道", "A discussion channel where access is controlled by groups and permissions": "由權限組控制的討論頻道", "A new version (v{{LATEST_VERSION}}) is now available.": "新版本 (v{{LATEST_VERSION}}) 已釋出。", @@ -201,6 +206,7 @@ "Ask a question": "提出問題", "Assistant": "助理", "Async Embedding Processing": "非同步嵌入處理", + "At time of event": "", "Attach File From Knowledge": "從知識庫附加檔案", "Attach Files": "新增檔案", "Attach Knowledge": "附加知識庫", @@ -275,6 +281,7 @@ "Bypass Web Loader": "繞過網頁載入器", "Cache Base Model List": "快取基礎模型清單", "Calendar": "日曆", + "Calendar deleted": "", "Calendars": "", "Call": "通話", "Call feature is not supported when using Web STT engine": "使用網頁語音辨識 (Web STT) 引擎時不支援通話功能", @@ -412,6 +419,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "連線至您自有或其他與 OpenAPI 相容的外部工具伺服器。", "Connected ({{type}})": "已連線({{type}})", "Connection failed": "連線失敗", + "Connection lost. Reconnecting...": "", "Connection successful": "連線成功", "Connection Type": "連線類型", "Connections": "連線", @@ -524,6 +532,8 @@ "Delete All Chats": "刪除所有對話紀錄", "Delete all contents inside this folder": "刪除此資料夾內的所有內容", "Delete automation?": "要刪除此自動化嗎?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "刪除對話紀錄", "Delete chat?": "刪除對話紀錄?", "Delete Event": "", @@ -885,6 +895,7 @@ "Failed to connect to {{URL}} terminal server": "無法連線至終端伺服器:{{URL}}", "Failed to copy link": "複製連結失敗", "Failed to create API Key.": "建立 API 金鑰失敗。", + "Failed to delete calendar": "", "Failed to delete note": "刪除筆記失敗", "Failed to download image": "圖片下載失敗", "Failed to extract content from the file: {{error}}": "檔案內容擷取失敗:{{error}}", @@ -1624,6 +1635,7 @@ "Reasoning Effort": "推理程度", "Reasoning Tags": "推理標籤", "Recently Used": "最近使用", + "Reconnected": "", "Record": "錄製", "Record voice": "錄音", "Redirecting you to Open WebUI Community": "正在將您重導向至 Open WebUI 社群", @@ -1647,6 +1659,7 @@ "Relevance": "相關性", "Relevance Threshold": "相關性閾值", "Remember Dismissal": "記住關閉狀態", + "Reminder": "", "Remove": "移除", "Remove {{MODELID}} from list.": "從清單中移除 {{MODELID}}", "Remove action": "刪除目前操作", @@ -1892,7 +1905,10 @@ "Start a new conversation": "開始新對話", "Start of the channel": "頻道起點", "Start Tag": "起始標籤", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "正在啟動核心…", + "Starting now": "", "State": "狀態", "Status": "狀態", "Status cleared successfully": "狀態已清除", @@ -2005,6 +2021,7 @@ "This will delete {{NAME}} and all its contents.": "這將會刪除 {{NAME}}其所有內容。", "This will delete all models including custom models": "這將刪除所有模型,包括自訂模型", "This will delete all models including custom models and cannot be undone.": "這將刪除所有模型,包括自訂模型,且無法復原。", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "這將重設知識庫並同步所有檔案。您確定要繼續嗎?", "Thorough explanation": "詳細解釋", "Thought": "思考過程", @@ -2091,6 +2108,7 @@ "Unloads {{FROM_NOW}}": "於 {{FROM_NOW}} 後解除載入", "Unlock mysteries": "解鎖謎題", "Unpin": "取消釘選", + "Unpin from Sidebar": "", "Unravel secrets": "揭開秘密", "Unshare Chat": "取消分享對話", "Unsupported file type.": "不支援的檔案類型", From 0542df147a90565cfec224af46e589200ddd9553 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 15:52:33 +0900 Subject: [PATCH 346/404] refac --- src/lib/components/chat/ChatControls.svelte | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lib/components/chat/ChatControls.svelte b/src/lib/components/chat/ChatControls.svelte index 3cbcc7ed87..8ac5f06617 100644 --- a/src/lib/components/chat/ChatControls.svelte +++ b/src/lib/components/chat/ChatControls.svelte @@ -72,7 +72,10 @@ $: showControlsTab = $user?.role === 'admin' || ($user?.permissions?.chat?.controls ?? true); $: showFilesTab = - !!$selectedTerminalId || + ($selectedTerminalId && + (($terminalServers ?? []).some((t) => t.id && t.id === $selectedTerminalId) || + $user?.role === 'admin' || + ($user?.permissions?.features?.direct_tool_servers ?? true))) || (codeInterpreterEnabled && $config?.code?.interpreter_engine !== 'jupyter'); $: showOverviewTab = hasMessages; @@ -96,13 +99,22 @@ } // Auto-open Files tab when a terminal is selected (suppress panel open when full-screen) - $: if ($selectedTerminalId) { + $: if ($selectedTerminalId && showFilesTab) { activeTab = 'files'; if (largeScreen) { showControls.set(true); } } + // Clear selected direct terminal if user lost permission + $: if ( + $selectedTerminalId && + !($terminalServers ?? []).some((t) => t.id && t.id === $selectedTerminalId) && + !($user?.role === 'admin' || ($user?.permissions?.features?.direct_tool_servers ?? true)) + ) { + selectedTerminalId.set(null); + } + // Attach a terminal file to the chat input const handleTerminalAttach = async (blob: Blob, name: string, contentType: string) => { const tempItemId = uuidv4(); From 65f55847a144a1c61775c0097116932f716ee7fa Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 16:04:48 +0900 Subject: [PATCH 347/404] refac --- backend/open_webui/retrieval/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index b9bfcc12c8..fb5a46c2b0 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -172,6 +172,11 @@ def _is_text_content_type(content_type: str) -> bool: def get_content_from_url(request, url: str) -> str: + from open_webui.retrieval.web.utils import validate_url + + # Validate URL before making any request (blocks private IPs, non-HTTP, filter list) + validate_url(url) + # Streamed GET to check Content-Type without downloading the body. try: response = requests.get(url, stream=True, timeout=30) From 116eb7fc5501e43d217489776d11792e4d2fe2ef Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 16:05:26 +0900 Subject: [PATCH 348/404] refac --- backend/open_webui/utils/oauth.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 9a35e30c3f..47302e7535 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -1922,10 +1922,10 @@ class OAuthManager: users_to_logout.append(user) if not users_to_logout and sid: - log.info(f'Back-channel logout: no user found by sub, sid-based lookup not yet supported (sid={sid})') + log.debug(f'Back-channel logout: no user found by sub, sid-based lookup not yet supported (sid={sid})') if not users_to_logout: - log.info(f'Back-channel logout: no matching user for provider={matched_provider}, sub={sub}, sid={sid}') + log.debug(f'Back-channel logout: no matching user for provider={matched_provider}, sub={sub}, sid={sid}') return JSONResponse(status_code=200, content={}) # 9. Revoke tokens and delete sessions From 085d3cb1c9e5046e0fa165e153bf821f53b795b9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 16:16:48 +0900 Subject: [PATCH 349/404] refac --- src/lib/utils/index.ts | 61 +++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index dc23620a12..38e7636e25 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -677,7 +677,9 @@ export const calculateSHA256 = async (file) => { export const getImportOrigin = (_chats) => { // Check what external service chat imports are from - if ('mapping' in _chats[0]) { + // ChatGPT exports may include folder/project metadata entries without 'mapping', + // so we check if ANY item has a 'mapping' key instead of only the first one. + if (_chats.some((chat) => 'mapping' in chat)) { return 'openai'; } return 'webui'; @@ -706,6 +708,21 @@ export const getUserPosition = async (raw = false) => { } }; +const extractOpenAIMessageContent = (message): string => { + // Extract text content from a ChatGPT message, handling various content formats + // (string parts, object parts like DALL-E images, text field fallback) + try { + const parts = message?.['content']?.['parts']; + if (Array.isArray(parts)) { + const textParts = parts.filter((p) => typeof p === 'string'); + if (textParts.length > 0) return textParts.join('\n'); + } + return message?.['content']?.['text'] || ''; + } catch { + return ''; + } +}; + const convertOpenAIMessages = (convo) => { // Parse OpenAI chat messages and create chat dictionary for creating new chats const mapping = convo['mapping']; @@ -726,15 +743,18 @@ const convertOpenAIMessages = (convo) => { // Skip chat messages with no content continue; } else { + const role = message['message']?.['author']?.['role']; + // Skip system and tool messages — they don't map to user/assistant + if (role === 'system' || role === 'tool') { + continue; + } + const new_chat = { id: message_id, parentId: lastId, childrenIds: message['children'] || [], - role: message['message']?.['author']?.['role'] !== 'user' ? 'assistant' : 'user', - content: - message['message']?.['content']?.['parts']?.[0] || - message['message']?.['content']?.['text'] || - '', + role: role !== 'user' ? 'assistant' : 'user', + content: extractOpenAIMessageContent(message['message']), model: 'gpt-3.5-turbo', done: true, context: null @@ -747,6 +767,12 @@ const convertOpenAIMessages = (convo) => { } } + // Fix up the last message's childrenIds to be empty (it's the leaf node in our + // linear chain regardless of what the original tree structure had) + if (messages.length > 0) { + messages[messages.length - 1].childrenIds = []; + } + const history: Record = {}; messages.forEach((obj) => (history[obj.id] = obj)); @@ -773,18 +799,6 @@ const validateChat = (chat) => { return false; } - // Last message's children should be an empty array - const lastMessage = messages[messages.length - 1]; - if (lastMessage.childrenIds.length !== 0) { - return false; - } - - // First message's parent should be null - const firstMessage = messages[0]; - if (firstMessage.parentId !== null) { - return false; - } - // Every message's content should be a string for (const message of messages) { if (typeof message.content !== 'string') { @@ -799,7 +813,15 @@ export const convertOpenAIChats = (_chats) => { // Create a list of dictionaries with each conversation from import const chats = []; let failed = 0; + let skipped = 0; for (const convo of _chats) { + // Skip folder/project metadata entries that lack a 'mapping' key + if (!('mapping' in convo)) { + skipped++; + console.log('Skipping non-conversation entry (folder/project):', convo['title'] ?? convo['id']); + continue; + } + const chat = convertOpenAIMessages(convo); if (validateChat(chat)) { @@ -815,6 +837,9 @@ export const convertOpenAIChats = (_chats) => { } } console.log(failed, 'Conversations could not be imported'); + if (skipped > 0) { + console.log(skipped, 'Non-conversation entries (folders/projects) were skipped'); + } return chats; }; From 3b821e1f3a54d56fcde9ee88ca977c8a0ff3caea Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 16:32:17 +0900 Subject: [PATCH 350/404] refac --- src/lib/utils/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index 38e7636e25..1820e70481 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -818,7 +818,10 @@ export const convertOpenAIChats = (_chats) => { // Skip folder/project metadata entries that lack a 'mapping' key if (!('mapping' in convo)) { skipped++; - console.log('Skipping non-conversation entry (folder/project):', convo['title'] ?? convo['id']); + console.log( + 'Skipping non-conversation entry (folder/project):', + convo['title'] ?? convo['id'] + ); continue; } From 493f238431e5b06e488cb5f9607bab7465301300 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 21 Apr 2026 16:46:02 +0900 Subject: [PATCH 351/404] refac --- CHANGELOG.md | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5f34d74f..4e0b35b16b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,26 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- 🖥️ **Native desktop app availability.** Open WebUI is now available as a cross-platform desktop app with local model support, multi-server switching, and offline-ready usage after first launch. [#8262](https://github.com/open-webui/open-webui/issues/8262), [Desktop](https://github.com/open-webui/desktop) -- 🤖 **Scheduled chat automations.** Users can now create, schedule, run, and manage recurring automations from both the dedicated automations page and built-in chat tools, with execution logs, direct run controls, and permission-aware access control for user and group policies. [#23303](https://github.com/open-webui/open-webui/pull/23303), [Commit](https://github.com/open-webui/open-webui/commit/5a2ff8b2e5b6f55a20f7ed491f818490eb535ea7), [Commit](https://github.com/open-webui/open-webui/commit/d30a0531d4add045c21a2368d6321a9b1906865f), [Commit](https://github.com/open-webui/open-webui/commit/bae5ff938ac88a3a647cc31ca8db1101015ae18b), [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) +- 🖥️ **Official Open WebUI Desktop App.** Open WebUI is now available as a native desktop app for Mac, Windows, and Linux. No Docker, no terminal, no setup. Runs Open WebUI locally without any server setup, or connects to your existing remote Open WebUI instances. Switch between multiple servers instantly from the sidebar. Comes with a system-wide floating chat bar (Shift+Cmd+I on macOS, Shift+Ctrl+I on Windows/Linux), system-wide push-to-talk, offline support after first launch, automatic updates, and zero telemetry. [#8262](https://github.com/open-webui/open-webui/issues/8262), [Desktop](https://github.com/open-webui/desktop) +- 🤖 **Scheduled chat automations.** You can now schedule the AI to run tasks automatically on a recurring basis: daily digests, periodic reports, anything you'd otherwise need to remember to ask for. Create and manage automations from the Automations page or directly in chat, with full run history and manual trigger controls. [#23303](https://github.com/open-webui/open-webui/pull/23303), [Commit](https://github.com/open-webui/open-webui/commit/5a2ff8b2e5b6f55a20f7ed491f818490eb535ea7), [Commit](https://github.com/open-webui/open-webui/commit/d30a0531d4add045c21a2368d6321a9b1906865f), [Commit](https://github.com/open-webui/open-webui/commit/bae5ff938ac88a3a647cc31ca8db1101015ae18b), [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) - 🧰 **Automation tools in chat.** Built-in chat tools can now create, update, list, pause, and delete scheduled automations directly in conversation when automation access is enabled. [Commit](https://github.com/open-webui/open-webui/commit/588b81eedaacbfd7394b707ae1600d9fb729b809..674695918e5e3e1811314ce2a082c5bbb42d76b2) -- 🤖 **Automation model selection reliability.** Automations created from chat now consistently use the calling model, avoiding mismatches when tool calls run under different model contexts. [Commit](https://github.com/open-webui/open-webui/commit/e709d6812f7fba246c4b7907f9fa41f751717566), [Commit](https://github.com/open-webui/open-webui/commit/398718d5059ce2a5614e9e124f20ef48b843ce42), [#23812](https://github.com/open-webui/open-webui/pull/23812) - ⏱️ **Automation scheduling limits.** Administrators can now set "AUTOMATION_MAX_COUNT" and "AUTOMATION_MIN_INTERVAL" to limit how many automations each non-admin user can create and prevent overly frequent schedules that could overload the system. [Commit](https://github.com/open-webui/open-webui/commit/406251c2f358ffabce4d631c98c6f2c879feae5c) -- 🧭 **Global automations toggle.** Administrators can now disable automations system-wide with the "ENABLE_AUTOMATIONS" setting, which hides automation pages and tools and pauses background automation processing until it is re-enabled. [Commit](https://github.com/open-webui/open-webui/commit/42694c7c0cc8ba586c1dd364ecfaa0b4080b6cad) - 📋 **Task management tool.** AI models can now create, update, and track tasks within a chat conversation, breaking down complex requests into manageable steps with real-time status updates. [Commit](https://github.com/open-webui/open-webui/commit/bcb71bb5206ac01d97a39fde8ecf0e0541dde636) -- 🗓️ **Calendar workspace and event management.** Users can now manage personal and shared calendars from a dedicated Calendar page, create and edit events (including recurring events), and view scheduled automations directly alongside calendar activity. [#23880](https://github.com/open-webui/open-webui/pull/23880) -- 🔐 **Calendar permission controls.** Administrators can now control calendar access through feature permissions, so calendar pages, APIs, and built-in calendar tools are available only to users and groups with calendar access enabled. [Commit](https://github.com/open-webui/open-webui/commit/5afc258c5b13f456be528420513ade546c5e86f9), [Commit](https://github.com/open-webui/open-webui/commit/37eba1c5a66b3145c122a6b40e5c29707526d121) -- 🗑️ **Calendar deletion controls.** Calendar sidebar entries now include a delete action with confirmation, allowing users to remove custom calendars directly from the Calendar page. [Commit](https://github.com/open-webui/open-webui/commit/51627555bf356c8ec663f4d2f43f2f013eadbce4) +- 🗓️ **Calendar workspace and event management.** Open WebUI now has a full Calendar workspace. Create and manage events, set up recurring schedules, get reminders via in-app toasts or browser notifications, and see your scheduled automations alongside your calendar. [#23880](https://github.com/open-webui/open-webui/pull/23880) - 🔔 **Calendar reminders and alerts.** Calendar events now support reminder options from no alert up to one hour before start time, with upcoming alerts delivered through in-app toasts, browser notifications, and optional webhooks while avoiding duplicate sends. [Commit](https://github.com/open-webui/open-webui/commit/e5b5a174265d6710e986f6534ee7e3b2923233be) - ⚙️ **Scheduler reminder configuration.** Administrators can now configure calendar reminder processing with "SCHEDULER_POLL_INTERVAL" and "CALENDAR_ALERT_LOOKAHEAD_MINUTES", while existing "AUTOMATION_POLL_INTERVAL" setups continue to work as a legacy fallback. [Commit](https://github.com/open-webui/open-webui/commit/e5b5a174265d6710e986f6534ee7e3b2923233be) -- 🗓️ **Unified calendar header controls.** The Calendar page now uses a single top navigation bar for date navigation, view selection, and quick event creation, with improved mobile behavior and label truncation for tighter screens. [Commit](https://github.com/open-webui/open-webui/commit/4e31fa4427037c0ffd4ad704308203639bf05df8), [Commit](https://github.com/open-webui/open-webui/commit/3e3f138d9323987a41b1e3c17721a0047cf8e40f) -- 🧰 **Dedicated task checklist tools.** Built-in task tracking exposes separate tools for creating task lists and updating individual task statuses, giving multi-step chats clearer progress control. [Commit](https://github.com/open-webui/open-webui/commit/a35926261646f8897ba71da1572ed5dff802e3be) - ☁️ **Azure responses support.** Azure OpenAI connections now support the newer "/openai/v1" format, enabling chat, responses, and proxy calls to work correctly with that endpoint style. [#23484](https://github.com/open-webui/open-webui/pull/23484) - 🤖 **Ollama responses support.** The Ollama proxy now supports the Responses API, letting clients use "/v1/responses" directly with Ollama-hosted models through Open WebUI. [#23483](https://github.com/open-webui/open-webui/pull/23483) - 🧩 **Responses tool output rendering.** Built-in tool outputs in Responses API flows now render more consistently so downstream chat output is easier to interpret. [Commit](https://github.com/open-webui/open-webui/commit/e695d854f2d11fada84d5fbec8d3edea4e468e19), [#23482](https://github.com/open-webui/open-webui/pull/23482) - 🔎 **Responses citation visibility.** Responses API flows now emit citation sources more consistently, making linked references easier to preserve and display in chat output. [Commit](https://github.com/open-webui/open-webui/commit/e695d854f2d11fada84d5fbec8d3edea4e468e19), [#23774](https://github.com/open-webui/open-webui/issues/23774) - 📎 **Attach previously uploaded files.** The chat input menu now includes a Files tab for browsing and attaching previously uploaded files, eliminating the need to re-upload files you have already shared. [Commit](https://github.com/open-webui/open-webui/commit/edb8971c7dbd974322c3207c4655ff66479c3ee2) -- 🖥️ **Terminal session tracking.** Open Terminal now tracks the current working directory per chat session, so relative paths and navigation work correctly across multiple interactions. [Commit](https://github.com/open-webui/open-webui/commit/a06685a47b89fb19dd6124fbe391ff78b54f451d), [Commit](https://github.com/open-webui/open-webui/commit/6512e085c4e56897dd49e56aff5d616820a962f3) - 🧷 **Default model terminal selection.** Workspace model editors can now preselect an Open Terminal connection, so new chats automatically start with the model’s configured terminal ready to use. [Commit](https://github.com/open-webui/open-webui/commit/47d413ce7b2a006a8126f4a9055b13e5fcb33a1d), [#23605](https://github.com/open-webui/open-webui/issues/23605) - 🎙️ **Mistral TTS support.** Mistral can now be used as a text-to-speech provider, with admin settings for the API key, base URL, voices, and model selection. [Commit](https://github.com/open-webui/open-webui/commit/4cee67e2be0c80a0b501073ea49a80d13efd1c41) - 🎧 **STT preprocessing bypass option.** Administrators can now enable "AUDIO_STT_SKIP_PREPROCESSING" to send audio files directly to the speech-to-text backend, reducing memory and CPU consumption during large uploads for better transcription performance and stability on constrained deployments. [#23661](https://github.com/open-webui/open-webui/pull/23661) @@ -38,7 +31,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 📌 **Recently used emojis.** The emoji picker now shows your most recently used emojis at the top, making it faster to find emojis you use often. [Commit](https://github.com/open-webui/open-webui/commit/64da99a32218171d41b3af5acc14783de8dbdf49) - 👆 **Swipe to reply on mobile.** Swiping right on a message now triggers a reply, making it easier to respond on touch devices with a natural gesture. [Commit](https://github.com/open-webui/open-webui/commit/012ce95f27d57bea8911bd63bfb923443c5797ae) - 📱 **Screen-awake voice recording.** Voice recording now keeps the screen awake during active dictation and safely re-acquires wake lock after visibility changes, helping prevent long transcriptions from being cut off on mobile devices. [#23145](https://github.com/open-webui/open-webui/issues/23145) -- ✨ **Improved task list visibility.** The task list automatically hides once all tasks are complete and generation is finished, keeping the chat interface cleaner. [Commit](https://github.com/open-webui/open-webui/commit/0ad397c0482004173d4a8bf4722100acc43db454), [Commit](https://github.com/open-webui/open-webui/commit/4b35d70078a2d7a322566699a43594b3c10b2dda) - 🔔 **Unread chat indicators.** Sidebar chats now show unread status and are marked as read when opened, making it easier to spot conversations with new activity. [Commit](https://github.com/open-webui/open-webui/commit/0638b9f56ce1ba8a496d0e84da2e7fa178b01a3f) - 🔌 **WebSocket reconnect status feedback.** Open WebUI now warns when the real-time connection drops and confirms when it reconnects, while avoiding a reconnect message on the initial page load. [Commit](https://github.com/open-webui/open-webui/commit/1824e69a70e756cfcf543a9fbe4b0780d9b57292) - 📍 **Pinned notes in sidebar.** Notes can now be pinned to the sidebar for quick access, and you can also create a new note directly from the pinned notes section. [Commit](https://github.com/open-webui/open-webui/commit/ecd74f220c7dd671d5705189a3f4493a3868c8bf), [Commit](https://github.com/open-webui/open-webui/commit/f1be85d997439b49fc143d2bcd2dc710f44446c8) @@ -48,11 +40,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🎨 **Theme updates.** Other windows can now update the app theme directly, keeping the interface in sync when theme changes are triggered externally. [Commit](https://github.com/open-webui/open-webui/commit/9f1b279e88bd22dfff4d2531209536dea6a2f65e) - 🚀 **Async performance and responsiveness improvements.** The core backend database and request paths now run asynchronously across the application, massively improving responsiveness and performance under concurrent load and reducing request blocking during heavy activity. [Commit](https://github.com/open-webui/open-webui/commit/27169124f220e5cea21c88601c731c3749496ab0), [Commit](https://github.com/open-webui/open-webui/commit/8936721414a17832852a90f3ee592af5a8b7232d) - ⚡ **Drawer performance and memory optimization.** Drawer interactions now stay smoother over long sessions by removing stale keyboard listeners on teardown, which reduces memory growth and avoids accumulated event handling overhead. [#23724](https://github.com/open-webui/open-webui/pull/23724#issuecomment-4245840810) -- 🚀 **Chat history memory culling.** Long conversations now stay much more responsive by rendering a smaller message window and unloading off-screen messages with spacer-based virtualization, significantly reducing memory pressure and UI freezing on heavy chats and mobile devices. [#23067](https://github.com/open-webui/open-webui/issues/23067), [Commit](https://github.com/open-webui/open-webui/commit/026903399be73ac4b6c226647110e5662d043a50), [Commit](https://github.com/open-webui/open-webui/commit/9dccd29c94875e6f0ac373c5802cb183296e47ff) +- 🚀 **Chat history memory culling.** Long conversations now stay responsive no matter how many messages they contain. Off-screen messages are unloaded automatically and reloaded as you scroll, keeping memory usage low and the UI smooth on both desktop and mobile. [#23067](https://github.com/open-webui/open-webui/issues/23067), [Commit](https://github.com/open-webui/open-webui/commit/026903399be73ac4b6c226647110e5662d043a50), [Commit](https://github.com/open-webui/open-webui/commit/9dccd29c94875e6f0ac373c5802cb183296e47ff) - 🧵 **Async file and knowledge processing performance.** File processing, knowledge reindexing, and channel message helper paths now consistently await async operations, preventing skipped processing steps and improving reliability and performance of indexing and tool responses. [Commit](https://github.com/open-webui/open-webui/commit/de27a121511a31606f250ba4033490797216a0eb) - 🚀 **Persistent chat payload efficiency.** Persisted chats now use server-side history loading instead of repeatedly resending full message payloads, improving multimodal performance and reducing stale-history overwrite risk across devices. [#19064](https://github.com/open-webui/open-webui/issues/19064), [Commit](https://github.com/open-webui/open-webui/commit/18fe17127a7175579506e7456d3e5aba201371e6), [Commit](https://github.com/open-webui/open-webui/commit/cf4218e688def6f11d195aeda6665ae5b5376b67) - 🧵 **Non-blocking file storage operations.** Uploading, reading, transcribing, and deleting files now offloads storage I/O to background threads, keeping the application responsive during file-heavy workflows. [Commit](https://github.com/open-webui/open-webui/commit/4866bec0f238198a721c952fe18dd04ba643be33) -- 🏃 **Faster automation list loading.** The automations page now loads more smoothly by batching latest-run lookups and avoiding duplicate initial fetches. [Commit](https://github.com/open-webui/open-webui/commit/09f6d7ba57d2aaad83ad0d29d005feb7157776a1) - 🏎️ **Streaming response performance.** Streaming responses now process each output line in a single step instead of two separate yields, reducing async overhead and improving responsiveness during long-running generations. [#23266](https://github.com/open-webui/open-webui/pull/23266) - 🔎 **Faster mention parsing.** Chat text with HTML-like content, file paths, or tool output now parses mentions more efficiently, which helps keep typing and rendering responsive in messages that contain many '<' characters. [#23551](https://github.com/open-webui/open-webui/pull/23551) - 🧪 **Code block rendering performance.** Code blocks now reuse a shared HTML unescape helper, reducing extra browser work when displaying encoded output in chat. [#23553](https://github.com/open-webui/open-webui/pull/23553) @@ -99,6 +90,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🧩 **Richer Anthropic tool results.** Anthropic-compatible tool calls now preserve more tool result content types, including images and structured search or document outputs, so models can use fuller tool context instead of receiving only plain text fragments. [#23188](https://github.com/open-webui/open-webui/issues/23188), [Commit](https://github.com/open-webui/open-webui/commit/40f5b3d135190dc9a2d8e94dbb1b2cbcbd829132) - 🖼️ **ComfyUI request reliability.** ComfyUI image generation and editing now use shared async connections with consistent SSL handling, making image uploads and workflow runs more reliable under concurrent load. [Commit](https://github.com/open-webui/open-webui/commit/5944eda0ff25a284f7157252683bccede741cbe7) - 🎛️ **Reranking batch size control.** Administrators can now set "RAG_RERANKING_BATCH_SIZE" in Documents settings to control reranking workload size, helping balance retrieval speed and resource usage for their deployment. [Commit](https://github.com/open-webui/open-webui/commit/4d2f18981051205016bd24d39521e25a33581225) +- 🔗 **Shared chat access controls.** You can now control who has access to a shared chat by granting access to specific users or groups, instead of sharing with anyone who has the link. - 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security. - 🌐 **Translation updates.** Translations for Irish, Catalan, German, Simplified Chinese, Hindi, and Portuguese (Brazil) were enhanced and expanded. @@ -111,8 +103,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🗣️ **Pipeline error detail visibility.** Pipeline inlet and outlet failures now preserve and surface provider error details more reliably in chat error messages, making troubleshooting failed requests much clearer. [Commit](https://github.com/open-webui/open-webui/commit/d5e69f182cd7a6371ab25248f6432b277f83ef23) - 📨 **Shared chat event routing.** Message update and send events now target the chat owner’s event channel, so shared chats receive the correct real-time updates instead of routing events to the acting user. [Commit](https://github.com/open-webui/open-webui/commit/47329b5032ba29716a7e7e973b07c6d9894968e0) - 🔐 **Consistent outbound SSL handling.** External requests for tools, functions, terminals, webhooks, retrieval loaders, audio provider discovery, and OpenAI-compatible embedding calls now consistently apply the configured SSL client setting, improving reliability for deployments that require custom certificate or verification behavior. [Commit](https://github.com/open-webui/open-webui/commit/fd25152076ea7c310e42c9bacc5cd2b544eeae48), [Commit](https://github.com/open-webui/open-webui/commit/56c5bc1d3487020ab886d3332aacc1644c1d6123) -- 🧭 **Scheduled Tasks calendar reliability.** Scheduled Tasks is now handled as a virtual automation calendar that appears only when automation access is available, and calendar selection now filters by stable ID instead of name so event forms behave consistently. [Commit](https://github.com/open-webui/open-webui/commit/1d501cfa3f96b3a9a5f4f7ce996947671fd09f29), [Commit](https://github.com/open-webui/open-webui/commit/24dd5b461eb44d306c823389e0f664c45db042e8) -- 🛡️ **Protected calendar deletion rules.** System and default calendars can no longer be deleted, preventing accidental removal of built-in calendar functionality. [Commit](https://github.com/open-webui/open-webui/commit/51627555bf356c8ec663f4d2f43f2f013eadbce4) - 🖼️ **Image SSL setting support.** Image generation now respects the configured SSL session setting, preventing avoidable connection failures in strict certificate environments. [Commit](https://github.com/open-webui/open-webui/commit/128cf41fcedf2638fc8a6acd850d8b0409be1c4e), [#23777](https://github.com/open-webui/open-webui/issues/23777) - 🗂️ **Folder ownership assignment hardening.** Folder create and update inputs now reject unexpected extra fields, preventing clients from overriding protected values like ownership through mass-assignment payloads. [#23648](https://github.com/open-webui/open-webui/pull/23648) - 🔐 **Knowledge file deletion ownership checks.** Collaborators with knowledge base write access can no longer permanently delete files they do not own, preventing unintended file removal across other linked chats and knowledge bases. [Commit](https://github.com/open-webui/open-webui/commit/914ccf07ef158afe5588b97ed42778c93c439938), [#23636](https://github.com/open-webui/open-webui/pull/23636#issuecomment-4232439454) From 9f61a6f13c5c7668aed894ef12b2711352e1e9c3 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Tue, 21 Apr 2026 19:37:22 +0900 Subject: [PATCH 352/404] fix --- pyproject.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 27e6faeddf..b6d07a61f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,8 @@ dependencies = [ "python-mimeparse==2.0.0", "sqlalchemy==2.0.48", + "aiosqlite==0.21.0", + "asyncpg==0.30.0", "alembic==1.18.4", "peewee==3.19.0", "peewee-migrate==1.14.3", From f162d4de9077824d613425552f127cf4eb4a38b5 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Tue, 21 Apr 2026 19:39:44 +0900 Subject: [PATCH 353/404] doc --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e0b35b16b..8049dcca1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.1] - 2026-04-21 + +### Fixed + +- 🐛 **Missing `aiosqlite` dependency.** Fixed a startup crash (`ModuleNotFoundError: No module named 'aiosqlite'`) when installing Open WebUI via `pip` or `uv` by adding the missing `aiosqlite` package to `pyproject.toml`. The dependency was listed in `requirements.txt` but not in the published package metadata, so it was not installed automatically. [#23916](https://github.com/open-webui/open-webui/issues/23916) +- 🐛 **Missing `asyncpg` dependency.** Added the missing `asyncpg` package to `pyproject.toml` to prevent the same startup crash for PostgreSQL users. Like `aiosqlite`, it was present in `requirements.txt` but absent from the published package dependencies. + ## [0.9.0] - 2026-04-20 ### Added diff --git a/package-lock.json b/package-lock.json index 8efa79c1b4..e3175ba8a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.9.0", + "version": "0.9.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.9.0", + "version": "0.9.1", "dependencies": { "@azure/msal-browser": "^4.5.0", "@codemirror/lang-javascript": "^6.2.2", diff --git a/package.json b/package.json index bc1a1c5da3..ab246848c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.9.0", + "version": "0.9.1", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", From d56d74b3877192af37961ea6c78cbcf0ec70f343 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 23 Apr 2026 19:39:06 +0900 Subject: [PATCH 354/404] refac --- src/lib/components/chat/Messages.svelte | 117 +----------------- .../components/chat/Messages/Message.svelte | 13 +- 2 files changed, 13 insertions(+), 117 deletions(-) diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index 151f89fb2a..51a75f1242 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -60,102 +60,7 @@ export let messagesCount: number | null = 8; let messagesLoading = false; - // Off-screen message unloading. Heights are measured on scroll so spacers - // always match real sizes — no scroll jumps, no feedback loops needed. - const OVERSCAN = 3; - const DEFAULT_HEIGHT = 150; - let visibleStart = 0; - let visibleEnd = 0; - let messageHeights = new Map(); - let topSpacerHeight = 0; - let bottomSpacerHeight = 0; - let pendingCull = null; - - // Helper: get height for a message (cached or default) - const heightOf = (id) => messageHeights.get(id) ?? DEFAULT_HEIGHT; - - /** Measure all currently rendered message elements and cache their heights */ - const measureMessageHeights = () => { - const elements = document - .getElementById('messages-container') - ?.querySelectorAll('[role="listitem"]'); - if (!elements) return; - - messageHeights = new Map([ - ...messageHeights, - ...Array.from(elements) - .map((el, i) => [messages[visibleStart + i]?.id, el.getBoundingClientRect().height]) - .filter(([id]) => id != null) - ]); - }; - - /** Compute visible range from current scroll position and apply */ - const updateVisibleRange = () => { - const container = document.getElementById('messages-container'); - if (!container || messages.length === 0) return; - - const st = container.scrollTop; - const ch = container.clientHeight; - - // Build prefix sums from measured heights - const prefixSums = messages.reduce( - (acc, m) => [...acc, acc[acc.length - 1] + heightOf(m.id)], - [0] - ); - - const firstVisible = Math.max(0, prefixSums.findIndex((h) => h > st) - 1); - const lastVisible = prefixSums.findIndex((h) => h > st + ch); - - // Only cull messages that have been measured (so spacer height is accurate) - // findIndex returns -1 when all are measured → no limit on culling - const firstUnmeasured = messages.findIndex((m) => !messageHeights.has(m.id)); - const cullLimit = firstUnmeasured === -1 ? messages.length : firstUnmeasured; - - visibleStart = Math.max(0, Math.min(firstVisible - OVERSCAN, cullLimit)); - visibleEnd = Math.min( - messages.length, - (lastVisible === -1 ? messages.length : lastVisible) + OVERSCAN - ); - topSpacerHeight = prefixSums[visibleStart] ?? 0; - bottomSpacerHeight = (prefixSums[messages.length] ?? 0) - (prefixSums[visibleEnd] ?? 0); - }; - - /** Scroll handler: measure every frame, cull via rAF (same throttle as pendingRebuild) */ - const handleContainerScroll = () => { - measureMessageHeights(); - - // Don't cull during progressive loading - if (messagesLoading) return; - - if (!pendingCull) { - pendingCull = requestAnimationFrame(() => { - pendingCull = null; - updateVisibleRange(); - }); - } - }; - - let scrollListenerAttached = false; - - const attachScrollListener = () => { - if (scrollListenerAttached) return; - const container = document.getElementById('messages-container'); - if (!container) return; - - container.addEventListener('scroll', handleContainerScroll, { passive: true }); - scrollListenerAttached = true; - }; - - onMount(() => { - attachScrollListener(); - }); - onDestroy(() => { - const container = document.getElementById('messages-container'); - if (container && scrollListenerAttached) { - container.removeEventListener('scroll', handleContainerScroll); - } - cancelAnimationFrame(pendingCull); cancelAnimationFrame(pendingRebuild); }); @@ -169,12 +74,6 @@ buildMessages(); - // Show all messages during progressive loading (no culling) - visibleStart = 0; - visibleEnd = messages.length; - topSpacerHeight = 0; - bottomSpacerHeight = 0; - await tick(); messagesLoading = false; @@ -201,7 +100,6 @@ } messages = _messages.reverse(); - visibleEnd = messages.length; }; // Throttle message list rebuilds to once per animation frame during streaming. @@ -220,8 +118,6 @@ cancelAnimationFrame(pendingRebuild); pendingRebuild = null; buildMessages(); - // No explicit culling needed — scrollToBottom will fire a scroll event, - // which triggers handleContainerScroll → rAF → updateVisibleRange } else if (_messages) { // Content update (streaming) — throttle to once per frame if (!pendingRebuild) { @@ -570,13 +466,7 @@ {/if}
    - - {#if topSpacerHeight > 0} -
diff --git a/src/lib/components/chat/Messages/Message.svelte b/src/lib/components/chat/Messages/Message.svelte index d9ca32492a..b161aa8556 100644 --- a/src/lib/components/chat/Messages/Message.svelte +++ b/src/lib/components/chat/Messages/Message.svelte @@ -49,7 +49,7 @@ role="listitem" class="flex flex-col justify-between px-5 mb-3 w-full {($settings?.widescreenMode ?? null) ? 'max-w-full' - : 'max-w-5xl'} mx-auto rounded-lg group" + : 'max-w-5xl'} mx-auto rounded-lg group message-listitem" > {#if history.messages[messageId]} {#if history.messages[messageId].role === 'user'} @@ -128,3 +128,14 @@ {/if} {/if}
+ + + From 83f3a9c5434770eabef48759733b60b18f1d98c5 Mon Sep 17 00:00:00 2001 From: Algorithm5838 <108630393+Algorithm5838@users.noreply.github.com> Date: Thu, 23 Apr 2026 22:26:11 +0300 Subject: [PATCH 355/404] fix: remove reactive label from onDestroy in Markdown --- src/lib/components/chat/Messages/Markdown.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/chat/Messages/Markdown.svelte b/src/lib/components/chat/Messages/Markdown.svelte index d0b54b6528..3cbef944e4 100644 --- a/src/lib/components/chat/Messages/Markdown.svelte +++ b/src/lib/components/chat/Messages/Markdown.svelte @@ -82,7 +82,7 @@ $: updateHandler(content); // Throttle parsing to once per animation frame while streaming - $: onDestroy(() => { + onDestroy(() => { cancelAnimationFrame(pendingUpdate); }); From a4eb10269e37e33263cd5324be33a492506d5040 Mon Sep 17 00:00:00 2001 From: Kylapaallikko Date: Fri, 24 Apr 2026 08:33:06 +0300 Subject: [PATCH 356/404] Update fi-FI translation.json (#24010) Added missing translations. --- src/lib/i18n/locales/fi-FI/translation.json | 198 ++++++++++---------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index 16501646eb..c21491242b 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -33,13 +33,13 @@ "{{user}}'s Chats": "{{user}}:n keskustelut", "{{webUIName}} Backend Required": "{{webUIName}}-backend vaaditaan", "*Prompt node ID(s) are required for image generation": "Kuvan luomiseen vaaditaan kehote-solmun ID(t)", - "1 hour before": "", + "1 hour before": "1 tunti ennen", "1 Source": "1 lähde", - "10 minutes before": "", - "15 minutes before": "", + "10 minutes before": "10 minuuttia ennen", + "15 minutes before": "15 minuuttia ennen", "1m_time_ago": "", - "30 minutes before": "", - "5 minutes before": "", + "30 minutes before": "30 minuuttia ennen", + "5 minutes before": "5 minuuttia ennen", "A collaboration channel where people join as members": "Yhteistyökanava, johon ihmiset liittyvät jäseninä", "A discussion channel where access is controlled by groups and permissions": "Keskustelukanava, johon pääsyä rajoitetaan ryhmillä ja käyttöoikeuksilla", "A new version (v{{LATEST_VERSION}}) is now available.": "Uusi versio (v{{LATEST_VERSION}}) on nyt saatavilla.", @@ -52,7 +52,7 @@ "Access Control": "Käyttöoikeuksien hallinta", "Access Grants": "Käyttöoikeudet", "Access List": "Pääsylista", - "Access updated": "", + "Access updated": "Käyttöoikeus päivitetty", "Accessible to all users": "Käytettävissä kaikille käyttäjille", "Account": "Tili", "Account Activation Pending": "Tilin aktivointi odottaa", @@ -78,11 +78,11 @@ "Add content here": "Lisää sisältöä tähän", "Add Custom Parameter": "Lisää mukautettu parametri", "Add Custom Prompt": "Lisää mukautettu kehote", - "Add description": "", + "Add description": "Lisää kuvaus", "Add Details": "Lisää yksityiskohtia", "Add Files": "Lisää tiedostoja", "Add Image": "Lisää kuva", - "Add location": "", + "Add location": "Lisää sijainti", "Add Member": "Lisää jäsen", "Add Members": "Lisää jäseniä", "Add Memory": "Lisää muistiin", @@ -99,7 +99,7 @@ "Add webpage": "Lisää verkkosivu", "Add your Open Terminal URL and API key in Settings → Integrations.": "Lisää Open Terminal verkko-osoite ja API-avain Asetukset → Integraatiot", "Additional Config": "Lisäasetukset", - "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": "", + "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": "Lisäasetukset merkille. Tämä tulisi olla JSON-merkkijono, jossa on avain-arvo-pareja. Esimerkiksi '{\"key\": \"value\"}'. Tuetut avaimet sisältävät: 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": "Lisäpalautteen kommentit", "Additional Parameters": "Lisäparametrit", "Adds filenames, titles, sections, and snippets into the BM25 text to improve lexical recall.": "Lisää tiedostonimiä, otsikoita, osioita ja katkelmia BM25-tekstiin leksikaalisen muistamisen parantamiseksi.", @@ -118,7 +118,7 @@ "AI": "AI", "All": "Kaikki", "All chats have been unarchived.": "Kaikki keskustelut poistettu arkistosta.", - "All day": "", + "All day": "Koko päivä", "All models are now hidden": "Kaikki mallit ovat nyt piilotettu", "All models are now visible": "Kaikki mallit ovat nyt näkyvissä", "All models deleted successfully": "Kaikki mallit poistettu onnistuneesti", @@ -152,7 +152,7 @@ "Allowed File Extensions": "Hyväksytyt tiedostomuodot", "Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.": "Hyväksyty tiedostomuodot. Erittele tiedostomuodot pilkulla. Jätä tyhjäksi kaikille tiedostomuodoille.", "Already have an account?": "Onko sinulla jo tili?", - "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.": "", + "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.": "Vaihtoehto top_p:lle, ja sen tavoitteena on varmistaa laadun ja monimuotoisuuden tasapaino. Parametri p edustaa vähimmäistodennäköisyyttä, jonka on oltava tokenin huomioimiseksi suhteessa todennäköisimmän tokenin todennäköisyyteen. Esimerkiksi, kun p=0.05 ja todennäköisin tokenilla on todennäköisyys 0.9, logitit, joiden arvo on alle 0.045, suodatetaan pois.", "Always": "Aina", "Always Collapse Code Blocks": "Pienennä aina koodilohkot", "Always Expand Details": "Laajenna aina tiedot", @@ -191,7 +191,7 @@ "Are you sure you want to archive all chats? This action cannot be undone.": "Haluatko varmasti arkistoida kaikki keskustelut? Tätä toimintoa ei voi peruuttaa.", "Are you sure you want to clear all memories? This action cannot be undone.": "Haluatko varmasti tyhjentää kaikki muistot? Tätä toimintoa ei voi peruuttaa.", "Are you sure you want to delete \"{{NAME}}\"?": "Haluatko varmasti poistaa \"{{NAME}}\"?", - "Are you sure you want to delete **{{modelName}}**?": "", + "Are you sure you want to delete **{{modelName}}**?": "Haluatko varmasti poistaa **{{modelName}}**?", "Are you sure you want to delete all chats? This action cannot be undone.": "Haluatko varmasti poistaa kaikki keskustelut? Tätä toimintoa ei voi peruuttaa.", "Are you sure you want to delete this channel?": "Haluatko varmasti poistaa tämän kanavan?", "Are you sure you want to delete this connection? This action cannot be undone.": "Haluatko varmasti poistaa yhteyden? Tätä toimintoa ei voi peruuttaa.", @@ -207,9 +207,9 @@ "Ask a question": "Kysy kysymys", "Assistant": "Avustaja", "Async Embedding Processing": "Asynkroninen upotus prosessointi", - "At time of event": "", + "At time of event": "Tapahtumahetkellä", "Attach File From Knowledge": "Liitä tiedosto tietämyksestä", - "Attach Files": "", + "Attach Files": "Liitä tiedostoja", "Attach Knowledge": "Liitä tietoa", "Attach Notes": "Liitä muistiinpanoja", "Attach Webpage": "Liitä verkkosivu", @@ -232,13 +232,13 @@ "AUTOMATIC1111 Base URL": "AUTOMATIC1111 verkko-osoite", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 verkko-osoite vaaditaan.", "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "Lisää järjestelmätyökaluja automaattisesti natiivissa toimintokutsutilassa (esim. aikaleimat, muisti, keskusteluhistoria, muistiinpanot jne.)", - "Automation": "", - "Automation created": "", - "Automation Name": "", - "Automation title": "", - "Automation triggered": "", - "Automation updated": "", - "Automations": "", + "Automation": "Automaatio", + "Automation created": "Automaatio luotu", + "Automation Name": "Automaation nimi", + "Automation title": "Automaation otsikko", + "Automation triggered": "Automaatio laukaistu", + "Automation updated": "Automaatio päivitetty", + "Automations": "Automaatiot", "Available list": "Käytettävissä oleva luettelo", "Available models": "Käytettävissä olevat mallit", "Available Tools": "Käytettävissä olevat työkalut", @@ -269,7 +269,7 @@ "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Tiettyjen tokeneiden tehostaminen tai rankaiseminen rajoitetuista vastauksista. Poikkeaman arvot rajoitetaan välille -100 ja 100 (mukaan lukien). (Oletus: ei mitään)", "Brave": "", "Brave Search API Key": "Brave Search API -avain", - "Break down complex requests into trackable steps": "", + "Break down complex requests into trackable steps": "Pilko monimutkaiset pyynnöt seurattaviin vaiheisiin", "Browse and query knowledge bases": "Selaa ja hae tietokannoista", "Builtin Tools": "Sisäänrakennetut työkalut", "Bullet List": "Luettelo", @@ -282,8 +282,8 @@ "Bypass Web Loader": "Ohita verkkolataaja", "Cache Base Model List": "Malli luettelon välimuisti", "Calendar": "Kalenteri", - "Calendar deleted": "", - "Calendars": "", + "Calendar deleted": "Kalenteri poistettu", + "Calendars": "Kalenterit", "Call": "Puhelu", "Call feature is not supported when using Web STT engine": "Puhelutoimintoa ei tueta käytettäessä web-puheentunnistusmoottoria", "Camera": "Kamera", @@ -405,7 +405,7 @@ "Concurrent Requests": "Samanaikaiset pyynnöt", "Config": "Määritykset", "Config imported successfully": "Määritysten tuonti onnistui", - "Configuration": "", + "Configuration": "Määritys", "Configure": "Määritä", "Confirm": "Vahvista", "Confirm Password": "Vahvista salasana", @@ -420,7 +420,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Yhdistä omat ulkopuoliset OpenAPI yhteensopivat työkalu palvelimet.", "Connected ({{type}})": "Yhdistetty ({{type}})", "Connection failed": "Yhteys epäonnistui", - "Connection lost. Reconnecting...": "", + "Connection lost. Reconnecting...": "Yhteys katkaistu. Yhdistetään uudelleen...", "Connection successful": "Yhteys onnistui", "Connection Type": "Yhteystyyppi", "Connections": "Yhteydet", @@ -452,7 +452,7 @@ "Copy Last Response": "Kopioi viimeisin vastaus", "Copy link": "Kopioi linkki", "Copy Link": "Kopioi linkki", - "Copy Path": "", + "Copy Path": "Kopioi polku", "Copy Prompt": "Kopioi kehote", "Copy Share Link": "Kopioi jakolinkki", "Copy to clipboard": "Kopioi leikepöydälle", @@ -468,7 +468,7 @@ "Create a new note": "Luo uusi muistiinpano", "Create Account": "Luo tili", "Create Admin Account": "Luo ylläpitäjätili", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "Luo ja hallinnoi aikataulutettuja automaatioita", "Create Channel": "Luo kanava", "Create Folder": "Luo kansio", "Create Image": "Luo kuva", @@ -478,7 +478,7 @@ "Create new secret key": "Luo uusi salainen avain", "Create note": "Luo muistiinpano", "Create Note": "Luo muistiinpano", - "Create scheduled prompts that run automatically on a recurring basis.": "", + "Create scheduled prompts that run automatically on a recurring basis.": "Luo aikataulutettuja kehotteita, jotka suoritetaan automaattisesti toistuvasti.", "Create your first note by clicking on the plus button below.": "Luo ensimmäinen muistiinpanosi painamalla alla olevaa plus painiketta.", "Created at": "Luotu", "Created At": "Luotu", @@ -494,14 +494,14 @@ "Custom Gender": "Muu sukupuoli", "Custom Parameter Name": "Mukautetun parametrin nimi", "Custom Parameter Value": "Mukautetun parametrin arvo", - "Daily": "", + "Daily": "Päivittäin", "Daily Messages": "Päivittäiset viestit", "Danger Zone": "Vaara-alue", "Dark": "Tumma", "Data Controls": "Datan hallinta", "Database": "Tietokanta", "Datalab Marker API": "Datalab Marker API", - "Day": "", + "Day": "Päivä", "DD/MM/YYYY": "DD/MM/YYYY", "DDGS Backend": "DDGS-taustajärjestelmä", "December": "joulukuu", @@ -532,12 +532,12 @@ "Delete All": "Poista kaikki", "Delete All Chats": "Poista kaikki keskustelut", "Delete all contents inside this folder": "Poista kaikki sisällöt tästä kansiosta", - "Delete automation?": "", - "Delete calendar": "", - "Delete Calendar": "", + "Delete automation?": "Poista automaatio?", + "Delete calendar": "Poista kalenteri", + "Delete Calendar": "Poista kalenteri", "Delete Chat": "Poista keskustelu", "Delete chat?": "Haluatko varmasti poistaa tämän keskustelun?", - "Delete Event": "", + "Delete Event": "Poista tapahtuma?", "Delete File": "Poista tiedosto", "Delete folder?": "Haluatko varmasti poistaa tämän kansion?", "Delete function?": "Haluatko varmasti poistaa tämän toiminnon?", @@ -680,7 +680,7 @@ "Embedding Concurrent Requests": "Samanaikaiset upotuspyynnöt", "Embedding Model": "Upotusmalli", "Embedding Model Engine": "Upotusmallin moottori", - "Emojis": "", + "Emojis": "Emojit", "Empty message": "Tyhjä viesti", "Enable All": "Ota kaikki käyttöön", "Enable API Keys": "Ota API-avaimet käyttöön", @@ -772,7 +772,7 @@ "Enter Perplexity Search API URL": "Aseta Perplexity Search API verkko-osoite", "Enter Playwright Timeout": "Aseta Playwright aikakatkaisu", "Enter Playwright WebSocket URL": "Aseta Playwright WebSocket-aikakatkaisu", - "Enter prompt here.": "", + "Enter prompt here.": "Kirjoita kehote tähän.", "Enter proxy URL (e.g. https://user:password@host:port)": "Kirjoita välityspalvelimen verkko-osoite (esim. https://käyttäjä:salasana@host:portti)", "Enter reasoning effort": "Kirjoita päättelyn määrä", "Enter Score": "Kirjoita pistemäärä", @@ -797,7 +797,7 @@ "Enter system prompt here": "Kirjoita järjestelmäkehote tähän", "Enter Tavily API Key": "Kirjoita Tavily API -avain", "Enter Tavily Extract Depth": "Kirjoita Tavily pominta syvyys", - "Enter the prompt instructions for this automation...": "", + "Enter the prompt instructions for this automation...": "Kirjoita kehotteen ohjeet tälle automaatiolle...", "Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Kirjoita julkinen WebUI verkko-osoitteesi. Verkko-osoitetta käytetään osoitteiden luontiin ilmoituksissa.", "Enter the URL of the function to import": "Kirjoita tuotavan toiminnon verkko-osoite", "Enter the URL to import": "Kirjoita tuotavan verkko-osoite", @@ -831,23 +831,23 @@ "Enter your webhook URL": "Kirjoita webhook osoitteesi", "Entra ID": "Entra ID", "Environment Variables": "Ympäristömuuttujat", - "Ephemeral": "", + "Ephemeral": "Tilapäinen", "Error": "Virhe", "ERROR": "VIRHE", "Error accessing directory": "Virhe hakemistoa avattaessa", "Error accessing Google Drive: {{error}}": "Virhe yhdistäessä Google Drive: {{error}}", "Error accessing media devices.": "Virhe medialaitteita käytettäessä.", - "Error deleting model: {{error}}": "", + "Error deleting model: {{error}}": "Virhe mallia poistaessa: {{error}}", "Error starting recording.": "Virhe nauhoitusta aloittaessa.", "Error unloading model: {{error}}": "Virhe mallia ladattaessa: {{error}}", "Error uploading file: {{error}}": "Virhe ladattaessa tiedostoa: {{error}}", "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Virhe: Malli '{{modelId}}' on jo käytössä. Valitse toinen ID jatkaaksesi.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Virhe: Mallin ID ei voi olla tyhjä. Kirjoita ID jatkaaksesi.", "Evaluations": "Arvioinnit", - "Event created": "", - "Event deleted": "", - "Event title": "", - "Event updated": "", + "Event created": "Tapahtuma luotu", + "Event deleted": "Tapahtuma poistettu", + "Event title": "Tapahtuman otsikko", + "Event updated": "Tapahtuma päivitetty", "Exa API Key": "Exa API -avain", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Esimerkki: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Esimerkki: KAIKKI", @@ -859,7 +859,7 @@ "Execute code": "Suorita koodi", "Execute code for analysis": "Suorita koodi analysointia varten", "Executing **{{NAME}}**...": "Suoritetaan **{{NAME}}**...", - "Execution Logs": "", + "Execution Logs": "Suorituslokit", "Expand": "Laajenna", "Experimental": "Kokeellinen", "Explain": "Selitä", @@ -869,8 +869,8 @@ "Export": "Vie", "Export All Archived Chats": "Vie kaikki arkistoidut keskustelut", "Export All Chats (All Users)": "Vie kaikki keskustelut (kaikki käyttäjät)", - "Export as CSV": "", - "Export as JSON": "", + "Export as CSV": "Vie CSV-tiedostona", + "Export as JSON": "Vie JSON:na", "Export chat (.json)": "Vie keskustelu (.json)", "Export Chats": "Vie keskustelut", "Export Config": "Vie asetukset", @@ -896,7 +896,7 @@ "Failed to connect to {{URL}} terminal server": "Yhdistäminen {{URL}} päätepalvelimeen epäonnistui", "Failed to copy link": "Linkin kopiointi epäonnistui", "Failed to create API Key.": "API-avaimen luonti epäonnistui.", - "Failed to delete calendar": "", + "Failed to delete calendar": "Kalenterin poistaminen epäonnistui", "Failed to delete note": "Muistiinpanon poistaminen epäonnistui", "Failed to download image": "Kuvan lataaminen epäonnistui", "Failed to extract content from the file: {{error}}": "Tiedoston sisällön pomiminen epäonnistui: {{error}}", @@ -1068,7 +1068,7 @@ "History": "Historia", "Home": "Koti", "Host": "Palvelin", - "Hourly": "", + "Hourly": "Tunneittain", "Hourly Messages": "Tuntikohtaiset viestit", "How can I help you today?": "Miten voin auttaa sinua tänään?", "How would you rate this response?": "Kuinka arvioisit tätä vastausta?", @@ -1128,7 +1128,7 @@ "Insert Suggestion Prompt to Input": "Lisää kehote ehdotus syötteeseen", "Install from Github URL": "Asenna Github-URL:stä", "Instant Auto-Send After Voice Transcription": "Heti automaattinen lähetys äänitunnistuksen jälkeen", - "Instructions": "", + "Instructions": "Ohjeistukset", "Integration": "Integrointi", "Integrations": "Integraatiot", "Interface": "Käyttöliittymä", @@ -1188,7 +1188,7 @@ "Last 90 days": "Viimeiset 90 päivää", "Last Active": "Viimeksi aktiivinen", "Last Modified": "Viimeksi muokattu", - "Last ran": "", + "Last ran": "Viimeksi suoritettu", "Last reply": "Viimeksi vastattu", "LDAP": "LDAP", "LDAP server updated": "LDAP-palvelin päivitetty", @@ -1218,7 +1218,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Rajoita samanaikaisia hakukyselyitä. 0 = rajoittamaton (oletus). Aseta arvoon 1 peräkkäistä suoritusta varten (suositellaan API-rajapinnoille, joilla on tiukat nopeusrajoitukset, kuten Brave-ilmaistaso).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Rajoittaa samanaikaisten upotuspyyntöjen määrää. Arvolla 0 ei rajoituksia.", "List": "Lista", - "List calendars, search, create, update, and delete calendar events": "", + "List calendars, search, create, update, and delete calendar events": "Listaa kalenterit, hae, luo, päivitä ja poista kalenteritapahtumia", "Listening...": "Kuuntelee...", "Live": "Live", "Llama.cpp": "Llama.cpp", @@ -1229,7 +1229,7 @@ "local": "paikallinen", "Local": "Paikallinen", "Local Task Model": "Paikallinen työmalli", - "Location": "", + "Location": "Sijainti", "Location access not allowed": "Ei pääsyä sijaintitietoihin", "Lost": "Mennyt", "Low": "Matala", @@ -1297,15 +1297,15 @@ "Model": "Malli", "Model '{{modelName}}' has been successfully downloaded.": "Malli '{{modelName}}' ladattiin onnistuneesti.", "Model '{{modelTag}}' is already in queue for downloading.": "Malli '{{modelTag}}' on jo jonossa ladattavaksi.", - "Model {{modelId}} not found": "", - "Model {{modelName}} deleted successfully": "", + "Model {{modelId}} not found": "Malli {{modelId}} ei löytynyt", + "Model {{modelName}} deleted successfully": "Malli {{modelName}} poistettu onnistuneesti", "Model {{modelName}} is not vision capable": "Malli {{modelName}} ei kykene näkökykyyn", "Model {{name}} is now {{status}}": "Malli {{name}} on nyt {{status}}", "Model {{name}} is now hidden": "Malli {{name}} on nyt piilotettu", "Model {{name}} is now visible": "Malli {{name}} on nyt näkyvissä", "Model accepts file inputs": "Malli hyväksyy tiedostosyötteet", "Model accepts image inputs": "Malli hyväksyy kuvasyötteitä", - "Model can access Open Terminal for command execution and file management": "", + "Model can access Open Terminal for command execution and file management": "Malli voi käyttää Open Terminal-toimintoa komentojen suorittamiseen ja tiedostojen hallintaan.", "Model can execute code and perform calculations": "Malli voi suorittaa koodia ja laskelmia", "Model can generate images based on text prompts": "Malli voi luoda kuvia tekstikehotteiden perusteella", "Model can search the web for information": "Malli voi hakea tietoa verkosta", @@ -1339,8 +1339,8 @@ "Models Sharing": "Mallien jako", "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API -avain", - "Month": "", - "Monthly": "", + "Month": "Kuukausi", + "Monthly": "Kuukausittain", "More": "Lisää", "More Concise": "Lyhyemmin", "More options": "Lisää vaihtoehtoja", @@ -1351,14 +1351,14 @@ "Name": "Nimi", "Name and ID are required, please fill them out": "Nimi ja ID vaaditaan, täytä puuttuvat kentät", "Name your knowledge base": "Anna tietokannalle nimi", - "Name, prompt, and model are required": "", + "Name, prompt, and model are required": "Nimi, kehote ja malli ovat pakollisia", "Native": "Natiivi", - "Never": "", + "Never": "Ei koskaan", "New": "Uusi", - "New Automation": "", + "New Automation": "Uusi automaatio", "New Button": "Uusi painike", "New Chat": "Uusi keskustelu", - "New Event": "", + "New Event": "Uusi tapahtuma", "New File": "Uusi tiedosto", "New Folder": "Uusi kansio", "New Function": "Uusi toiminto", @@ -1375,11 +1375,11 @@ "New Webhook": "Uusi Webhook", "new-channel": "uusi-kanava", "Next message": "Seuraava viesti", - "Next run": "", + "Next run": "Seuraava suoritus", "No access grants. Private to you.": "Ei käyttöoikeuksia. Yksityinen sinulle.", "No activity data": "Ei aktiivisuustietoja", "No authentication": "Ei todennusta", - "No automations found": "", + "No automations found": "Automaatioita ei löytynyt", "No chats found": "Keskuteluja ei löytynyt", "No chats found for this user.": "Käyttäjän keskusteluja ei löytynyt.", "No chats found.": "Keskusteluja ei löytynyt", @@ -1390,7 +1390,7 @@ "No data": "Ei dataa", "No data found": "Dataa ei löytynyt", "No distance available": "Etäisyyttä ei saatavilla", - "No execution logs available yet": "", + "No execution logs available yet": "Suorituslokeja ei saatavilla", "No expiration can pose security risks.": "Vanhenemisen laittamatta jättäminen voi altistaa tietoturvariskeille.", "No feedback found": "Ei palautetta", "No file selected": "Tiedostoa ei ole valittu", @@ -1437,7 +1437,7 @@ "Not factually correct": "Ei faktuaalisesti oikein", "Not helpful": "Ei hyödyllinen", "Not Registered": "Ei kirjautunut", - "Not scheduled": "", + "Not scheduled": "Ei aikataulutettu", "Note": "Muistiinpano", "Note deleted successfully": "Muistiinpano poistettiin onnistuneesti", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Huomautus: Jos asetat vähimmäispistemäärän, haku palauttaa vain sellaiset asiakirjat, joiden pistemäärä on vähintään vähimmäismäärä.", @@ -1462,7 +1462,7 @@ "Ollama Cloud API Key": "Ollama Cloud API avain", "Ollama Version": "Ollama-versio", "On": "Päällä", - "Once": "", + "Once": "Kerran", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "Aktiivinen vain, kun \"Liitä suuri teksti tiedostona\" -asetus on käytössä.", "Only active when the chat input is in focus and an LLM is generating a response.": "Aktiivinen vain, kun tekstikenttä on kohdistettuna ja LLM luo vastausta.", @@ -1528,8 +1528,8 @@ "Password": "Salasana", "Passwords do not match.": "Salasanat eivät täsmää", "Paste Large Text as File": "Liitä suuri teksti tiedostona", - "Path copied": "", - "Paused": "", + "Path copied": "Polku kopioitu", + "Paused": "Keskeytetty", "PDF document (.pdf)": "PDF-asiakirja (.pdf)", "PDF Extract Images (OCR)": "Poimi kuvat PDF:stä (OCR)", "PDF Loader Mode": "PDF latausmoodi", @@ -1548,7 +1548,7 @@ "Persistent": "Pysyvä", "Personalization": "Personointi", "Pin": "Kiinnitä", - "Pin to Sidebar": "", + "Pin to Sidebar": "Kiinnitä sivupalkkiin", "Pinned": "Kiinnitetty", "Pinned Messages": "Kiinnitetyt viestit", "Pinned Models": "Kiinnitetyt mallit", @@ -1635,8 +1635,8 @@ "Reason": "Päättely", "Reasoning Effort": "Päättelyn määrä", "Reasoning Tags": "Päättely tagit", - "Recently Used": "", - "Reconnected": "", + "Recently Used": "Viimeeksi käytetty", + "Reconnected": "Yhdistetty", "Record": "Nauhoita", "Record voice": "Nauhoita ääntä", "Redirecting you to Open WebUI Community": "Ohjataan sinut OpenWebUI-yhteisöön", @@ -1660,7 +1660,7 @@ "Relevance": "Relevanssi", "Relevance Threshold": "Relevanssikynnys", "Remember Dismissal": "Muista sulkeminen", - "Reminder": "", + "Reminder": "Muistutus", "Remove": "Poista", "Remove {{MODELID}} from list.": "Poista {{MODELID}} listalta", "Remove action": "Poista toiminto", @@ -1673,7 +1673,7 @@ "Renamed to {{name}}": "Nimetty uudelleen {{name}}", "Render Markdown in Previews": "Renderöi Markdown esikatseluissa", "Reorder Models": "Uudelleenjärjestä malleja", - "Repeats": "", + "Repeats": "Toistot", "Reply": "Vastaa", "Reply in Thread": "Vastaa ketjussa", "Reply to thread...": "Vastaa ketjussa...", @@ -1707,8 +1707,8 @@ "RTL": "RTL", "Run": "Suorita", "Run All": "Suorita kaikki", - "Run now": "", - "Run Now": "", + "Run now": "Suorita nyt", + "Run Now": "Suorita nyt", "Running": "Käynnissä", "Running...": "Käynnissä...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Suorittaa upotustehtäviä samanaikaisesti käsittelyn nopeuttamiseksi. Poista käytöstä, jos kutsurajoituksesta tulee ongelma.", @@ -1720,15 +1720,15 @@ "Save Chat": "Tallenna keskustelu", "Saved": "Tallennettu", "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "Keskustelulokien tallentaminen suoraan selaimen tallennustilaan ei ole enää tuettu. Lataa ja poista keskustelulokit napsauttamalla alla olevaa painiketta. Älä huoli, voit helposti tuoda keskustelulokit takaisin backendiin", - "Schedule": "", - "Scheduled time must be in the future": "", + "Schedule": "Aikataulu", + "Scheduled time must be in the future": "Aikataulutetun ajan on oltava tulevaisuudessa", "Scroll On Branch Change": "Vieritä haaran vaihtoon", "Search": "Haku", "Search a model": "Hae mallia", "Search all emojis": "Hae emojeista", "Search and manage user memories": "Hae ja hallinnoi käyttäjien muistoja", "Search and view user chat history": "Hae ja tarkastele käyttäjän keskusteluhistoriaa", - "Search Automations": "", + "Search Automations": "Etsi automaatioita", "Search Base": "Hakupohja", "Search channels and channel messages": "Hae kanavia ja kanavaviestejä", "Search Chats": "Hae keskusteluja", @@ -1798,7 +1798,7 @@ "Select how to split message text for TTS requests": "Valitse, miten viestit jaetaan TTS-pyyntöjä varten", "Select Knowledge": "Valitse tietämys", "Select Method": "Valitse metodi", - "Select model": "", + "Select model": "Valitse malli", "Select only one model to call": "Valitse vain yksi malli kutsuttavaksi", "Select view": "Valitse näkymä", "Selected model: {{modelName}}": "Valittu malli: {{modelName}}", @@ -1907,12 +1907,12 @@ "Start a new conversation": "Aloita uusi keskustelu", "Start of the channel": "Kanavan alku", "Start Tag": "Aloitus tagi", - "Starting in {{count}} minutes_one": "", - "Starting in {{count}} minutes_other": "", - "Starting in 1 minute": "", + "Starting in {{count}} minutes_one": "Aloitetaan {{count}} minutes_one", + "Starting in {{count}} minutes_other": "Aloitetaan {{count}} minutes_other", + "Starting in 1 minute": "Aloitetaan minuutin kuluttua", "Starting kernel...": "Käynnistetään kerneliä...", - "Starting now": "", - "State": "", + "Starting now": "Aloitetaan nyt", + "State": "Tila", "Status": "Tila", "Status cleared successfully": "Tila poistettu onnistuneesti", "Status updated successfully": "Tila päivitetty onnistuneesti", @@ -1923,7 +1923,7 @@ "Stop Download": "Lopeta lataus", "Stop Generating": "Lopeta generointi", "Stop Sequence": "Lopetussekvenssi", - "Storage": "", + "Storage": "Käyttötila", "Stream Chat Response": "Striimaa keskusteluvastaus", "Stream Delta Chunk Size": "Striimin delta-lohkon koko", "Streamable HTTP": "Streamable HTTP", @@ -1964,10 +1964,10 @@ "Talk to Model": "Puhu mallille", "Tap to interrupt": "Napauta keskeyttääksesi", "Task List": "Tehtävälista", - "Task Management": "", + "Task Management": "Tehtävien hallinta", "Task Model": "Työmalli", "Tasks": "Tehtävät", - "tasks completed": "", + "tasks completed": "Tehtävät suoritettu", "Tavily API Key": "Tavily API -avain", "Tavily Extract Depth": "Tavily poiminta syvyys", "Tell us more:": "Kerro lisää:", @@ -1999,7 +1999,7 @@ "The score should be a value between 0.0 (0%) and 1.0 (100%).": "Pisteytyksen tulee olla arvo välillä 0,0 (0 %) ja 1,0 (100 %).", "The stream delta chunk size for the model. Increasing the chunk size will make the model respond with larger pieces of text at once.": "Mallin striimin delta-lohkon koko. Lohkon koon kasvattaminen saa mallin vastaamaan kerralla suuremmilla tekstipaloilla.", "The temperature of the model. Increasing the temperature will make the model answer more creatively.": "Mallin lämpötila. Lisäämällä lämpötilaa mallin vastaukset ovat luovempia.", - "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "", + "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "BM25-hybridihaun painoarvo. 0 semanttista, 1 leksikaalista. Oletusarvo 0,5", "The width in pixels to compress images to. Leave empty for no compression.": "Leveys pikseleinä, johon kuvat pakataan. Jätä tyhjäksi, jos et halua pakkausta.", "Theme": "Teema", "There was an error syncing your stats. Please try again.": "Tilastojen synkronoinnissa tapahtui virhe. Yritä uudelleen.", @@ -2024,7 +2024,7 @@ "This will delete {{NAME}} and all its contents.": "Tämä poistaa {{NAME}} ja kaikki sen sisällöt.", "This will delete all models including custom models": "Tämä poistaa kaikki mallit mukaan lukien mukautetut mallit", "This will delete all models including custom models and cannot be undone.": "Tämä poistaa kaikki mallit, mukaan lukien mukautetut mallit, eikä sitä voi peruuttaa.", - "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "Tämä poistaa pysyvästi kalenterin \"{{name}}\" ja kaikki sen tapahtumat. Tätä toimintoa ei voi peruuttaa.", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Tämä nollaa tietokannan ja synkronoi kaikki tiedostot. Haluatko jatkaa?", "Thorough explanation": "Perusteellinen selitys", "Thought": "Ajatus", @@ -2036,7 +2036,7 @@ "Tika": "Tika", "Tika Server URL required.": "Tika palvelimen verkko-osoite vaaditaan.", "Tiktoken": "Tiktoken", - "Time": "", + "Time": "Aika", "Time & Calculation": "Aika ja laskenta", "Timeout": "Aikakatkaisu", "Title": "Otsikko", @@ -2044,7 +2044,7 @@ "Title cannot be an empty string.": "Otsikko ei voi olla tyhjä merkkijono.", "Title Generation": "Otsikon luonti", "Title Generation Prompt": "Otsikon luontikehote", - "Title is required": "", + "Title is required": "Otsikko on pakollinen", "TLS": "TLS", "To access the available model names for downloading,": "Päästäksesi käsiksi ladattavissa oleviin mallinimiin,", "To access the GGUF models available for downloading,": "Päästäksesi käsiksi ladattavissa oleviin GGUF-malleihin,", @@ -2055,7 +2055,7 @@ "To select toolkits here, add them to the \"Tools\" workspace first.": "Valitaksesi työkalusettejä tässä, lisää ne ensin \"Työkalut\"-työtilaan.", "Toast notifications for new updates": "Ilmoituspopuppien näyttäminen uusista päivityksistä", "Today": "Tänään", - "Today at": "", + "Today at": "Tänään", "Today at {{LOCALIZED_TIME}}": "Tänään {{LOCALIZED_TIME}}", "Toggle {{COUNT}} sources": "Näytä/piilota {{COUNT}} lähdettä", "Toggle 1 source": "Näytä/piilota 1 lähde", @@ -2111,7 +2111,7 @@ "Unloads {{FROM_NOW}}": "Purkuja {{FROM_NOW}}", "Unlock mysteries": "Selvitä arvoituksia", "Unpin": "Irrota kiinnitys", - "Unpin from Sidebar": "", + "Unpin from Sidebar": "Irrota sivupalkista", "Unravel secrets": "Avaa salaisuuksia", "Unshare Chat": "Lopeta keskustelun jakaminen", "Unsupported file type.": "Ei tuettu tiedostotyyppi", @@ -2196,7 +2196,7 @@ "Waiting for upload...": "Odottaa latausta...", "Warning": "Varoitus", "Warning:": "Varoitus:", - "Warning: Enabling this will allow users to run scheduled prompts automatically.": "", + "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Varoitus: Tämän käyttöönotto sallii käyttäjien suorittaa aikataulutettuja kehotteita automaattisesti.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Varoitus: Tämän käyttöönotto sallii käyttäjien ladata mielivaltaista koodia palvelimelle.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Varoitus: Jupyter käyttö voi mahdollistaa mielivaltaiseen koodin suorittamiseen, mikä voi aiheuttaa tietoturvariskejä - käytä äärimmäisen varoen.", "We_day_of_week": "", @@ -2216,15 +2216,15 @@ "WebUI will make requests to \"{{url}}\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}/chat/completions\"", - "Week": "", - "Weekly": "", + "Week": "Viikko", + "Weekly": "Viikoittain", "What are you trying to achieve?": "Mitä yrität saavuttaa?", "What are you working on?": "Mitä olet työskentelemässä?", "What is NOT shared:": "Mitä EI jaeta:", "What is shared:": "Mitä jaetaan:", "What's New in": "Mitä uutta", "What's on your mind?": "Mitä ajattelet?", - "When": "", + "When": "Milloin", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Kun käytössä, malli vastaa jokaiseen chatviestiin reaaliajassa, tuottaen vastauksen heti kun käyttäjä lähettää viestin. Tämä tila on hyödyllinen reaaliaikaisissa chat-sovelluksissa, mutta voi vaikuttaa suorituskykyyn hitaammilla laitteistoilla.", "wherever you are": "missä tahansa oletkin", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Sivutetaanko tuloste. Jokainen sivu erotetaan toisistaan vaakasuoralla viivalla ja sivunumerolla. Oletusarvo ei käytössä.", @@ -2235,7 +2235,7 @@ "Width": "Leveys", "Wikipedia": "", "Won": "Voitti", - "Working Directory": "", + "Working Directory": "Työhakemisto", "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.": "Toimii top-k:n kanssa. Korkeampi arvo (esim. 0.95) johtaa monipuolisempaan tekstiin, kun taas matalampi arvo (esim. 0.5) tuottaa kohdennetumpaa ja konservatiivisempaa teksti.", "Workspace": "Työtila", "Workspace Permissions": "Työtilan käyttöoikeudet", From d47993385a450411e4cdb90b204cc351dd71a212 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 14:35:15 +0900 Subject: [PATCH 357/404] refac --- backend/requirements.txt | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 9aaa3aad5d..3437ab7652 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -23,7 +23,7 @@ httpx[socks,http2,zstd,cli,brotli]==0.28.1 starsessions[redis]==2.2.1 python-mimeparse==2.0.0 -sqlalchemy==2.0.48 +sqlalchemy[asyncio]==2.0.48 aiosqlite==0.21.0 asyncpg==0.30.0 alembic==1.18.4 diff --git a/pyproject.toml b/pyproject.toml index b6d07a61f7..e405188cb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -31,7 +31,7 @@ dependencies = [ "starsessions[redis]==2.2.1", "python-mimeparse==2.0.0", - "sqlalchemy==2.0.48", + "sqlalchemy[asyncio]==2.0.48", "aiosqlite==0.21.0", "asyncpg==0.30.0", "alembic==1.18.4", From 91d98702666d57a6bcaa6bd8406651d314f0e914 Mon Sep 17 00:00:00 2001 From: Teay Date: Fri, 24 Apr 2026 07:38:12 +0200 Subject: [PATCH 358/404] i18n: update ko-KR translations (conflict solved) (#23949) * i18n: update ko-KR translations * i18n: fix missing ko-KR translations and reviewed pr-bot recommendation --- src/lib/i18n/locales/ko-KR/translation.json | 1295 +++++++++---------- 1 file changed, 630 insertions(+), 665 deletions(-) diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index e29c402508..2acbd0b8a1 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -12,46 +12,41 @@ "{{COUNT}} Available Tools": "사용 가능한 도구 {{COUNT}}개", "{{COUNT}} characters": "{{COUNT}} 문자", "{{COUNT}} extracted lines": "추출된 줄 {{COUNT}}개", - "{{COUNT}} files": "", + "{{COUNT}} files": "{{COUNT}}개 파일", "{{COUNT}} hidden lines": "숨겨진 줄 {{COUNT}}개", - "{{COUNT}} members": "", + "{{COUNT}} members": "{{COUNT}}명의 멤버", "{{COUNT}} Replies": "답글 {{COUNT}}개", - "{{COUNT}} Rows": "", - "{{count}} selected_other": "", + "{{COUNT}} Rows": "{{COUNT}}개 행", + "{{count}} selected_other": "{{count}}개 선택됨", "{{COUNT}} Sources": "{{COUNT}}개의 소스", "{{COUNT}} words": "{{COUNT}} 단어", - "{{COUNT}}d_time_ago": "", - "{{COUNT}}h_time_ago": "", - "{{COUNT}}m_time_ago": "", - "{{COUNT}}w_time_ago": "", - "{{COUNT}}y_time_ago": "", - "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "", + "{{COUNT}}d_time_ago": "{{COUNT}}일 전", + "{{COUNT}}h_time_ago": "{{COUNT}}시간 전", + "{{COUNT}}m_time_ago": "{{COUNT}}분 전", + "{{COUNT}}w_time_ago": "{{COUNT}}주 전", + "{{COUNT}}y_time_ago": "{{COUNT}}년 전", + "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "{{LOCALIZED_DATE}}일 {{LOCALIZED_TIME}}시", "{{model}} download has been canceled": "{{model}} 다운로드가 취소되었습니다.", - "{{modelName}} profile image": "", - "{{NAMES}} reacted with {{REACTION}}": "", + "{{modelName}} profile image": "{{modelName}} 프로필 이미지", + "{{NAMES}} reacted with {{REACTION}}": "{{NAMES}} 님이 {{REACTION}}으로 반응했습니다", "{{user}}'s Chats": "{{user}}의 채팅", "{{webUIName}} Backend Required": "{{webUIName}} 백엔드가 필요합니다.", "*Prompt node ID(s) are required for image generation": "이미지 생성에는 프롬프트 노드 ID가 필요합니다.", - "1 hour before": "", - "1 Source": "소스1", - "10 minutes before": "", - "15 minutes before": "", - "1m_time_ago": "", - "30 minutes before": "", - "5 minutes before": "", - "A collaboration channel where people join as members": "", - "A discussion channel where access is controlled by groups and permissions": "", + "1 Source": "소스 1", + "1m_time_ago": "1분 전", + "A collaboration channel where people join as members": "사람들이 멤버로 참여하는 협업 채널", + "A discussion channel where access is controlled by groups and permissions": "그룹과 권한으로 접근이 제어되는 토론 채널", "A new version (v{{LATEST_VERSION}}) is now available.": "새로운 버전 (v{{LATEST_VERSION}})을 사용할 수 있습니다.", - "A private conversation between you and selected users": "", + "A private conversation between you and selected users": "나와 선택한 사용자 간의 비공개 대화", "A task model is used when performing tasks such as generating titles for chats and web search queries": "작업 모델은 채팅 및 웹 검색 쿼리에 대한 제목 생성 등의 작업 수행 시 사용됩니다.", "a user": "사용자", "About": "정보", - "Accept Autocomplete Generation\nJump to Prompt Variable": "", + "Accept Autocomplete Generation\nJump to Prompt Variable": "자동완성 생성 수락\n프롬프트 변수로 이동", "Access": "접근", "Access Control": "접근 제어", - "Access Grants": "", - "Access List": "", - "Access updated": "", + "Access Grants": "접근 권한", + "Access List": "접근 목록", + "Access updated": "접근 업데이트", "Accessible to all users": "모든 사용자가 이용할 수 있음", "Account": "계정", "Account Activation Pending": "계정 활성화 대기", @@ -64,65 +59,62 @@ "Activate this command by typing \"/{{COMMAND}}\" to chat input.": "채팅 입력창에 \"{{COMMAND}}\"을 입력해 명령을 실행하세요.", "Active": "활성", "Active Users": "활성 사용자", - "Activity": "", + "Activity": "활동", "Add": "추가", "Add a model ID": "모델 ID 추가", "Add a short description about what this model does": "모델의 기능에 대한 간단한 설명 추가", "Add a tag": "태그 추가", - "Add a tag...": "", - "Add Access": "", + "Add a tag...": "태그 추가...", + "Add Access": "접근 권한 추가", "Add Arena Model": "아레나 모델 추가", "Add Connection": "연결 추가", "Add Content": "내용 추가", "Add content here": "여기에 내용을 추가하세요", "Add Custom Parameter": "사용자 정의 매개변수 추가", "Add Custom Prompt": "사용자 정의 프롬프트 추가", - "Add description": "", "Add Details": "디테일 추가", "Add Files": "파일 추가", - "Add Image": "", - "Add location": "", + "Add Image": "이미지 추가", "Add Member": "멤버 추가", "Add Members": "멤버 추가", "Add Memory": "메모리 추가", "Add Model": "모델 추가", "Add Reaction": "리액션 추가", - "Add tag": "", + "Add tag": "태그 추가", "Add Tag": "태그 추가", - "Add Terminal": "", - "Add Terminal Connection": "", + "Add Terminal": "터미널 추가", + "Add Terminal Connection": "터미널 연결 추가", "Add text content": "글 추가", - "Add to favorites": "", + "Add to favorites": "즐겨찾기에 추가", "Add User": "사용자 추가", "Add User Group": "사용자 그룹 추가", - "Add webpage": "", - "Add your Open Terminal URL and API key in Settings → Integrations.": "", + "Add webpage": "웹페이지 추가", + "Add your Open Terminal URL and API key in Settings → Integrations.": "설정 → 통합에서 Open Terminal URL과 API 키를 추가하세요.", "Additional Config": "추가 설정", "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": "Marker에 대한 추가 설정 옵션입니다. 키-값 쌍으로 이루어진 JSON 문자열이어야 합니다. 예를 들어, '{\"key\": \"value\"}'와 같습니다. 지원되는 키는 다음과 같습니다: 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": "", + "Additional feedback comments": "추가 피드백 의견", "Additional Parameters": "추가 매개변수", - "Adds filenames, titles, sections, and snippets into the BM25 text to improve lexical recall.": "", + "Adds filenames, titles, sections, and snippets into the BM25 text to improve lexical recall.": "어휘 검색 재현율을 높이기 위해 BM25 텍스트에 파일명, 제목, 섹션, 스니펫을 추가합니다.", "Adjusting these settings will apply changes universally to all users.": "이 설정을 조정하면 모든 사용자에게 변경 사항이 일괄 적용됩니다.", "admin": "관리자", "Admin": "관리자", - "Admin Contact Email": "", + "Admin Contact Email": "관리자 이메일", "Admin Panel": "관리자 패널", "Admin Settings": "관리자 설정", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "관리자는 항상 모든 도구에 접근할 수 있지만, 사용자는 워크스페이스에서 모델마다 도구를 할당받아야 합니다.", - "Advanced": "", + "Advanced": "고급", "Advanced Parameters": "고급 매개변수", - "Advanced parameters for MinerU parsing (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)": "", + "Advanced parameters for MinerU parsing (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)": "MinerU 파싱을 위한 고급 매개변수(enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)", "Advanced Params": "고급 매개변수", "After updating or changing the embedding model, you must reindex the knowledge base for the changes to take effect. You can do this using the \"Reindex\" button below.": "임베딩 모델을 업데이트하거나 변경 후 변경 사항을 적용하려면 지식 베이스를 다시 인덱싱해야 합니다. 아래의 \"재색인\" 버튼을 사용하여 수행할 수 있습니다.", - "AI": "", + "AI": "AI", "All": "전체", "All chats have been unarchived.": "모든 채팅이 보관 해제되었습니다.", - "All day": "", - "All models are now hidden": "", - "All models are now visible": "", + "All models are now hidden": "모든 모델이 이제 숨김 처리되었습니다", + "All models are now visible": "모든 모델이 이제 표시됩니다", "All models deleted successfully": "성공적으로 모든 모델이 삭제되었습니다", - "All time": "", - "All Users": "", + "All time": "전체 기간", + "All Users": "모든 사용자", "Allow Call": "음성 통화 허용", "Allow Chat Controls": "채팅 제어 허용", "Allow Chat Delete": "채팅 삭제 허용", @@ -137,16 +129,16 @@ "Allow File Upload": "파일 업로드 허용", "Allow Multiple Models in Chat": "채팅에서 여러 모델 허용", "Allow non-local voices": "외부 음성 허용", - "Allow public write access": "", - "Allow Rate Response": "", + "Allow public write access": "공개 쓰기 접근 허용", + "Allow Rate Response": "응답 평가 허용", "Allow Regenerate Response": "응답 재생성 허용", - "Allow Sharing With Users": "", + "Allow Sharing With Users": "사용자와 공유 허용", "Allow Speech to Text": "음성 텍스트 변환 허용", "Allow Temporary Chat": "임시 채팅 허용", "Allow Text to Speech": "텍스트 음성 변환 허용", "Allow User Location": "사용자 위치 활용 허용", "Allow Voice Interruption in Call": "음성 기능에서 음성 방해 허용", - "Allow Web Upload": "", + "Allow Web Upload": "웹 업로드 허용", "Allowed Endpoints": "허용 엔드포인트", "Allowed File Extensions": "허용 파일 확장자", "Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.": "업로드할 수 있는 파일 확장자. 여러 확장자를 구분하기 위해 쉼표로 구분합니다. 모든 파일 유형을 허용하려면 비워두세요.", @@ -165,50 +157,48 @@ "and {{COUNT}} more": "그리고 {{COUNT}}개 더", "and create a new shared link.": "새로운 공유 링크를 생성합니다.", "Android": "안드로이드", - "Anyone": "", + "Anyone": "누구나", "API Base URL": "API 기본 URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "Datalab Marker 서비스의 API URL. 기본값: https://www.datalab.to/api/v1/marker", "API Key": "API 키", "API Key created.": "API 키가 생성되었습니다.", "API Key Endpoint Restrictions": "API 키 엔드포인트 제한", "API keys": "API 키", - "API Keys": "", - "API Mode": "", - "API Timeout": "", - "API Type": "", + "API Keys": "API 키", + "API Mode": "API 모드", + "API Timeout": "API 시간 초과", + "API Type": "API 유형", "API Version": "API 버전", - "API Version is required": "", + "API Version is required": "API 버전이 필요합니다", "Application DN": "Application DN", "Application DN Password": "Application DN 비밀번호", "applies to all users with the \"user\" role": "\"사용자\" 권한의 모든 사용자에게 적용됩니다", "April": "4월", "Archive": "보관", - "Archive All": "", + "Archive All": "모두 보관", "Archive All Chats": "모든 채팅 보관", "Archived Chats": "보관된 채팅", "archived-chat-export": "보관된 채팅 내보내기", - "Are you sure you want to archive all chats? This action cannot be undone.": "", + "Are you sure you want to archive all chats? This action cannot be undone.": "정말 모든 채팅을 보관하시겠습니까? 이 작업은 되돌릴 수 없습니다.", "Are you sure you want to clear all memories? This action cannot be undone.": "정말 모든 메모리를 지우시겠습니까? 이 작업은 되돌릴 수 없습니다.", - "Are you sure you want to delete \"{{NAME}}\"?": "", - "Are you sure you want to delete **{{modelName}}**?": "", - "Are you sure you want to delete all chats? This action cannot be undone.": "", + "Are you sure you want to delete \"{{NAME}}\"?": "정말 \"{{NAME}}\"을 삭제하시겠습니까?", + "Are you sure you want to delete all chats? This action cannot be undone.": "정말 모든 채팅을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", "Are you sure you want to delete this channel?": "정말 이 채널을 삭제하시겠습니까?", - "Are you sure you want to delete this connection? This action cannot be undone.": "", - "Are you sure you want to delete this memory? This action cannot be undone.": "", + "Are you sure you want to delete this connection? This action cannot be undone.": "정말 이 연결을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", + "Are you sure you want to delete this memory? This action cannot be undone.": "정말 이 메모리를 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", "Are you sure you want to delete this message?": "정말 이 메시지를 삭제하시겠습니까?", - "Are you sure you want to delete this version? Child versions will be relinked to this version's parent.": "", - "Are you sure you want to delete this?": "", + "Are you sure you want to delete this version? Child versions will be relinked to this version's parent.": "정말 이 버전을 삭제하시겠습니까? 하위 버전은 이 버전의 상위 버전에 다시 연결됩니다.", + "Are you sure you want to delete this?": "정말 이 항목을 삭제하시겠습니까?", "Are you sure you want to unarchive all archived chats?": "정말 보관된 모든 채팅을 보관 해제하시겠습니까?", "Arena Models": "Arena 모델", "Artifacts": "아티팩트", - "Asc": "", + "Asc": "오름차순", "Ask": "질문", "Ask a question": "질문하기", "Assistant": "어시스턴트", - "Async Embedding Processing": "", - "At time of event": "", + "Async Embedding Processing": "비동기 임베딩 처리", "Attach File From Knowledge": "지식 기반에서 파일 첨부", - "Attach Files": "", + "Attach Files": "첨부 파일", "Attach Knowledge": "지식 기반 첨부", "Attach Notes": "노트 첨부", "Attach Webpage": "웹페이지 첨부", @@ -221,7 +211,7 @@ "Authenticate": "인증하다", "Authentication": "인증", "Auto": "자동", - "Auto (Random)": "", + "Auto (Random)": "자동 (랜덤)", "Auto-Copy Response to Clipboard": "응답을 클립보드에 자동 복사", "Auto-playback response": "응답 자동 재생", "Autocomplete Generation": "자동완성 생성", @@ -230,16 +220,16 @@ "AUTOMATIC1111 Api Auth String": "Automatic1111 API 인증 문자", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 기본 URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 기본 URL 설정이 필요합니다.", - "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", - "Automation": "", - "Automation created": "", - "Automation Name": "", - "Automation title": "", - "Automation triggered": "", - "Automation updated": "", - "Automations": "", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "네이티브 함수 호출 모드에서 시스템 도구(예: 타임스탬프, 메모리, 채팅 기록, 노트 등)를 자동으로 삽입합니다.", + "Automation": "자동", + "Automation created": "자동 생성", + "Automation Name": "자동 생성된 이름", + "Automation title": "자동 생성된 제목", + "Automation triggered": "자동 시행", + "Automation updated": "자동 업데이트", + "Automations": "자동", "Available list": "가능한 목록", - "Available models": "", + "Available models": "사용 가능한 모델", "Available Tools": "사용 가능한 도구", "available users": "사용 가능 사용자", "available!": "사용 가능!", @@ -253,11 +243,11 @@ "Banners": "배너", "Base Model (From)": "기본 모델(시작)", "Base Model List Cache speeds up access by fetching base models only at startup or on settings save—faster, but may not show recent base model changes.": "기본 모델 목록 캐시는 시작 시 또는 설정 저장 시에만 기본 모델을 불러와 접근 속도를 높여줍니다. 이는 더 빠르지만, 최근 기본 모델 변경 사항이 반영되지 않을 수 있습니다.", - "Bearer": "", + "Bearer": "보유자", "before": "이전", "Being lazy": "게으름 피우기", "Beta": "베타", - "Bing": "", + "Bing": "Bing", "Bing Search V7 Endpoint": "Bing Search V7 엔드포인트", "Bing Search V7 Subscription Key": "Bing Search V7 구독 키", "Bio": "소개", @@ -266,42 +256,40 @@ "Bocha Search API Key": "Bocha Search API 키", "Bold": "굵게", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "특정 토큰을 가중 상향/하향하여 응답을 제약합니다. 값은 -100 ~ 100(기본값: 없음)", - "Brave": "", + "Brave": "Brave", "Brave Search API Key": "Brave Search API 키", - "Break down complex requests into trackable steps": "", - "Browse and query knowledge bases": "", - "Builtin Tools": "", + "Break down complex requests into trackable steps": "복잡한 요청을 추적 가능한 단계로 나누세요", + "Browse and query knowledge bases": "지식 기반 탐색 및 쿼리", + "Builtin Tools": "내장(빌트인) 도구", "Bullet List": "글머리 기호 목록", "Button ID": "버튼 ID", "Button Label": "버튼 레이블", "Button Prompt": "버튼 프롬프트", - "by {{name}}": "", + "by {{name}}": "작성자: {{name}}", "By {{name}}": "작성자: {{name}}", "Bypass Embedding and Retrieval": "임베딩 검색 우회", "Bypass Web Loader": "웹 콘텐츠 불러오기 생략", "Cache Base Model List": "기본 모델 목록 캐시", "Calendar": "캘린더", - "Calendar deleted": "", - "Calendars": "", "Call": "음성 기능", "Call feature is not supported when using Web STT engine": "웹 STT 엔진 사용 시, 음성 기능은 지원되지 않습니다.", "Camera": "카메라", "Cancel": "취소", - "Cancel download of {{model}}": "", - "Cannot create an empty note.": "", - "Cannot delete the production version": "", + "Cancel download of {{model}}": "{{model}} 다운로드 취소", + "Cannot create an empty note.": "빈 노트를 생성할 수 없습니다.", + "Cannot delete the production version": "이 프로덕션 버전은 삭제할 수 없습니다.", "Capabilities": "기능", "Capture": "캡처", "Capture Audio": "오디오 캡처", "Certificate Path": "인증서 경로", - "Change folder icon": "", + "Change folder icon": "폴더 아이콘 변경", "Change Password": "비밀번호 변경", - "Change User Role": "", + "Change User Role": "사용자 역할 변경", "Channel": "채널", "Channel deleted successfully": "채널 삭제 성공", "Channel Name": "채널 이름", "Channel name cannot be empty.": "채널 이름은 비워둘 수 없습니다.", - "Channel name must be less than 128 characters": "", + "Channel name must be less than 128 characters": "채널 이름은 128자 미만이어야 합니다", "Channel Type": "채널 타입", "Channel updated successfully": "채널 업데이트 성공", "Channels": "채널", @@ -309,35 +297,35 @@ "Character limit for autocomplete generation input": "자동 완성 생성 입력 문자 제한", "Chart new frontiers": "새로운 영역 개척", "Chat": "채팅", - "Chat archived.": "", + "Chat archived.": "채팅 보관됨.", "Chat Background Image": "채팅 배경 이미지", "Chat Bubble UI": "버블형 채팅 UI", - "Chat Completions": "", + "Chat Completions": "채팅 완성", "Chat Conversation": "채팅 대화", "Chat direction": "채팅 방향", - "Chat exported successfully": "", - "Chat History": "", + "Chat exported successfully": "채팅 내보내기 성공", + "Chat History": "채팅 기록", "Chat ID": "채팅 ID", "Chat moved successfully": "채팅 이동 성공", "Chat Permissions": "채팅 권한", "Chat Tags Auto-Generation": "채팅 태그 자동생성", - "Chat unshared successfully.": "", - "chats": "", + "Chat unshared successfully.": "채팅 공유 해제 성공", + "chats": "채팅", "Chats": "채팅", "Check Again": "다시 확인", "Check for updates": "업데이트 확인", "Checking for updates...": "업데이트 확인중...", "Choose a model before saving...": "저장하기 전에 모델을 선택하세요...", - "Chunk Min Size Target": "", + "Chunk Min Size Target": "최소 청크 크기 목표", "Chunk Overlap": "청크 중첩", "Chunk Size": "청크 크기", - "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "이 임계값보다 작은 청크는 가능한 경우 이웃한 청크와 병합됩니다. 병합을 비활성화하려면 0으로 설정하세요.", "Ciphers": "암호", "Citation": "인용", "Citations": "인용", "Clear memory": "메모리 초기화", "Clear Memory": "메모리 지우기", - "Clear search": "", + "Clear search": "검색 초기화", "Clear status": "상태 초기화", "click here": "여기를 클릭하세요", "Click here for filter guides.": "필터 가이드를 보려면 여기를 클릭하세요.", @@ -352,30 +340,30 @@ "Click here to upload a workflow.json file.": "workflow.json 파일을 업로드하려면 여기를 클릭하세요", "click here.": "여기를 클릭하세요.", "Click on the user role button to change a user's role.": "사용자 역할 버튼을 클릭하여 사용자의 역할을 변경하세요.", - "Click to connect": "", - "Click to copy ID": "", - "Client ID": "", - "Client Secret": "", + "Click to connect": "연결하려면 클릭하세요", + "Click to copy ID": "ID를 복사하려면 클릭하세요", + "Client ID": "클라이언트 ID", + "Client Secret": "클라이언트 시크릿", "Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "클립보드 쓰기 권한이 거부되었습니다. 브라우저 설정에서 권한을 허용해주세요.", "Clone": "복제", "Clone Chat": "채팅 복제", "Clone of {{TITLE}}": "{{TITLE}}의 복제본", "Close": "닫기", "Close Banner": "배너 닫기", - "Close chat controls": "", - "Close citation modal": "", + "Close chat controls": "채팅 제어 닫기", + "Close citation modal": "인용 모달 닫기", "Close Configure Connection Modal": "연결 설정 닫기", - "Close feedback": "", + "Close feedback": "피드백 닫기", "Close modal": "닫기", - "Close Modal": "", + "Close Modal": "모달 닫기", "Close settings modal": "설정 닫기", "Close Sidebar": "사이드바 닫기", - "cloud": "", + "cloud": "클라우드", "CMU ARCTIC speaker embedding name": "CMU ARCTIC 화자 임베딩 이름", "Code Block": "코드 블록", "Code Editor": "코드 편집기", "Code execution": "코드 실행", - "Code Execution": "", + "Code Execution": "코드 실행", "Code Execution Engine": "코드 실행 엔진", "Code Execution Timeout": "코드 실행 시간 초과", "Code formatted successfully": "코드 포맷팅이 성공적으로 완료되었습니다.", @@ -385,7 +373,7 @@ "Collaboration channel where people join as members": "사람들이 멤버로 참여하는 협업 채널", "Collapse": "접기", "Collection": "컬렉션", - "Collections": "", + "Collections": "컬렉션", "Color": "색상", "ComfyUI": "ComfyUI", "ComfyUI API Key": "ComfyUI API 키", @@ -394,32 +382,31 @@ "ComfyUI Workflow": "ComfyUI 워크플로", "ComfyUI Workflow Nodes": "ComfyUI 워크플로 노드", "Comma separated Node Ids (e.g. 1 or 1,2)": "쉼표로 구분된 노드 아이디 (예: 1 또는 1,2)", - "command": "", + "command": "명령", "Command": "명령", "Comment": "주석", - "Commit Message": "", - "Community Reviews": "", + "Commit Message": "커밋 메시지", + "Community Reviews": "커뮤니티 리뷰", "Completions": "완성됨", "Compress Images in Channels": "채널에 이미지들 압축하기", "Concurrent Requests": "동시 요청 수", - "Config": "", + "Config": "구성", "Config imported successfully": "구성을 성공적으로 가져왔습니다", - "Configuration": "", + "Configuration": "구성", "Configure": "구성", "Confirm": "확인", "Confirm Password": "비밀번호 확인", - "Confirm Prompt from Embed": "", + "Confirm Prompt from Embed": "임베드에서 확인 프롬프트", "Confirm your action": "작업 확인", "Confirm your new password": "새로운 비밀번호를 한 번 더 입력해 주세요", "Confirm Your Password": "비밀번호를 확인해주세요", - "Connect to an AI provider to start chatting": "", - "Connect to Open Terminal instances to browse files and use them as always-on tools. Only one can be active at a time.": "", - "Connect to Open Terminal instances. All users will have access to file browsing and terminal tools through these servers.": "", + "Connect to an AI provider to start chatting": "AI 제공자에 연결하여 채팅을 시작하세요", + "Connect to Open Terminal instances to browse files and use them as always-on tools. Only one can be active at a time.": "파일을 탐색하고 항상 켜진 도구로 사용하려면 Open Terminal 인스턴스에 연결하세요. 한 번에 하나만 활성화할 수 있습니다.", + "Connect to Open Terminal instances. All users will have access to file browsing and terminal tools through these servers.": "Open Terminal 인스턴스에 연결합니다. 모든 사용자는 이 서버를 통해 파일 탐색과 터미널 도구를 사용할 수 있습니다.", "Connect to your own OpenAI compatible API endpoints.": "OpenAI 호환 API 엔드포인트에 연결합니다.", "Connect to your own OpenAPI compatible external tool servers.": "OpenAPI 호환 외부 도구 서버에 연결합니다.", - "Connected ({{type}})": "", + "Connected ({{type}})": "{{type}}에 연결됨", "Connection failed": "연결 실패", - "Connection lost. Reconnecting...": "", "Connection successful": "연결 성공", "Connection Type": "연결 방식", "Connections": "연결", @@ -429,7 +416,7 @@ "Contact Admin for WebUI Access": "WebUI 접속을 위해서는 관리자에게 연락에 연락하십시오", "Content": "내용", "Content Extraction Engine": "콘텐츠 추출 엔진", - "Content lengths (character counts only)": "", + "Content lengths (character counts only)": "콘텐츠 길이(문자 수만)", "Continue Response": "응답 이어 받기", "Continue with {{provider}}": "{{provider}}로 계속", "Continue with Email": "이메일로 계속", @@ -444,30 +431,30 @@ "Copied shared chat URL to clipboard!": "채팅 공유 URL이 클립보드에 복사되었습니다!", "Copied to clipboard": "클립보드에 복사되었습니다", "Copy": "복사", - "Copy API Key": "", - "Copy content": "", + "Copy API Key": "API 키 복사", + "Copy content": "콘텐츠 복사", "Copy Formatted Text": "서식 있는 텍스트 복사", "Copy Last Code Block": "마지막 코드 블록 복사", "Copy Last Response": "마지막 응답 복사", "Copy link": "링크 복사", "Copy Link": "링크 복사", - "Copy Path": "", - "Copy Prompt": "", - "Copy Share Link": "", + "Copy Path": "경로 복사", + "Copy Prompt": "프롬프트 복사", + "Copy Share Link": "공유 링크 복사", "Copy to clipboard": "클립보드에 복사", - "Copy Token": "", - "Copy URL": "", + "Copy Token": "토큰 복사", + "Copy URL": "URL 복사", "Copying to clipboard was successful!": "성공적으로 클립보드에 복사되었습니다!", "CORS must be properly configured by the provider to allow requests from Open WebUI.": "Open WebUI의 요청을 허용하려면 공급자가 CORS를 올바르게 구성해야 합니다.", - "Could not read file.": "", - "CPU": "", + "Could not read file.": "파일을 읽을 수 없습니다.", + "CPU": "CPU", "Create": "생성", "Create a knowledge base": "지식 기반 생성", "Create a model": "모델 생성", "Create a new note": "새 노트 생성", "Create Account": "계정 생성", "Create Admin Account": "관리자 계정 생성", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "예약된 자동화를 생성하고 관리합니다", "Create Channel": "채널 생성", "Create Folder": "폴더 생성", "Create Image": "이미지 생성", @@ -475,37 +462,37 @@ "Create Model": "모델 생성", "Create new key": "새로운 키 생성", "Create new secret key": "새로운 비밀 키 생성", - "Create note": "", + "Create note": "노트 생성", "Create Note": "노트 생성", - "Create scheduled prompts that run automatically on a recurring basis.": "", + "Create scheduled prompts that run automatically on a recurring basis.": "반복적으로 자동으로 실행되는 예약 프롬프트를 생성합니다.", "Create your first note by clicking on the plus button below.": "아래의 플러스 버튼을 클릭하여 첫 번째 노트를 생성하세요.", "Created at": "생성일", "Created At": "생성일", "Created by": "작성자", - "Created by you": "", - "Created on {{date}}": "", + "Created by you": "당신이 생성함", + "Created on {{date}}": "{{date}}에 생성됨", "CSV Import": "CSV 가져오기", "Ctrl+Enter to Send": "Ctrl+Enter로 보내기", "Current Model": "현재 모델", "Current Password": "현재 비밀번호", "Custom": "사용자 정의", "Custom description enabled": "사용자 정의 설명 활성화됨", - "Custom Gender": "", + "Custom Gender": "사용자 정의 성별", "Custom Parameter Name": "사용자 정의 매개변수 이름", "Custom Parameter Value": "사용자 정의 매개변수 값", - "Daily": "", - "Daily Messages": "", + "Daily": "매일", + "Daily Messages": "일일 메시지", "Danger Zone": "위험 기능", "Dark": "다크", "Data Controls": "데이터 제어", "Database": "데이터베이스", "Datalab Marker API": "Datalab Marker API", - "Day": "", + "Day": "일", "DD/MM/YYYY": "YYYY/MM/DD", - "DDGS Backend": "", + "DDGS Backend": "DDGS 백엔드", "December": "12월", - "Decrease UI Scale": "", - "Deepgram": "", + "Decrease UI Scale": "UI 크기 축소", + "Deepgram": "Deepgram", "Default": "기본값", "Default (Open AI)": "기본값 (Open AI)", "Default (SentenceTransformers)": "기본값 (SentenceTransformers)", @@ -513,7 +500,7 @@ "Default description enabled": "기본 설명 활성화됨", "Default Features": "기본 기능", "Default Filters": "기본 필터", - "Default Group": "", + "Default Group": "기본 그룹", "Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model's built-in tool-calling capabilities, but requires the model to inherently support this feature.": "기본 모드는 실행 전에 도구를 한 번 호출하여 더 다양한 모델에서 작동합니다. 기본 모드는 모델에 내장된 도구 호출 기능을 활용하지만, 모델이 이 기능을 본질적으로 지원해야 합니다.", "Default Model": "기본 모델", "Default model updated": "기본 모델이 업데이트되었습니다.", @@ -524,56 +511,53 @@ "Default to ALL": "기본값: 전체", "Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.": "집중적이고 관련성 있는 콘텐츠 추출을 위해 세분화된 검색을 기본으로 하며, 대부분의 경우에 권장됩니다.", "Default User Role": "기본 사용자 역할", - "Defaults": "", + "Defaults": "기본값", "Delete": "삭제", - "Delete {{name}}": "", + "Delete {{name}}": "{{name}} 삭제", "Delete a model": "모델 삭제", - "Delete All": "", + "Delete All": "모두 삭제", "Delete All Chats": "모든 채팅 삭제", - "Delete all contents inside this folder": "", - "Delete automation?": "", - "Delete calendar": "", - "Delete Calendar": "", + "Delete all contents inside this folder":"이 폴더 내 모든 콘텐츠 삭제", + "Delete automation?": "자동 삭제하시겠습니까?", "Delete Chat": "채팅 삭제", "Delete chat?": "채팅을 삭제하시겠습니까?", - "Delete Event": "", - "Delete File": "", + "Delete File": "파일 삭제", "Delete folder?": "폴더를 삭제하시겠습니까?", "Delete function?": "함수를 삭제하시겠습니까?", - "Delete Memory?": "", + "Delete Memory?": "메모리를 삭제하시겠습니까?", "Delete Message": "메시지 삭제", "Delete message?": "메시지를 삭제하시겠습니까?", "Delete Model": "모델 삭제", "Delete note?": "노트를 삭제하시겠습니까?", "Delete prompt?": "프롬프트를 삭제하시겠습니까?", - "Delete skill?": "", + "Delete skill?": "스킬을 삭제하시겠습니까?", "delete this link": "이 링크를 삭제합니다.", "Delete tool?": "도구를 삭제하시겠습니까?", "Delete User": "사용자 삭제", - "Delete Version": "", - "Deleted": "", + "Delete Version": "버전 삭제", + "Deleted": "삭제됨", "Deleted {{deleteModelTag}}": "{{deleteModelTag}} 삭제됨", "Deleted {{name}}": "{{name}}을(를) 삭제했습니다.", - "Deleted {{ok}} of {{total}} items": "", + "Deleted {{ok}} of {{total}} items": "총 {{total}}개 항목 중 {{ok}}개가 삭제되었습니다.", "Deleted User": "삭제된 사용자", "Deployment names are required for Azure OpenAI": "Azure OpenAI 사용 시 배포 이름은 필수입니다.", - "Desc": "", - "Describe the edit...": "", - "Describe the image...": "", - "Describe what changed...": "", + "Desc": "내림차순", + "Describe the edit...": "편집 내용 설명...", + "Describe the image...": "이미지 설명...", + "Describe what changed...": "변경 내용 설명...", "Describe your knowledge base and objectives": "지식 기반에 대한 설명과 목적을 입력하세요", "Description": "설명", - "Deselect": "", + "Deselect": "선택 해제", "Detect Artifacts Automatically": "아티팩트 자동 감지", "Dictate": "마이크 사용", "Didn't fully follow instructions": "완전히 지침을 따르지 않음", - "Direct": "", + "Direct": "직접", "Direct Connections": "직접 연결", "Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "직접 연결을 통해 사용자는 자체 OpenAI 호환 API 엔드포인트에 연결할 수 있습니다.", "Direct Message": "1:1 메시지", "Direct Tool Servers": "다이렉트 도구 서버", - "Directory selection was cancelled": "", - "Disable All": "", + "Directory selection was cancelled": "디렉토리 선택이 취소되었습니다.", + "Disable All": "모두 비활성화", "Disable Code Interpreter": "코드 인터프리터 비활성화", "Disable Image Extraction": "이미지 추출 비활성화", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDF에서 이미지 추출을 비활성화합니다. Use LLM이 활성화된 경우 이미지는 자동으로 캡션이 달립니다. 기본값은 False입니다.", @@ -588,7 +572,7 @@ "Discover, download, and explore custom prompts": "사용자 정의 프롬프트 검색, 다운로드 및 탐색", "Discover, download, and explore custom tools": "사용자 정의 도구 검색, 다운로드 및 탐색", "Discover, download, and explore model presets": "모델 사전 설정 검색, 다운로드 및 탐색", - "Discussion channel where access is based on groups and permissions": "", + "Discussion channel where access is based on groups and permissions": "그룹과 권한을 기반으로 액세스하는 토론 채널", "Display": "표시", "Display chat title in tab": "탭에 채팅 목록 표시", "Display Emoji in Call": "음성기능에서 이모지 표시", @@ -599,16 +583,16 @@ "Dive into knowledge": "지식 탐구", "Do not install functions from sources you do not fully trust.": "불분명한 출처를 가진 함수를 설치하지마세요", "Do not install tools from sources you do not fully trust.": "불분명한 출처를 가진 도구를 설치하지마세요", - "Do you want to sync your usage stats with Open WebUI Community?": "", - "Docling": "", - "Docling Parameters": "", + "Do you want to sync your usage stats with Open WebUI Community?": "사용 통계를 Open WebUI 커뮤니티와 동기화하시겠습니까?", + "Docling": "Docling", + "Docling Parameters": "Docling 매개변수", "Docling Server URL required.": "Docling 서버 URL이 필요합니다.", "Document": "문서", - "Document Intelligence": "", - "Document Intelligence endpoint required.": "", - "Document Intelligence Model": "", + "Document Intelligence": "문서 인텔리전스", + "Document Intelligence endpoint required.": "문서 인텔리전스 엔드포인트가 필요합니다.", + "Document Intelligence Model": "문서 인텔리전스 모델", "Documentation": "문서", - "Documents": "", + "Documents": "문서", "does not make any external connections, and your data stays securely on your locally hosted server.": "외부와 어떠한 연결도 하지 않으며, 데이터는 로컬에서 호스팅되는 서버에 안전하게 유지됩니다.", "Domain Filter List": "도메인 필터 목록", "don't fetch random pipelines from sources you don't trust.": "신뢰하지 않는 출처에서 임의의 파이프라인을 가져오지 마세요.", @@ -619,34 +603,34 @@ "Done": "완료됨", "Download": "다운로드", "Download & Delete": "다운로드 및 삭제", - "Download as JSON": "", + "Download as JSON": "JSON으로 다운로드", "Download as SVG": "SVG로 다운로드", "Download canceled": "다운로드 취소", "Download Database": "데이터베이스 다운로드", - "Downloading stats...": "", + "Downloading stats...": "통계 다운로드 중...", "Draw": "그리기", "Drop any files here to upload": "여기에 파일을 끌어다 놓아 업로드하세요", - "Drop files here": "", - "Drop files here to upload": "", - "DuckDuckGo": "", + "Drop files here": "파일을 여기에 끌어다 놓으세요", + "Drop files here to upload": "업로드할 파일을 여기에 끌어다 놓으세요", + "DuckDuckGo": "DuckDuckGo", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "예: '30초','10분'. 올바른 시간 단위는 '초', '분', '시'입니다.", - "e.g. 'low', 'medium', 'high'": "", + "e.g. 'low', 'medium', 'high'": "예: '낮음', '중간', '높음'", "e.g. \"json\" or a JSON schema": "예: \\\"json\\\" 또는 JSON 스키마", "e.g. 60": "예: 60", "e.g. A filter to remove profanity from text": "예: 텍스트에서 비속어를 제거하는 필터", - "e.g. about the Roman Empire": "", - "e.g. alloy, echo, shimmer": "", - "e.g. Code Review Guidelines": "", - "e.g. code-review-guidelines": "", + "e.g. about the Roman Empire": "예: 로마 제국에 대해", + "e.g. alloy, echo, shimmer": "예: alloy, echo, shimmer", + "e.g. Code Review Guidelines": "예: 코드 리뷰 가이드라인", + "e.g. code-review-guidelines": "예: code-review-guidelines", "e.g. en": "예: en", "e.g. My Filter": "예: 내 필터", "e.g. My Tools": "예: 내 도구", "e.g. my_filter": "예: my_filter", "e.g. my_tools": "예: my_tools", "e.g. pdf, docx, txt": "예: pdf, docx, txt", - "e.g. Step-by-step instructions for code reviews": "", - "e.g. Tell me a fun fact": "", - "e.g. Tell me a fun fact about the Roman Empire": "", + "e.g. Step-by-step instructions for code reviews": "예: 코드 리뷰를 위한 단계별 지침", + "e.g. Tell me a fun fact": "예: 재미있는 사실을 말해주세요", + "e.g. Tell me a fun fact about the Roman Empire": "예: 로마 제국에 대한 재미있는 사실을 말해주세요", "e.g. Tools for performing various operations": "예: 다양한 작업을 수행하는 도구", "e.g., 3, 4, 5 (leave blank for default)": "예: 3, 4, 5 (기본값을 위해 비워 두세요)", "e.g., audio/wav,audio/mpeg,video/* (leave blank for defaults)": "예: audio/wav,audio/mpeg,video/* (기본값은 빈칸)", @@ -659,55 +643,55 @@ "Edit Default Permissions": "기본 권한 편집", "Edit Folder": "폴더 편집", "Edit Image": "이미지 편집", - "Edit Last Message": "", + "Edit Last Message": "마지막 메시지 편집", "Edit Memory": "메모리 편집", - "Edit Prompt": "", - "Edit Terminal Connection": "", + "Edit Prompt": "프롬프트 편집", + "Edit Terminal Connection": "터미널 연결 편집", "Edit User": "사용자 편집", "Edit User Group": "사용자 그룹 편집", - "Edit workflow.json content": "", + "Edit workflow.json content": "workflow.json 콘텐츠 편집", "edited": "수정됨", "Edited": "수정됨", "Editing": "수정중", "Eject": "추출", - "Eject model": "", + "Eject model": "모델 추출", "ElevenLabs": "ElevenLabs", "Email": "이메일", "Embark on adventures": "모험을 떠나기", "Embedding": "임베딩", "Embedding Batch Size": "임베딩 배치 크기", - "Embedding Concurrent Requests": "", + "Embedding Concurrent Requests": "임베딩 동시 요청 수", "Embedding Model": "임베딩 모델", "Embedding Model Engine": "임베딩 모델 엔진", - "Emojis": "", - "Empty message": "", - "Enable All": "", - "Enable API Keys": "", + "Emojis": "이모티콘", + "Empty message": "빈 메시지", + "Enable All": "모두 활성화", + "Enable API Keys": "API 키 활성화", "Enable autocomplete generation for chat messages": "채팅 메시지에 대한 자동 완성 생성 활성화", "Enable Code Execution": "코드 실행 활성화", "Enable Code Interpreter": "코드 인터프리터 활성화", "Enable Community Sharing": "커뮤니티 공유 활성화", "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.": "모델 데이터가 RAM에서 스왑 아웃되는 것을 방지하기 위해 메모리 잠금(mlock)을 활성화합니다. 이 옵션은 모델의 작업 페이지 집합을 RAM에 잠가 디스크로 스왑 아웃되지 않도록 보장합니다. 이는 페이지 폴트를 피하고 빠른 데이터 액세스를 보장하여 성능을 유지하는 데 도움이 될 수 있습니다.", "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.": "모델 데이터를 로드하기 위해 메모리 매핑(mmap)을 활성화합니다. 이 옵션을 사용하면 시스템이 디스크 파일을 RAM에 있는 것처럼 처리하여 디스크 스토리지를 RAM의 확장으로 사용할 수 있습니다. 이는 더 빠른 데이터 액세스를 허용하여 모델 성능을 향상시킬 수 있습니다. 그러나 모든 시스템에서 올바르게 작동하지 않을 수 있으며 상당한 양의 디스크 공간을 소비할 수 있습니다.", - "Enable Message Queue": "", + "Enable Message Queue": "메시지 큐 활성화", "Enable Message Rating": "메시지 평가 활성화", "Enable Mirostat sampling for controlling perplexity.": "퍼플렉서티 제어를 위해 Mirostat 샘플링 활성화", "Enable New Sign Ups": "새 회원가입 활성화", - "Enable, disable, or customize the reasoning tags used by the model. \"Enabled\" uses default tags, \"Disabled\" turns off reasoning tags, and \"Custom\" lets you specify your own start and end tags.": "", + "Enable, disable, or customize the reasoning tags used by the model. \"Enabled\" uses default tags, \"Disabled\" turns off reasoning tags, and \"Custom\" lets you specify your own start and end tags.": "모델이 사용하는 추론 태그를 활성화, 비활성화 또는 사용자 지정할 수 있습니다. \"활성화됨\"은 기본 태그를 사용하고, \"비활성화됨\"은 추론 태그를 끄며, \"사용자 지정\"은 직접 시작 및 종료 태그를 지정할 수 있습니다.", "Enabled": "활성화됨", "End Tag": "종료 태그", "Endpoint URL": "엔드포인트 URL", "Enforce Temporary Chat": "임시 채팅 강제 적용", "Enhance": "향상", - "Enrich Hybrid Search Text": "", + "Enrich Hybrid Search Text": "하이브리드 검색 텍스트 강화", "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "CSV 파일에 이름, 이메일, 비밀번호, 역할 4개의 열이 순서대로 포함되어 있는지 확인하세요.", "Enter {{role}} message here": "여기에 {{role}} 메시지 입력", "Enter a detail about yourself for your LLMs to recall": "자신에 대한 세부사항을 입력하여 LLM들이 기억할 수 있도록 하세요.", "Enter a title for the pending user info overlay. Leave empty for default.": "대기 중인 사용자 정보 오버레이의 제목을 입력하세요. 비워두면 기본값이 사용됩니다.", "Enter a watermark for the response. Leave empty for none.": "응답에 사용할 워터마크를 입력하세요. 비워두면 워터마크가 적용되지 않습니다.", - "Enter additional headers in JSON format": "", - "Enter additional headers in JSON format (e.g. {\"X-Custom-Header\": \"value\"}": "", - "Enter additional parameters in JSON format": "", + "Enter additional headers in JSON format": "추가 헤더를 JSON 형식으로 입력하세요", + "Enter additional headers in JSON format (e.g. {\"X-Custom-Header\": \"value\"}": "추가 헤더를 JSON 형식으로 입력하세요(예: {\"X-Custom-Header\": \"value\"})", + "Enter additional parameters in JSON format": "추가 매개변수를 JSON 형식으로 입력하세요", "Enter api auth string (e.g. username:password)": "API 인증 문자 입력 (예: 사용자 이름:비밀번호)", "Enter Application DN": "애플리케이션 DN 입력", "Enter Application DN Password": "애플리케이션 DN 비밀번호 입력", @@ -716,7 +700,7 @@ "Enter Bocha Search API Key": "Bocha 검색 API 키 입력", "Enter Brave Search API Key": "Brave Search API Key 입력", "Enter certificate path": "인증서 경로 입력", - "Enter Chunk Min Size Target": "", + "Enter Chunk Min Size Target": "청크 최소 크기 목표 입력", "Enter Chunk Overlap": "청크 중첩 입력", "Enter Chunk Size": "청크 크기 입력", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "쉼표로 구분된 \\\"토큰:편향_값\\\" 쌍 입력 (예: 5432:100, 413:-100)", @@ -725,12 +709,12 @@ "Enter Datalab Marker API Base URL": "Datalab Marker API URL 입력", "Enter Datalab Marker API Key": "Datalab Marker API 키 입력", "Enter description": "설명 입력", - "Enter Docling API Key": "", + "Enter Docling API Key": "Docling API 키 입력", "Enter Docling Server URL": "Docling 서버 URL 입력", "Enter Document Intelligence Endpoint": "Document Intelligence 엔드포인트 입력", "Enter Document Intelligence Key": "Document Intelligence 키 입력", - "Enter Document Intelligence Model": "", - "Enter domains separated by commas (e.g., example.com,site.org,!excludedsite.com)": "", + "Enter Document Intelligence Model": "Document Intelligence 모델 입력", + "Enter domains separated by commas (e.g., example.com,site.org,!excludedsite.com)": "쉼표로 구분하여 도메인을 입력하세요(예: example.com,site.org,!excludedsite.com)", "Enter Exa API Key": "Exa API 키 입력", "Enter External Document Loader API Key": "외부 문서 로더 API 키 입력", "Enter External Document Loader URL": "외부 문서 로더 URL 입력", @@ -740,15 +724,15 @@ "Enter External Web Search URL": "외부 웹 검색 URL 입력", "Enter Firecrawl API Base URL": "Firecrawl API 기본 URL 입력", "Enter Firecrawl API Key": "Firecrawl API 키 입력", - "Enter Firecrawl Timeout": "", + "Enter Firecrawl Timeout": "Firecrawl 시간 초과 입력", "Enter folder name": "폴더 이름 입력", - "Enter function name filter list (e.g. func1, !func2)": "", + "Enter function name filter list (e.g. func1, !func2)": "함수 이름 필터 목록을 입력하세요(예: func1, !func2)", "Enter Github Raw URL": "Github Raw URL 입력", "Enter Google PSE API Key": "Google PSE API 키 입력", "Enter Google PSE Engine Id": "Google PSE 엔진 ID 입력", "Enter hex color (e.g. #FF0000)": "색상 hex 입력 (예: #FF0000)", "Enter Image Size (e.g. 512x512)": "이미지 크기 입력(예: 512x512)", - "Enter Jina API Base URL": "", + "Enter Jina API Base URL": "Jina API 기본 URL 입력", "Enter Jina API Key": "Jina API 키 입력", "Enter JSON config (e.g., {\"disable_links\": true})": "JSON 설정 입력 (예: {\"disable_links\": true})", "Enter Jupyter Password": "Jupyter 비밀번호 입력", @@ -757,7 +741,7 @@ "Enter Kagi Search API Key": "Kagi Search API 키 입력", "Enter Key Behavior": "키 동작 입력", "Enter language codes": "언어 코드 입력", - "Enter MinerU API Key": "", + "Enter MinerU API Key": "MinerU API 키 입력", "Enter Mistral API Base URL": "Mistral API Base URL 입력", "Enter Mistral API Key": "Mistral API 키 입력", "Enter Model ID": "모델 ID 입력", @@ -768,17 +752,17 @@ "Enter Number of Steps (e.g. 50)": "단계 수 입력(예: 50)", "Enter Ollama Cloud API Key": "Ollama 클라우드 API 키 입력", "Enter Perplexity API Key": "Perplexity API 키 입력", - "Enter Perplexity Search API URL": "", + "Enter Perplexity Search API URL": "Perplexity 검색 API URL 입력", "Enter Playwright Timeout": "Playwright 시간 초과 입력", "Enter Playwright WebSocket URL": "Playwright WebSocket URL 입력", - "Enter prompt here.": "", + "Enter prompt here.": "여기에 프롬프트를 입력하세요.", "Enter proxy URL (e.g. https://user:password@host:port)": "프록시 URL 입력(예: https://user:password@host:port)", "Enter reasoning effort": "추론 난이도", "Enter Score": "점수 입력", "Enter SearchApi API Key": "SearchApi API 키 입력", "Enter SearchApi Engine": "SearchApi 엔진 입력", "Enter Searxng Query URL": "Searxng 쿼리 URL 입력", - "Enter Searxng search language": "", + "Enter Searxng search language": "Searxng 검색 언어 입력", "Enter Seed": "Seed 입력", "Enter SerpApi API Key": "SerpApi API 키 입력", "Enter SerpApi Engine": "SerpApi 엔진 입력", @@ -788,7 +772,7 @@ "Enter server host": "서버 호스트 입력", "Enter server label": "서버 레이블 입력", "Enter server port": "서버 포트 입력", - "Enter skill instructions in markdown...": "", + "Enter skill instructions in markdown...": "마크다운 형식으로 스킬 지침을 입력하세요...", "Enter Sougou Search API sID": "Sougou 검색 API sID 입력", "Enter Sougou Search API SK": "Sougou 검색 API SK 입력", "Enter stop sequence": "중지 시퀀스 입력", @@ -796,7 +780,7 @@ "Enter system prompt here": "여기에 시스템 프롬프트 입력", "Enter Tavily API Key": "Tavily API 키 입력", "Enter Tavily Extract Depth": "Tavily 추출 깊이 입력", - "Enter the prompt instructions for this automation...": "", + "Enter the prompt instructions for this automation...": "이 자동화의 프롬프트 지침을 입력하세요...", "Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "WebUI의 공개 URL을 입력해 주세요. 이 URL은 알림에서 링크를 생성하는 데 사용합니다.", "Enter the URL of the function to import": "가져올 함수의 URL 입력", "Enter the URL to import": "가져올 URL 입력", @@ -812,9 +796,9 @@ "Enter Yacy Password": "Yacy 비밀번호 입력", "Enter Yacy URL (e.g. http://yacy.example.com:8090)": "Yacy URL 입력(예: http://yacy.example.com:8090)", "Enter Yacy Username": "Yacy 사용자 이름 입력", - "Enter Yandex Web Search API Key": "", - "Enter Yandex Web Search URL": "", - "Enter You.com API Key": "", + "Enter Yandex Web Search API Key": "Yandex 웹 검색 API 키 입력", + "Enter Yandex Web Search URL": "Yandex 웹 검색 URL 입력", + "Enter You.com API Key": "You.com API 키 입력", "Enter your code here...": "여기에 코드를 입력하세요...", "Enter your current password": "현재 비밀번호를 입력해 주세요", "Enter Your Email": "이메일 입력", @@ -828,25 +812,21 @@ "Enter Your Role": "역할 입력", "Enter Your Username": "사용자 이름 입력", "Enter your webhook URL": "웹훅 URL을 입력해 주세요", - "Entra ID": "", - "Environment Variables": "", - "Ephemeral": "", + "Entra ID": "Entra ID", + "Environment Variables": "환경 변수", + "Ephemeral": "임시", "Error": "오류", "ERROR": "오류", "Error accessing directory": "디렉토리 액세스 오류", "Error accessing Google Drive: {{error}}": "Google Drive 액세스 오류: {{error}}", "Error accessing media devices.": "미디어 장치 액세스 오류", - "Error deleting model: {{error}}": "", + "Error deleting model: {{error}}": "모델 삭제 중 오류: {{error}}", "Error starting recording.": "녹화 시작 오류", "Error unloading model: {{error}}": "모델 언로드 오류: {{error}}", "Error uploading file: {{error}}": "파일 업로드 오류: {{error}}", - "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", - "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", + "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "오류: ID가 '{{modelId}}'인 모델이 이미 존재합니다. 계속하려면 다른 ID를 선택하세요.", + "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "오류: 모델 ID는 비워둘 수 없습니다. 계속하려면 유효한 ID를 입력하세요.", "Evaluations": "평가", - "Event created": "", - "Event deleted": "", - "Event title": "", - "Event updated": "", "Exa API Key": "Exa API 키", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "예: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "예: 전체", @@ -855,24 +835,24 @@ "Example: sAMAccountName or uid or userPrincipalName": "예: sAMAccountName or uid or userPrincipalName", "Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "라이선스의 좌석 수를 초과했습니다. 좌석 수를 늘리려면 지원팀에 문의해 주세요.", "Exclude": "미포함", - "Execute code": "", + "Execute code": "코드 실행", "Execute code for analysis": "분석을 위한 코드 실행", "Executing **{{NAME}}**...": "**{{NAME}}** 실행 중...", - "Execution Logs": "", + "Execution Logs": "실행 로그", "Expand": "확장", "Experimental": "실험적", "Explain": "설명", "Explore the cosmos": "우주 탐험", - "Explored": "", - "Exploring": "", + "Explored": "탐색 완료", + "Exploring": "탐색 중", "Export": "내보내기", "Export All Archived Chats": "모든 보관된 채팅 내보내기", "Export All Chats (All Users)": "모든 채팅 내보내기(모든 사용자)", - "Export as CSV": "", - "Export as JSON": "", + "Export as CSV": "CSV로 내보내기", + "Export as JSON": "JSON으로 내보내기", "Export chat (.json)": "채팅 내보내기 (.json)", "Export Chats": "채팅 내보내기", - "Export Config": "", + "Export Config": "설정 내보내기", "Export Models": "모델 내보내기", "Export Prompts": "프롬프트 내보내기", "Export to CSV": "CSV로 내보내기", @@ -888,29 +868,28 @@ "Fade Effect for Streaming Text": "스트리밍 텍스트에 대한 페이드 효과", "Failed to add file.": "파일추가에 실패했습니다", "Failed to add members": "멤버 추가에 실패했습니다", - "Failed to archive chat.": "", - "Failed to attach file": "", + "Failed to archive chat.": "채팅 보관에 실패했습니다.", + "Failed to attach file": "파일 첨부에 실패했습니다", "Failed to clear status": "상태 초기화에 실패했습니다", "Failed to connect to {{URL}} OpenAPI tool server": "{{URL}} OpenAPI 도구 서버 연결 실패", - "Failed to connect to {{URL}} terminal server": "", + "Failed to connect to {{URL}} terminal server": "{{URL}} 터미널 서버 연결에 실패했습니다", "Failed to copy link": "링크 복사 실패", "Failed to create API Key.": "API 키 생성에 실패했습니다.", - "Failed to delete calendar": "", "Failed to delete note": "노트 삭제 실패", - "Failed to download image": "", + "Failed to download image": "이미지 다운로드에 실패했습니다", "Failed to extract content from the file: {{error}}": "파일 내용 추출 실패: {{error}}", "Failed to extract content from the file.": "파일 내용 추출 실패.", "Failed to fetch models": "모델 조회 실패", "Failed to generate title": "제목 생성 실패", "Failed to import models": "모델 가져오기 실패", "Failed to load chat preview": "채팅 미리보기 로드 실패", - "Failed to load DOCX file. Please try downloading it instead.": "", - "Failed to load Excel/CSV file. Please try downloading it instead.": "", + "Failed to load DOCX file. Please try downloading it instead.": "DOCX 파일을 불러오지 못했습니다. 대신 다운로드해 보세요.", + "Failed to load Excel/CSV file. Please try downloading it instead.": "Excel/CSV 파일을 불러오지 못했습니다. 대신 다운로드해 보세요.", "Failed to load file content.": "파일 내용 로드 실패.", - "Failed to load Interface settings": "", - "Failed to load PPTX file. Please try downloading it instead.": "", + "Failed to load Interface settings": "인터페이스 설정을 불러오지 못했습니다", + "Failed to load PPTX file. Please try downloading it instead.": "PPTX 파일을 불러오지 못했습니다. 대신 다운로드해 보세요.", "Failed to move chat": "채팅 이동 실패", - "Failed to process URL: {{url}}": "", + "Failed to process URL: {{url}}": "URL 처리에 실패했습니다: {{url}}", "Failed to read clipboard contents": "클립보드 내용 가져오기를 실패하였습니다", "Failed to remove member": "멤버 삭제에 실패했습니다", "Failed to render diagram": "다이어그램을 표시할 수 없습니다", @@ -918,40 +897,40 @@ "Failed to save connections": "연결 저장 실패", "Failed to save conversation": "대화 저장 실패", "Failed to save models configuration": "모델 구성 저장 실패", - "Failed to save policy: {{error}}": "", - "Failed to save terminal servers": "", - "Failed to unshare chat.": "", + "Failed to save policy: {{error}}": "정책 저장에 실패했습니다: {{error}}", + "Failed to save terminal servers": "터미널 서버 저장에 실패했습니다", + "Failed to unshare chat.": "채팅 공유 해제에 실패했습니다.", "Failed to update settings": "설정 업데이트에 실패하였습니다", "Failed to update status": "상태 업데이트에 실패하였습니다", "Failed to upload file.": "파일 업로드에 실패했습니다.", "Features": "기능", "Features Permissions": "기능 권한", "February": "2월", - "Feedback": "", - "Feedback Activity": "", - "Feedback deleted successfully": "", + "Feedback": "피드백", + "Feedback Activity": "피드백 활동", + "Feedback deleted successfully": "피드백이 성공적으로 삭제되었습니다", "Feedback Details": "피드백 상세내용", "Feedback History": "피드백 기록", "Feel free to add specific details": "자세한 내용을 자유롭게 추가하세요.", "Female": "여성", - "Fetch URL Content Length Limit": "", + "Fetch URL Content Length Limit": "URL 콘텐츠 길이 제한 가져오기", "File": "파일", "File added successfully.": "파일이 성공적으로 추가되었습니다", - "File attached to chat": "", - "File browser": "", - "File content": "", + "File attached to chat": "파일이 채팅에 첨부되었습니다", + "File browser": "파일 브라우저", + "File content": "파일 내용", "File content updated successfully.": "내용이 성공적으로 업데이트되었습니다", - "File Context": "", - "File deleted successfully.": "", + "File Context": "파일 컨텍스트", + "File deleted successfully.": "파일이 성공적으로 삭제되었습니다.", "File Mode": "파일 모드", - "File name": "", + "File name": "파일 이름", "File not found.": "파일을 찾을 수 없습니다.", "File removed successfully.": "파일이 성공적으로 삭제되었습니다", "File size should not exceed {{maxSize}} MB.": "파일 사이즈가 {{maxSize}} MB를 초과하면 안됩니다.", "File Upload": "파일 업로드", "File uploaded successfully": "파일이 성공적으로 업로드되었습니다", "File uploaded!": "파일이 업로드되었습니다!", - "Filename": "", + "Filename": "파일명", "Files": "파일", "Filter": "필터", "Filter is now globally disabled": "전반적으로 필터 비활성화됨", @@ -960,28 +939,28 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingerprint spoofing 감지: 이니셜을 아바타로 사용할 수 없습니다. 기본 프로필 이미지로 설정합니다.", "Firecrawl API Base URL": "Firecrawl API 기본 URL", "Firecrawl API Key": "Firecrawl API 키", - "Firecrawl Timeout (s)": "", - "Floating Quick Actions": "", + "Firecrawl Timeout (s)": "Firecrawl 시간 초과(초)", + "Floating Quick Actions": "플로팅 퀵 액션", "Focus Chat Input": "채팅 입력창에 포커스", "Folder": "폴더", "Folder Background Image": "폴더 배경 이미지", - "Folder created successfully": "", + "Folder created successfully": "폴더가 성공적으로 생성되었습니다", "Folder deleted successfully": "성공적으로 폴더가 삭제되었습니다", - "Folder Max File Count": "", - "Folder name": "", + "Folder Max File Count": "폴더 최대 파일 수", + "Folder name": "폴더 이름", "Folder Name": "폴더 이름", "Folder name cannot be empty.": "폴더 이름을 작성해주세요", "Folder name updated successfully": "성공적으로 폴더 이름이 저장되었습니다", - "Folder options": "", + "Folder options": "폴더 옵션", "Folder updated successfully": "폴더가 성공적으로 업데이트되었습니다", "Folders": "폴더", "Follow up": "후속 질문", "Follow Up Generation": "후속 질문 생성", "Follow Up Generation Prompt": "후속 질문 생성 프롬프트", - "Follow up: {{question}}": "", + "Follow up: {{question}}": "후속 질문: {{question}}", "Follow-Up Auto-Generation": "후속 질문 자동 생성", "Followed instructions perfectly": "지시를 완벽히 수행함", - "for placeholders": "", + "for placeholders": "플레이스홀더용", "Force OCR": "OCR 강제 적용", "Force OCR on all pages of the PDF. This can lead to worse results if you have good text in your PDFs. Defaults to False.": "PDF의 모든 페이지에 대해 OCR을 강제로 적용합니다. PDF에 좋은 텍스트가 포함된 경우 결과가 더 나빠질 수 있습니다. 기본값은 False입니다.", "Forge new paths": "새로운 경로 만들기", @@ -989,10 +968,10 @@ "Format Lines": "줄 서식", "Format the lines in the output. Defaults to False. If set to True, the lines will be formatted to detect inline math and styles.": "출력되는 줄에 서식을 적용합니다. 기본값은 False입니다. 이 옵션을 True로 하면, 인라인 수식 및 스타일을 감지하도록 줄에 서식이 적용됩니다.", "Formatting may be inconsistent from source.": "출처에서의 서식이 일관되지 않을 수 있습니다.", - "Forward": "", + "Forward": "전달", "Forwards system user OAuth access token to authenticate": "인증을 위해 시스템 사용자 OAuth 액세스 토큰을 전달합니다.", "Forwards system user session credentials to authenticate": "인증을 위해 시스템 사용자 세션 자격 증명 전달", - "Fr_day_of_week": "", + "Fr_day_of_week": "Fr_day_of_week", "Full Context Mode": "전체 컨텍스트 모드", "Function": "함수", "Function Calling": "함수 호출", @@ -1004,82 +983,82 @@ "Function is now globally disabled": "전반적으로 함수 비활성화됨", "Function is now globally enabled": "전반적으로 함수 활성화됨", "Function Name": "함수 이름", - "Function Name Filter List": "", + "Function Name Filter List": "함수 이름 필터 목록", "Function updated successfully": "성공적으로 함수가 업데이트되었습니다", "Functions": "함수", "Functions allow arbitrary code execution.": "함수가 임의의 코드를 실행하도록 허용하였습니다", "Functions imported successfully": "성공적으로 함수를 가져왔습니다", - "Gemini": "", - "Gemini API Key": "", + "Gemini": "Gemini", + "Gemini API Key": "Gemini API 키", "Gemini API Key is required.": "Gemini API 키가 필요합니다.", - "Gemini Base URL": "", - "Gemini Endpoint Method": "", + "Gemini Base URL": "Gemini 기본 URL", + "Gemini Endpoint Method": "Gemini 엔드포인트 방식", "Gender": "성별", "General": "일반", "Generate": "생성", "Generate an image": "이미지 생성", - "Generate and edit images": "", - "Generate Message Pair": "", + "Generate and edit images": "이미지 생성 및 편집", + "Generate Message Pair": "메시지 쌍 생성", "Generated Image": "생성된 이미지", - "Generated images will appear here": "", + "Generated images will appear here": "생성된 이미지가 여기에 표시됩니다", "Generating search query": "검색 쿼리 생성", "Generating...": "생성 중...", - "Get current time and perform date/time calculations": "", + "Get current time and perform date/time calculations": "현재 시간을 가져오고 날짜/시간 계산을 수행합니다", "Get information on {{name}} in the UI": "UI에서 {{name}} 정보 확인", "Get started": "시작하기", "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}} 시작하기", "Global": "글로벌", "Good Response": "좋은 응답", - "Google": "", + "Google": "Google", "Google Drive": "구글 드라이브", "Google PSE API Key": "Google PSE API 키", "Google PSE Engine Id": "Google PSE 엔진 ID", - "Gravatar": "", - "Grid": "", - "Grokipedia": "", - "Group Channel": "", + "Gravatar": "Gravatar", + "Grid": "그리드", + "Grokipedia": "Grokipedia", + "Group Channel": "그룹 채널", "Group created successfully": "성공적으로 그룹을 생성했습니다", "Group deleted successfully": "성공적으로 그룹을 삭제했습니다", "Group Description": "그룹 설명", "Group Name": "그룹 명", "Group updated successfully": "성공적으로 그룹을 수정했습니다", - "groups": "", + "groups": "그룹들", "Groups": "그룹", "H1": "제목 1", "H2": "제목 2", "H3": "제목 3", "Haptic Feedback": "햅틱 피드백", - "Headers": "", - "Headers must be a valid JSON object": "", - "Height": "", + "Headers": "헤더", + "Headers must be a valid JSON object": "헤더는 유효한 JSON 객체여야 합니다", + "Height": "높이", "Hello, {{name}}": "안녕하세요, {{name}}", "Help": "도움말", - "Help the community discover great models": "", + "Help the community discover great models": "커뮤니티가 훌륭한 모델을 발견하도록 도와주세요", "Hex Color": "Hex 색상", "Hex Color - Leave empty for default color": "Hex 색상 - 기본 색상의 경우 빈 상태로 유지", - "Hidden": "", + "Hidden": "숨겨짐", "Hide": "숨기기", - "Hide All": "", + "Hide All": "모두 숨기기", "Hide from Sidebar": "사이드바에서 숨기기", "Hide Model": "모델 숨기기", - "High": "", + "High": "높은", "High Contrast Mode": "고대비 모드", - "History": "", + "History": "기록", "Home": "홈", "Host": "호스트", - "Hourly": "", - "Hourly Messages": "", + "Hourly": "시간별", + "Hourly Messages": "시간별 메시지", "How can I help you today?": "무엇을 도와드릴까요?", "How would you rate this response?": "이 응답을 어떻게 평가하시겠어요?", - "HTML": "", - "http://localhost:8000": "", - "https://mineru.net/api/v4": "", + "HTML": "HTML", + "http://localhost:8000": "http://localhost:8000", + "https://mineru.net/api/v4": "https://mineru.net/api/v4", "Hybrid Search": "하이브리드 검색", "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.": "저는 제 행동의 의미를 읽고 이해했음을 인정합니다. 임의 코드 실행과 관련된 위험을 인지하고 있으며 출처의 신뢰성을 확인했습니다.", "ID": "ID", - "ID cannot contain \":\" or \"|\" characters": "", - "ID copied to clipboard": "", - "Idle Timeout": "", + "ID cannot contain \":\" or \"|\" characters": "ID는 \":\" 또는 \"|\" 문자를 포함할 수 없습니다", + "ID copied to clipboard": "ID가 클립보드에 복사되었습닙다", + "Idle Timeout": "Idle 시간 초과", "iframe Sandbox Allow Forms": "iframe 샌드박스 허용 양식", "iframe Sandbox Allow Same Origin": "iframe 샌드박스에서 동일한 오리진 허용", "Ignite curiosity": "호기심 자극", @@ -1087,8 +1066,8 @@ "Image Compression": "이미지 압축", "Image Compression Height": "이미지 압축 높이", "Image Compression Width": "이미지 압축 너비", - "Image Edit": "", - "Image Edit Engine": "", + "Image Edit": "이미지 편집", + "Image Edit Engine": "이미지 편집 엔진", "Image Generation": "이미지 생성", "Image Generation Engine": "이미지 생성 엔진", "Image Max Compression Size": "이미지 최대 압축 크기", @@ -1097,29 +1076,29 @@ "Image Prompt Generation": "이미지 프롬프트 생성", "Image Prompt Generation Prompt": "이미지 프롬프트를 생성하기 위한 프롬프트", "Image Size": "이미지 크기", - "Images": "", + "Images": "이미지들", "Import": "가져오기", "Import Chats": "채팅 가져오기", - "Import Config": "", + "Import Config": "구성 가져오기", "Import From Link": "링크에서 가져오기", - "Import Models": "", - "Import Prompts": "", - "Import successful": "", - "Import Tools": "", + "Import Models": "모델 가져오기", + "Import Prompts": "프롬프트 가져오기", + "Import successful": "가져오기 성공", + "Import Tools": "도구 가져오기", "Important Update": "중요 업데이트", - "Inactive": "", + "Inactive": "비활성화", "Include": "포함", "Include `--api-auth` flag when running stable-diffusion-webui": "stable-diffusion-webui를 실행 시 `--api-auth` 플래그를 포함하세요", "Include `--api` flag when running stable-diffusion-webui": "stable-diffusion-webui를 실행 시 `--api` 플래그를 포함하세요", "Includes SharePoint": "SharePoint 포함", - "Increase UI Scale": "", + "Increase UI Scale": "UI 크기 증가", "Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive.": "생성된 텍스트의 피드백에 알고리즘이 얼마나 빨리 반응하는지에 영향을 미칩니다. 학습률이 낮을수록 조정 속도가 느려지고 학습률이 높아지면 알고리즘의 반응 속도가 빨라집니다.", "Info": "정보", - "Initials": "", - "Inject file content into conversation context": "", + "Initials": "초기", + "Inject file content into conversation context": "파일 콘텐츠를 대화 컨텍스트에 삽입", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "전체 콘텐츠를 포괄적인 처리를 위해 컨텍스트로 삽입하세요. 이는 복잡한 쿼리에 권장됩니다.", "Input": "입력", - "Input Key (e.g. text, unet_name, steps)": "", + "Input Key (e.g. text, unet_name, steps)": "입력 키 (예: text, unet_name, steps)", "Input Variables": "변수 입력", "Insert": "삽입", "Insert Follow-Up Prompt to Input": "후속 질문을 메시지 입력란에 삽입(자동 전송 없이)", @@ -1127,29 +1106,29 @@ "Insert Suggestion Prompt to Input": "입력할 제안 프롬프트 삽입", "Install from Github URL": "Github URL에서 설치", "Instant Auto-Send After Voice Transcription": "음성 변환 후 즉시 자동 전송", - "Instructions": "", + "Instructions": "지침", "Integration": "통합", "Integrations": "통합", "Interface": "인터페이스", - "Interface Settings Access": "", + "Interface Settings Access": "인터페이스 설정 접근", "Invalid file content": "잘못된 파일 내용", "Invalid file format.": "잘못된 파일 형식", "Invalid JSON file": "잘못된 JSON 파일", - "Invalid JSON format for ComfyUI Edit Workflow.": "", - "Invalid JSON format for ComfyUI Workflow.": "", - "Invalid JSON format for Parameters": "", - "Invalid JSON format in {{NAME}}": "", + "Invalid JSON format for ComfyUI Edit Workflow.": "잘못된 ComfyUI 편집 워크플로우 JSON 형식입니다.", + "Invalid JSON format for ComfyUI Workflow.": "잘못된 ComfyUI 워크플로우 JSON 형식입니다.", + "Invalid JSON format for Parameters": "잘못된 파라미터 JSON 형식입니다.", + "Invalid JSON format in {{NAME}}": "잘못된 JSON 형식 in {{NAME}}", "Invalid JSON format in Additional Config": "추가 설정에 잘못된 JSON 형식 입력", - "Invalid JSON format in MinerU Parameters": "", + "Invalid JSON format in MinerU Parameters": "MinerU 파라미터에 잘못된 JSON 형식 입력", "is typing...": "입력 중...", "Italic": "기울임", "January": "1월", - "Jina API Base URL": "", + "Jina API Base URL": "Jina API 기본 URL", "Jina API Key": "Jina API 키", "join our Discord for help.": "도움말을 보려면 Discord에 가입하세요.", "JSON": "JSON", "JSON Preview": "JSON 미리 보기", - "JSON Spec": "", + "JSON Spec": "JSON 스펙", "July": "7월", "June": "6월", "Jupyter Auth": "Jupyter 인증", @@ -1162,85 +1141,83 @@ "Key": "키", "Key is required": "키가 필요합니다", "Keyboard shortcuts": "키보드 단축키", - "Keyboard Shortcuts": "", + "Keyboard Shortcuts": "키보드 단축키", "Knowledge": "지식 기반", "Knowledge Access": "지식 기반 접근", "Knowledge Base": "지식 기반", "Knowledge created successfully.": "성공적으로 지식 기반이 생성되었습니다", "Knowledge deleted successfully.": "성공적으로 지식 기반이 삭제되었습니다", "Knowledge Description": "지식 기반 설명", - "Knowledge exported successfully": "", + "Knowledge exported successfully": "성공적으로 지식 기반이 내보내졌습니다", "Knowledge Name": "지식 기반 이름", "Knowledge Public Sharing": "지식 기반 공개 공유", "Knowledge reset successfully.": "성공적으로 지식 기반이 초기화되었습니다", - "Knowledge Sharing": "", + "Knowledge Sharing": "지식 기반 공유", "Knowledge updated successfully": "성공적으로 지식 기반이 업데이트되었습니다", "Kokoro.js (Browser)": "Kokoro.js (브라우저)", - "Kokoro.js Dtype": "", + "Kokoro.js Dtype": "Kokoro.js 데이터 유형", "Label": "라벨", "Landing Page Mode": "랜딩페이지 모드", "Language": "언어", "Language Locales": "언어 로케일", - "Last 24 hours": "", - "Last 30 days": "", - "Last 7 days": "", - "Last 90 days": "", + "Last 24 hours": "최근 24시간", + "Last 30 days": "최근 30일", + "Last 7 days": "최근 7일", + "Last 90 days": "최근 90일", "Last Active": "최근 활동", "Last Modified": "마지막 수정", - "Last ran": "", + "Last ran": "마지막 실행", "Last reply": "마지막 답글", - "LDAP": "", + "LDAP": "LDAP", "LDAP server updated": "LDAP 서버가 업데이트되었습니다", "Leaderboard": "리더보드", - "Learn more": "", + "Learn more": "자세히 알아보기", "Learn More": "자세히 알아보기", - "Learn more about Open Terminal": "", + "Learn more about Open Terminal": "Open Terminal에 대해 자세히 알아보기", "Learn more about OpenAPI tool servers.": "OpenAPI 도구 서버에 대해 자세히 알아보세요.", - "Learn more about Voxtral transcription.": "", - "Leave a public review for {{modelName}}": "", + "Learn more about Voxtral transcription.": "Voxtral 변환에 대해 자세히 알아보세요.", + "Leave a public review for {{modelName}}": "{{modelName}}에 대한 공개 리뷰 남기기", "Leave empty for no compression": "압축하지 않으려면 비워 두세요", "Leave empty for unlimited": "제한하지 않으려면 비워 두세요", "Leave empty to include all models from \"{{url}}\" endpoint": "\"{{url}}\" 엔드포인트의 모든 모델을 포함하려면 비워 두세요", "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "\"{{url}}/api/tags\" 엔드포인트의 모든 모델을 포함하려면 비워 두세요", "Leave empty to include all models from \"{{url}}/models\" endpoint": "\"{{url}}/models\" 엔드포인트의 모든 모델을 포함하려면 비워 두세요", "Leave empty to include all models or select specific models": "비워두면 모든 모델이 포함되며, 특정 모델을 선택할 수도 있습니다.", - "Leave empty to use first admin user": "", - "Leave empty to use the default config, or enter a valid json (see https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest)": "", + "Leave empty to use first admin user": "첫 번째 관리자 사용자로 사용하려면 비워 두세요", + "Leave empty to use the default config, or enter a valid json (see https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest)": "기본 구성을 사용하려면 비워 두세요, 또는 유효한 json을 입력하세요 (https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest 참조)", "Leave empty to use the default model (voxtral-mini-latest).": "비워두면 기본 모델(voxtral-mini-latest)을 사용합니다.", "Leave empty to use the default prompt, or enter a custom prompt": "기본 프롬프트를 사용하기 위해 빈칸으로 남겨두거나, 커스텀 프롬프트를 입력하세요", "Leave model field empty to use the default model.": "기본 모델을 사용하려면 모델 필드를 비워 두세요.", - "Legacy": "", + "Legacy": "레거시", "lexical": "어휘적", "License": "라이선스", "Lift List": "리스트 올리기", "Light": "라이트", - "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", - "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", - "List": "", - "List calendars, search, create, update, and delete calendar events": "", + "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "동시 검색 쿼리 수를 제한합니다. 0은 무제한(기본값)입니다. 순차 실행하려면 1로 설정하세요(Brave 무료 요금제처럼 엄격한 속도 제한이 있는 API에 권장됩니다).", + "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "동시 임베딩 요청 수를 제한합니다. 무제한은 0으로 설정하세요.", + "List": "목록", "Listening...": "듣는 중...", - "Live": "", + "Live": "실시간", "Llama.cpp": "Llama.cpp", "LLMs can make mistakes. Verify important information.": "LLM에 오류가 있을 수 있습니다. 중요한 정보는 확인이 필요합니다.", "Loader": "로더", "Loading Kokoro.js...": "Kokoro.js 로딩 중...", "Loading...": "로딩 중...", - "local": "", + "local": "로컬", "Local": "로컬", "Local Task Model": "로컬 작업 모델", - "Location": "", "Location access not allowed": "위치 접근이 허용되지 않습니다", "Lost": "패배", - "Low": "", + "Low": "낮음", "LTR": "LTR", "Made by Open WebUI Community": "OpenWebUI 커뮤니티에 의해 개발됨", "Make password visible in the user interface": "비밀번호 보이기", "Make sure to export a workflow.json file as API format from ComfyUI.": "꼭 workflow.json 파일을 ComfyUI의 API 형식대로 내보내세요", "Male": "남성", "Manage": "관리", - "Manage Connections": "", + "Manage Connections": "연결 관리", "Manage Direct Connections": "다이렉트 연결 관리", - "Manage Files": "", + "Manage Files": "파일 관리", "Manage Models": "모델 관리", "Manage Ollama": "Ollama 관리", "Manage Ollama API Connections": "Ollama API 연결 관리", @@ -1250,24 +1227,24 @@ "Manage your account information.": "계정 정보를 관리하세요.", "March": "3월", "Markdown": "마크다운", - "Markdown Header Text Splitter": "", + "Markdown Header Text Splitter": "마크다운 헤더 텍스트 분할기", "Max Speakers": "최대 화자 수", "Max Upload Count": "업로드 최대 수", "Max Upload Size": "업로드 최대 사이즈", - "Maximum characters to return from fetched URLs. Leave empty for no limit.": "", - "Maximum number of files allowed per folder.": "", - "Maximum number of files per folder is {{max}}.": "", + "Maximum characters to return from fetched URLs. Leave empty for no limit.": "가져온 URL에서 반환할 최대 문자 수입니다. 제한이 없으면 비워 두세요.", + "Maximum number of files allowed per folder.": "폴더당 허용되는 최대 파일 수입니다.", + "Maximum number of files per folder is {{max}}.": "폴더당 파일 수의 최대값은 {{max}}입니다.", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "최대 3개의 모델을 동시에 다운로드할 수 있습니다. 나중에 다시 시도하세요.", "May": "5월", - "MBR": "", - "MCP": "", + "MBR": "MBR", + "MCP": "MCP", "MCP support is experimental and its specification changes often, which can lead to incompatibilities. OpenAPI specification support is directly maintained by the Open WebUI team, making it the more reliable option for compatibility.": "MCP 지원은 실험적이며 명세가 자주 변경되므로, 호환성 문제가 발생할 수 있습니다. Open WebUI 팀이 OpenAPI 명세 지원을 직접 유지·관리하고 있어, 호환성 측면에서는 더 신뢰할 수 있는 선택입니다.", - "Medium": "", + "Medium": "중간", "Member removed successfully": "멤버 삭제에 성공했습니다", - "members": "", + "members": "멤버들", "Members": "멤버", "Members added successfully": "멤버 추가에 성공했습니다", - "Memories": "", + "Memories": "메모리", "Memories accessible by LLMs will be shown here.": "LLM에서 접근할 수 있는 메모리는 여기에 표시됩니다.", "Memory": "메모리", "Memory added successfully": "성공적으로 메모리가 추가되었습니다", @@ -1277,38 +1254,38 @@ "Merge Responses": "응답들 결합하기", "Merged Response": "결합된 응답", "Message": "메시지", - "Message counts and response timestamps": "", - "Message counts are based on assistant responses.": "", + "Message counts and response timestamps": "메시지 수와 응답 타임스탬프", + "Message counts are based on assistant responses.": "메시지 수는 어시스턴트 응답을 기준으로 계산됩니다.", "Message rating should be enabled to use this feature": "이 기능을 사용하려면 메시지 평가가 활성화되어야합니다", - "messages": "", - "Messages": "", + "messages": "메시지들", + "Messages": "메시지", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "링크 생성 후에 보낸 메시지는 공유되지 않습니다. URL이 있는 사용자는 공유된 채팅을 볼 수 있습니다.", - "Microsoft OneDrive": "", + "Microsoft OneDrive": "Microsoft OneDrive", "Microsoft OneDrive (personal)": "Microsoft OneDrive (개인용)", "Microsoft OneDrive (work/school)": "Microsoft OneDrive (회사/학교용)", - "min": "", - "MinerU": "", + "min": "분", + "MinerU": "MinerU", "MinerU API Key required for Cloud API mode.": "클라우드 API 모드를 사용하려면 MinerU API 키가 필요합니다.", - "Mistral OCR": "", + "Mistral OCR": "Mistral OCR", "Mistral OCR API Key required.": "Mistral OCR API Key가 필요합니다.", - "MistralAI": "", - "Mo_day_of_week": "", + "MistralAI": "MistralAI", + "Mo_day_of_week": "Mo_day_of_week", "Model": "모델", "Model '{{modelName}}' has been successfully downloaded.": "모델 '{{modelName}}'이/가 성공적으로 다운로드되었습니다.", "Model '{{modelTag}}' is already in queue for downloading.": "모델 '{{modelTag}}'은/는 이미 다운로드 대기열에 있습니다.", - "Model {{modelId}} not found": "", - "Model {{modelName}} deleted successfully": "", + "Model {{modelId}} not found": "모델 {{modelId}}을/를 찾을 수 없습니다", + "Model {{modelName}} deleted successfully": "모델 {{modelName}}이/가 성공적으로 삭제되었습니다", "Model {{modelName}} is not vision capable": "모델 {{modelName}}은/는 비전을 사용할 수 없습니다.", "Model {{name}} is now {{status}}": "모델 {{name}}은/는 이제 {{status}} 상태입니다.", "Model {{name}} is now hidden": "모델 {{name}}은/는 이제 숨겨졌습니다.", "Model {{name}} is now visible": "모델 {{name}}은/는 이제 볼 수 있습니다.", "Model accepts file inputs": "모델에 파일 입력을 허용합니다", "Model accepts image inputs": "모델에 이미지 입력을 허용합니다", - "Model can access Open Terminal for command execution and file management": "", + "Model can access Open Terminal for command execution and file management": "모델이 명령 실행과 파일 관리를 위해 Open Terminal에 접근할 수 있습니다.", "Model can execute code and perform calculations": "모델이 코드를 실행하고 계산을 수행할 수 있습니다.", "Model can generate images based on text prompts": "모델이 텍스트 프롬프트를 기반으로 이미지를 생성할 수 있습니다.", "Model can search the web for information": "모델이 웹에서 정보를 검색할 수 있습니다.", - "Model Capabilities": "", + "Model Capabilities": "모델 성능", "Model created successfully!": "성공적으로 모델이 생성되었습니다", "Model filesystem path detected. Model shortname is required for update, cannot continue.": "모델 파일 시스템 경로가 감지되었습니다. 업데이트하려면 모델 단축 이름이 필요하며 계속할 수 없습니다.", "Model Filtering": "모델 필터링", @@ -1318,16 +1295,16 @@ "Model Name": "모델 이름", "Model name already exists, please choose a different one": "이 모델 이름은 이미 존재합니다. 다른 이름을 선택해주세요.", "Model Name is required.": "모델 이름이 필요합니다", - "Model names and usage frequency": "", - "Model not found": "", + "Model names and usage frequency": "모델 이름과 사용 빈도", + "Model not found": "모델을 찾을 수 없습니다", "Model not selected": "모델이 선택되지 않았습니다.", - "Model Parameters": "", + "Model Parameters": "모델 매개변수", "Model Params": "모델 매개변수", "Model Permissions": "모델 권한", - "Model responses or outputs": "", + "Model responses or outputs": "모델 응답 또는 출력", "Model unloaded successfully": "성공적으로 모델이 언로드되었습니다", "Model updated successfully": "성공적으로 모델이 업데이트되었습니다", - "Model Usage": "", + "Model Usage": "모델 사용량", "Model(s) do not support file upload": "모델이 파일 업로드를 지원하지 않습니다", "Modelfile Content": "모델 파일 내용", "Models": "모델", @@ -1335,50 +1312,48 @@ "Models configuration saved successfully": "모델 구성이 성공적으로 저장되었습니다", "Models imported successfully": "모델을 성공적으로 가져왔습니다.", "Models Public Sharing": "모델 공개 공유", - "Models Sharing": "", - "Mojeek": "", + "Models Sharing": "모델 공유", + "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API 키", - "Month": "", - "Monthly": "", + "Monthly": "월간", "More": "더보기", "More Concise": "더 간결하게", - "More options": "", + "More options": "추가 옵션", "More Options": "추가 설정", "Move": "이동", - "Moved {{name}}": "", - "My Terminal": "", + "Moved {{name}}": "{{name}} 이동됨", + "My Terminal": "내 터미널", "Name": "이름", - "Name and ID are required, please fill them out": "", + "Name and ID are required, please fill them out": "이름과 ID는 필수입니다. 작성해주세요", "Name your knowledge base": "지식 기반 이름을 지정하세요", - "Name, prompt, and model are required": "", + "Name, prompt, and model are required": "이름, 프롬프트, 및 모델은 필수입니다", "Native": "네이티브", - "Never": "", - "New": "", - "New Automation": "", + "Never": "절대", + "New": "새로 만들기", + "New Automation": "새로운 자동", "New Button": "새 버튼", "New Chat": "새 채팅", - "New Event": "", - "New File": "", + "New File": "새 파일", "New Folder": "새 폴더", "New Function": "새 함수", - "New Group": "", + "New Group": "새 그룹", "New Knowledge": "새 지식 기반", "New Model": "새 모델", - "New Note": "", + "New Note": "새 노트", "New Password": "새 비밀번호", "New Prompt": "새 프롬프트", - "New Skill": "", - "New Temporary Chat": "", - "New Terminal": "", + "New Skill": "새 기능", + "New Temporary Chat": "새 임시 채팅", + "New Terminal": "새 터미널", "New Tool": "새 도구", - "New Webhook": "", + "New Webhook": "새 Webhook", "new-channel": "새 채널", "Next message": "다음 메시지", - "Next run": "", - "No access grants. Private to you.": "", - "No activity data": "", - "No authentication": "", - "No automations found": "", + "Next run": "다음 실행", + "No access grants. Private to you.": "접근 권한이 없습니다. 개인용입니다.", + "No activity data": "활동 데이터가 없습니다", + "No authentication": "권한 인증이 없습니다", + "No automations found": "자동화된 항목을 찾을 수 없습니다.", "No chats found": "채팅을 찾을 수 없습니다", "No chats found for this user.": "이 사용자에 대한 채팅을 찾을 수 없습니다.", "No chats found.": "채팅을 찾을 수 없습니다.", @@ -1386,57 +1361,57 @@ "No content found": "내용을 찾을 수 없습니다", "No content to speak": "음성 출력할 내용을 찾을 수 없습니다", "No conversation to save": "저장할 대화가 없습니다", - "No data": "", - "No data found": "", + "No data": "데이터가 없습니다", + "No data found": "데이터를 찾을 수 없습니다", "No distance available": "거리 불가능", - "No execution logs available yet": "", + "No execution logs available yet": "아직 실행 로그가 없습니다", "No expiration can pose security risks.": "만료 기한이 없으면 보안 위험이 발생할 수 있습니다.", - "No feedback found": "", + "No feedback found": "피드백을 찾을 수 없습니다", "No file selected": "파일이 선택되지 않았습니다", - "No files found": "", - "No files in this knowledge base.": "", - "No files yet. Upload files or run Python code to create them.": "", + "No files found": "파일을 찾을 수 없습니다", + "No files in this knowledge base.": "이 지식 기반에 파일이 없습니다.", + "No files yet. Upload files or run Python code to create them.": "아직 파일이 없습니다. 파일을 업로드하거나 Python 코드를 실행하여 생성하세요.", "No functions found": "함수를 찾을 수 없습니다", - "No groups found": "", - "No history available": "", + "No groups found": "그룹을 찾을 수 없습니다", + "No history available": "사용 기록이 없습니다", "No HTML, CSS, or JavaScript content found.": "HTML, CSS, JavaScript이 발견되지 않았습니다", "No inference engine with management support found": "관리 지원이 포함된 추론 엔진을 찾을 수 없습니다", - "No kernel": "", - "No knowledge bases found.": "", + "No kernel": "커널이 없습니다", + "No knowledge bases found.": "지식 기반을 찾을 수 없습니다", "No knowledge found": "지식 기반을 찾을 수 없습니다", - "No limit": "", + "No limit": "제한이 없습니다", "No memories to clear": "메모리를 정리할 수 없습니다", "No model IDs": "모델 ID가 없습니다", - "No models available": "", + "No models available": "사용 가능한 모델이 없습니다", "No models found": "모델을 찾을 수 없습니다", "No models selected": "모델이 선택되지 않았습니다", "No Notes": "노트가 없습니다", "No notes found": "노트를 찾을 수 없습니다", - "No one": "", + "No one": "없음", "No pinned messages": "고정된 메시지가 없습니다", "No prompts found": "프롬프트를 찾을 수 없습니다", "No results": "결과가 없습니다", "No results found": "결과를 찾을 수 없습니다", "No search query generated": "검색어가 생성되지 않았습니다", - "No servers detected": "", - "No skills found": "", + "No servers detected": "서버가 감지되지 않았습니다", + "No skills found": "기능을 찾을 수 없습니다", "No source available": "사용 가능한 소스가 없습니다.", "No sources found": "소스를 찾을 수 없습니다", "No suggestion prompts": "추천 프롬프트가 없습니다", - "No Terminal connection configured.": "", - "No terminal connections configured.": "", - "No tool server connections configured.": "", + "No Terminal connection configured.": "터미널 연결이 구성되지 않았습니다.", + "No terminal connections configured.": "터미널 연결이 구성되지 않았습니다.", + "No tool server connections configured.": "도구 서버 연결이 구성되지 않았습니다.", "No tools found": "도구를 찾을 수 없습니다", "No users were found.": "사용자를 찾을 수 없습니다", "No valves": "밸브가 없습니다", "No valves to update": "업데이트 할 밸브가 없습니다", - "No webhooks yet": "", - "Node Ids": "Ids 가 없습니다", + "No webhooks yet": "webhook이 아직 없습니다", + "Node Ids": "노드 ID", "None": "없음", "Not factually correct": "사실상 맞지 않습니다", "Not helpful": "도움이 되지않습니다", "Not Registered": "등록되지 않았습니다", - "Not scheduled": "", + "Not scheduled": "예약되지 않았습니다", "Note": "노트", "Note deleted successfully": "노트가 성공적으로 삭제되었습니다", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "참고: 최소 점수를 설정하면, 검색 결과로 최소 점수 이상의 점수를 가진 문서만 반환합니다.", @@ -1447,9 +1422,9 @@ "Notification Webhook": "알림 웹훅", "Notifications": "알림", "November": "11월", - "OAuth": "", - "OAuth 2.1": "", - "OAuth 2.1 (Static)": "", + "OAuth": "OAuth", + "OAuth 2.1": "OAuth 2.1", + "OAuth 2.1 (Static)": "OAuth 2.1 (Static)", "OAuth ID": "OAuth ID", "October": "10월", "Off": "끄기", @@ -1458,10 +1433,10 @@ "Ollama": "Ollama", "Ollama API": "Ollama API", "Ollama API settings updated": "Ollama API 세팅이 업데이트 되었습니다.", - "Ollama Cloud API Key": "", + "Ollama Cloud API Key": "Ollama Cloud API Key", "Ollama Version": "Ollama 버전", "On": "켜기", - "Once": "", + "Once": "Once", "OneDrive": "OneDrive", "Only active when \"Paste Large Text as File\" setting is toggled on.": "\"긴 텍스트를 파일로 붙여넣기\" 설정이 켜져 있을 때만 작동합니다.", "Only active when the chat input is in focus and an LLM is generating a response.": "채팅 입력창이 선택되어 있고 LLM이 응답을 생성 중일 때만 작동합니다.", @@ -1473,65 +1448,65 @@ "Only invited users can access": "초대된 사용자만 접근할 수 있습니다.", "Only markdown files are allowed": "마크다운 파일만 허용됩니다", "Only select users and groups with permission can access": "권한이 있는 사용자와 그룹만 접근 가능합니다.", - "Only sync new/updated chats": "", + "Only sync new/updated chats": "새로운/업데이트된 채팅만 동기화", "Oops! Looks like the URL is invalid. Please double-check and try again.": "이런! URL이 잘못된 것 같습니다. 다시 한번 확인하고 다시 시도해주세요.", "Oops! There are files still uploading. Please wait for the upload to complete.": "이런! 파일이 계속 업로드중 입니다. 업로드가 완료될 때까지 잠시만 기다려주세요.", "Oops! There was an error in the previous response.": "이런! 이전 응답에 에러가 있었던 것 같습니다.", "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "이런! 지원되지 않는 방식(프론트엔드만)을 사용하고 계십니다. 백엔드에서 WebUI를 제공해주세요.", "Open file": "파일 열기", "Open in full screen": "전체화면으로 열기", - "Open in new tab": "", + "Open in new tab": "새 탭에서 열기", "Open link": "링크 열기", "Open modal to configure connection": "연결 설정 열기", - "Open Modal To Manage Floating Quick Actions": "", - "Open Modal To Manage Image Compression": "", - "Open Model Selector": "", + "Open Modal To Manage Floating Quick Actions": "플로팅 빠른 작업 관리를 위한 모달 열기", + "Open Modal To Manage Image Compression": "이미지 압축 관리를 위한 모달 열기", + "Open Model Selector": "모델 선택기 열기", "Open Settings": "설정 열기", "Open Sidebar": "사이드바 열기", - "Open Terminal": "", + "Open Terminal": "터미널 열기", "Open User Profile Menu": "사용자 프로필 메뉴 열기", "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI는 모든 OpenAPI 서버에서 제공하는 도구를 사용할 수 있습니다.", "Open WebUI uses faster-whisper internally.": "Open WebUI는 내부적으로 패스트 위스퍼를 사용합니다.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI는 SpeechT5와 CMU Arctic 스피커 임베딩을 사용합니다.", - "Open WebUI version": "", + "Open WebUI version": "Open WebUI 버전", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "열린 WebUI 버젼(v{{OPEN_WEBUI_VERSION}})은 최소 버젼 (v{{REQUIRED_VERSION}})보다 낮습니다", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", - "OpenAI API Base URL": "", + "OpenAI API Base URL": "OpenAI API 기본 URL", "OpenAI API Key": "OpenAI API 키", "OpenAI API Key is required.": "OpenAI API 키가 필요합니다.", "OpenAI API settings updated": "OpenAI API 설정이 업데이트되었습니다.", "OpenAI API Version": "OpenAI API 버전", "OpenAI URL/Key required.": "OpenAI URL/키가 필요합니다.", - "OpenAPI": "", - "OpenAPI Spec": "", + "OpenAPI": "OpenAPI", + "OpenAPI Spec": "OpenAPI 사양", "openapi.json URL or Path": "openapi.json URL 또는 경로", - "optional": "", - "Optional": "", + "optional": "선택 사항", + "Optional": "선택 사항", "or": "또는", "Ordered List": "번호 목록", "Other": "기타", - "out of": "", - "Output": "", + "out of": "의", + "Output": "출력", "OUTPUT": "출력", "Output format": "출력 형식", "Output Format": "출력 형식", "Overview": "개요", "page": "페이지", - "Page": "", - "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", + "Page": "페이지", + "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "페이지 모드는 페이지마다 하나의 문서를 생성합니다. 단일 모드는 모든 페이지를 하나의 문서로 결합하여 페이지 경계를 넘어 더 나은 청킹을 제공합니다.", "Paginate": "페이지 나누기", "Parameters": "매개변수", - "Parent message not found": "", - "Participate in community leaderboards and evaluations! Syncing aggregated usage stats helps drive research and improvements to Open WebUI. Your privacy is paramount: no message content is ever shared.": "", + "Parent message not found": "상위 메시지를 찾을 수 없습니다.", + "Participate in community leaderboards and evaluations! Syncing aggregated usage stats helps drive research and improvements to Open WebUI. Your privacy is paramount: no message content is ever shared.": "커뮤니티 리더보드와 평가에 참여하세요! 집계된 사용 통계를 동기화하면 Open WebUI의 연구과 개선을 지원합니다. 귀하의 개인정보는 최우선으로 보호됩니다: 메시지 내용은 절대 공유되지 않습니다.", "Password": "비밀번호", "Passwords do not match.": "비밀번호가 일치하지 않습니다.", "Paste Large Text as File": "큰 텍스트를 파일로 붙여넣기", - "Path copied": "", - "Paused": "", + "Path copied": "경로가 복사되었습니다.", + "Paused": "일시정지됨", "PDF document (.pdf)": "PDF 문서(.pdf)", "PDF Extract Images (OCR)": "PDF 이미지 추출(OCR)", - "PDF Loader Mode": "", + "PDF Loader Mode": "PDF 로더 모드", "pending": "보류 중", "Pending": "보류", "Pending User Overlay Content": "대기 중인 사용자 오버레이 내용", @@ -1542,20 +1517,20 @@ "Permissions": "권한", "Perplexity API Key": "Perplexity API 키", "Perplexity Model": "Perplexity 모델", - "Perplexity Search API URL": "", + "Perplexity Search API URL": "Perplexity 검색 API URL", "Perplexity Search Context Usage": "Perplexity 검색 컨텍스트 사용", - "Persistent": "", + "Persistent": "지속적", "Personalization": "개인화", "Pin": "고정", - "Pin to Sidebar": "", + "Pin to Sidebar": "사이드바에 고정", "Pinned": "고정됨", "Pinned Messages": "고정된 메시지", - "Pinned Models": "", + "Pinned Models": "고정된 모델", "Pioneer insights": "혁신적인 발견", "Pipe": "파이프", "Pipeline deleted successfully": "성공적으로 파이프라인이 삭제되었습니다.", "Pipeline downloaded successfully": "성공적으로 파이프라인이 설치되었습니다.", - "Pipelines": "", + "Pipelines": "파이프라인", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines는 임의 코드 실행이 가능한 플러그인 시스템입니다 —", "Pipelines Not Detected": "파이프라인이 발견되지 않았습니다.", "Pipelines Valves": "파이프라인 밸브", @@ -1565,7 +1540,7 @@ "Playwright Timeout (ms)": "Playwright 시간 초과 (ms)", "Playwright WebSocket URL": "Playwright WebSocket URL", "Please carefully review the following warnings:": "다음 주의를 조심히 확인해주십시오", - "Please connect all required integrations before sending a message": "", + "Please connect all required integrations before sending a message": "모든 필요한 통합을 연결한 후 메시지를 보내세요", "Please do not close the settings page while loading the model.": "모델을 로드하는 동안 설정 페이지를 닫지 마세요.", "Please enter a message or attach a file.": "메시지를 입력하거나 파일을 첨부해 주세요.", "Please enter a prompt": "프롬프트를 입력해주세요", @@ -1574,7 +1549,7 @@ "Please enter a valid path": "올바른 경로를 입력하세요", "Please enter a valid URL": "올바른 URL을 입력하세요", "Please enter a valid URL.": "올바른 URL을 입력하세요.", - "Please enter Client ID and Client Secret": "", + "Please enter Client ID and Client Secret": "Client ID와 Client Secret을 입력하세요", "Please fill in all fields.": "모두 빈칸없이 채워주세요", "Please register the OAuth client": "OAuth clith를 등록해주세요", "Please save the connection to persist the OAuth client information and do not change the ID": "OAuth 클라이언트 정보를 저장하려면 연결을 저장하고 ID를 변경하지 마세요.", @@ -1584,9 +1559,9 @@ "Please select a valid JSON file": "올바른 Json 파일을 선택해 주세요", "Please select at least one user for Direct Message channel.": "1:1 메시지 채널에 참여할 사용자를 최소 한 명 선택해주세요.", "Please wait until all files are uploaded.": "모든 파일이 업로드될 때까지 기다려 주세요.", - "Policy ID": "", + "Policy ID": "정책 ID", "Port": "포트", - "Ports": "", + "Ports": "포트", "Positive attitude": "긍정적인 자세", "Prefer not to say": "언급하고 싶지 않습니다.", "Prefix ID": "Prefix ID", @@ -1598,55 +1573,54 @@ "Previous message": "이전 메시지", "Private": "비공개", "Private conversation between selected users": "선택한 사용자 간의 비공개 대화", - "Production version updated": "", + "Production version updated": " production 버전이 업데이트되었습니다.", "Profile": "프로필", "Prompt": "프롬프트", "Prompt Autocompletion": "프롬프트 자동 완성", "Prompt Content": "프롬프트 내용", "Prompt created successfully": "성공적으로 프롬프트를 생성했습니다", - "Prompt Name": "", - "Prompt Suggestions": "", + "Prompt Name": "프롬프트 이름", + "Prompt Suggestions": "프롬프트 제안", "Prompt updated successfully": "성공적으로 프롬프트를 수정했습니다", "Prompts": "프롬프트", "Prompts Access": "프롬프트 접근", "Prompts Public Sharing": "프롬프트 공개 공유", "Prompts Sharing": "프롬프트 공유", - "Provider Type": "", + "Provider Type": "제공자 유형", "Public": "공개", "Pull \"{{searchValue}}\" from Ollama.com": "Ollama.com에서 \"{{searchValue}}\" 가져오기", "Pull a model from Ollama.com": "Ollama.com에서 모델 가져오기(pull)", "Pull Model": "모델 pull", - "Pyodide file browser": "", + "Pyodide file browser": "Pyodide 파일 브라우저", "Query Generation Prompt": "쿼리 생성 프롬프트", "Querying": "쿼리 진행중", "Quick Actions": "빠른 작업", "RAG Template": "RAG 템플릿", - "Ran {{COUNT}} analyses": "", - "Ran {{COUNT}} analysis": "", - "Rate {{rating}} out of 10": "", + "Ran {{COUNT}} analyses": "{{COUNT}}개의 분석이 실행되었습니다", + "Ran {{COUNT}} analysis": "{{COUNT}}개의 분석이 실행되었습니다", + "Rate {{rating}} out of 10": "{{rating}}/10 점 평가", "Rating": "평가", "Re-rank models by topic similarity": "주제 유사성으로 모델을 재정렬하기", "Read": "읽기", "Read Aloud": "읽어주기", "Read more →": "더 읽기 →", - "Read Only": "", - "Read-Only Access": "", + "Read Only": "읽기 전용", + "Read-Only Access": "읽기 전용 접근", "Reason": "근거", "Reasoning Effort": "추론 난이도", "Reasoning Tags": "추론 태그", - "Recently Used": "", - "Reconnected": "", + "Recently Used": "최근 사용", "Record": "녹음", "Record voice": "음성 녹음", "Redirecting you to Open WebUI Community": "OpenWebUI 커뮤니티로 리디렉션 중", "Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative.": "넌센스를 생성할 확률을 줄입니다. 값이 높을수록(예: 100) 더 다양한 답변을 제공하는 반면, 값이 낮을수록(예: 10) 더 보수적입니다.", "Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "스스로를 \"사용자\" 라고 지칭하세요. (예: \"사용자는 영어를 배우고 있습니다\")", "Reference Chats": "채팅 참조", - "Refresh": "", + "Refresh": "새로 고침", "Refused when it shouldn't have": "허용되지 않았지만 허용되어야 합니다.", "Regenerate": "재생성", "Regenerate Menu": "메뉴 재생성", - "Regenerate Response": "", + "Regenerate Response": "응답 재생성", "Register Again": "재등록", "Register Client": "클라이언트 등록", "Registered": "등록됨", @@ -1659,26 +1633,25 @@ "Relevance": "관련도", "Relevance Threshold": "관련성 임계값", "Remember Dismissal": "다시 보지 않기", - "Reminder": "", "Remove": "삭제", "Remove {{MODELID}} from list.": "{{MODELID}}를 목록에서 제거.", - "Remove action": "", + "Remove action": "작업 제거", "Remove file": "파일 삭제", "Remove File": "파일 삭제", - "Remove from favorites": "", + "Remove from favorites": "즐겨찾기에서 제거", "Remove image": "이미지 삭제", "Remove Model": "모델 삭제", "Rename": "이름 변경", - "Renamed to {{name}}": "", - "Render Markdown in Previews": "", + "Renamed to {{name}}": "{{name}}(으)로 이름 변경", + "Render Markdown in Previews": "미리보기에서 마크다운 렌더링", "Reorder Models": "모델 재정렬", - "Repeats": "", + "Repeats": "반복", "Reply": "답장", "Reply in Thread": "스레드로 답장하기", "Reply to thread...": "스레드로 답장하기...", "Replying to {{NAME}}": "{{NAME}}에게 답장하는 중", - "required": "", - "Reranking Batch Size": "", + "required": "필수", + "Reranking Batch Size": "리랭킹 배치 사이즈", "Reranking Engine": "Reranking 엔진", "Reranking Model": "Reranking 모델", "Reset": "초기화", @@ -1691,26 +1664,26 @@ "Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "웹사이트 권한이 거부되어 응답 알림을 활성화할 수 없습니다. 필요한 접근 권한을 부여하려면 브라우저 설정을 확인해 주세요.", "Response splitting": "응답 나누기", "Response Watermark": "응답 워터마크", - "Responses": "", - "Restart": "", + "Responses": "응답", + "Restart": "재시작", "Result": "결과", "RESULT": "결과", "Retrieval": "검색", "Retrieval Query Generation": "검색 쿼리 생성", - "Retrieved {{count}} sources": "", - "Retrieved {{count}} sources_other": "", + "Retrieved {{count}} sources": "{{count}}개의 소스 검색됨", + "Retrieved {{count}} sources_other": "{{count}}개의 소스 검색됨", "Retrieved 1 source": "검색된 source 1개", "Rich Text Input for Chat": "다양한 텍스트 서식 사용", "Role": "역할", "RTL": "RTL", "Run": "실행", - "Run All": "", - "Run now": "", - "Run Now": "", + "Run All": "모두 실행", + "Run now": "지금 실행", + "Run Now": "지금 실행", "Running": "실행 중", "Running...": "실행 중...", - "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "", - "Sa_day_of_week": "", + "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "임베딩 작업을 동시에 실행하여 처리 속도를 높입니다. 속도 제한이 문제가 되면 끄세요.", + "Sa_day_of_week": "Sa_day_of_week", "Save": "저장", "Save & Create": "저장 및 생성", "Save & Update": "저장 및 업데이트", @@ -1718,20 +1691,20 @@ "Save Chat": "채팅 저장", "Saved": "저장됨", "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "브라우저의 저장소에 채팅 로그를 직접 저장하는 것은 더 이상 지원되지 않습니다. 아래 버튼을 클릭하여 채팅 로그를 다운로드하고 삭제하세요. 걱정 마세요. 백엔드를 통해 채팅 로그를 쉽게 다시 가져올 수 있습니다.", - "Schedule": "", - "Scheduled time must be in the future": "", + "Schedule": "일정", + "Scheduled time must be in the future": "예약 시간은 미래여야 합니다", "Scroll On Branch Change": "브랜치 변경 시 스크롤", "Search": "검색", "Search a model": "모델 검색", "Search all emojis": "모든 이모지 검색", - "Search and manage user memories": "", - "Search and view user chat history": "", - "Search Automations": "", + "Search and manage user memories":"사용자 기억 검색 및 관리", + "Search and view user chat history":"사용자 채팅 기록 검색 및 보기", + "Search Automations": "자동 검색", "Search Base": "검색 기반", - "Search channels and channel messages": "", + "Search channels and channel messages": "채널 및 채널 메시지 검색", "Search Chats": "채팅 검색", "Search Collection": "컬렉션 검색", - "Search Files": "", + "Search Files": "파일 검색", "Search Filters": "필터 검색", "search for archived chats": "보관된 채팅 검색", "search for folders": "폴더 검색", @@ -1739,20 +1712,20 @@ "search for shared chats": "공유된 채팅 검색", "search for tags": "태그 검색", "Search Functions": "함수 검색", - "Search Groups": "", + "Search Groups": "그룹 검색", "Search In Models": "모델에서 검색", "Search Knowledge": "지식 기반 검색", - "Search Memories": "", + "Search Memories": "메모리 검색", "Search Models": "모델 검색", "Search Notes": "노트 검색", "Search options": "검색 옵션", "Search Prompts": "프롬프트 검색", "Search Result Count": "검색 결과 수", - "Search Skills": "", + "Search Skills": "스킬 검색", "Search the internet": "인터넷 검색", - "Search the web and fetch URLs": "", + "Search the web and fetch URLs": "웹에서 검색하고 URL 가져오기", "Search Tools": "검색 도구", - "Search, view, and manage user notes": "", + "Search, view, and manage user notes": "사용자 노트 검색, 보기, 및 관리", "SearchApi API Key": "SearchApi API 키", "SearchApi Engine": "SearchApi 엔진", "Searched {{count}} sites": "{{count}}개 사이트 검색됨", @@ -1761,12 +1734,12 @@ "Searching Knowledge for \"{{searchQuery}}\"": "\"{{searchQuery}}\"에 대한 지식 기반 검색 중", "Searching the web": "웹에서 검색 중...", "Searxng Query URL": "Searxng 쿼리 URL", - "Searxng search language (all, en, es, de, fr, etc.)": "", + "Searxng search language (all, en, es, de, fr, etc.)": "Searxng 검색 언어 (all, en, es, de, fr, etc.)", "See readme.md for instructions": "설명은 readme.md를 참조하세요.", "See what's new": "새로운 기능 보기", "Seed": "시드", "Select": "선택", - "Select {{modelName}} model": "", + "Select {{modelName}} model": "{{modelName}} 모델 선택", "Select a base model": "기본 모델 선택", "Select a base model (e.g. llama3, gpt-4o)": "기본 모델 선택 (예: llama3, gpt-4o)", "Select a conversation to preview": "대화를 선택하여 미리 보기", @@ -1779,34 +1752,34 @@ "Select a model (optional)": "모델 선택 (선택사항)", "Select a pipeline": "파이프라인 선택", "Select a pipeline url": "파이프라인 URL 선택", - "Select a reranking model engine": "", + "Select a reranking model engine": "리랭킹 모델 엔진 선택", "Select a role": "역할 선택", "Select a theme": "테마 선택", "Select a tool": "도구 선택", "Select a voice": "음성 선택", - "Select All": "", + "Select All": "모두 선택", "Select an auth method": "인증 방법 선택", "Select an embedding model engine": "임베딩 모델 엔진 선택", "Select an engine": "엔진 선택", "Select an Ollama instance": "Ollama 인스턴스 선택", - "Select an option": "", + "Select an option": "옵션 선택", "Select an output format": "출력 형식 선택", "Select dtype": "dtype 선택", "Select Engine": "엔진 선택", "Select how to split message text for TTS requests": "TTS 요청에 대한 메시지 텍스트 분할 방법 선택", "Select Knowledge": "지식 기반 선택", - "Select Method": "", - "Select model": "", + "Select Method": "방법 선택", + "Select model": "모델 선택", "Select only one model to call": "음성 기능을 위해서는 모델을 하나만 선택해야 합니다.", - "Select view": "", - "Selected model: {{modelName}}": "", + "Select view": "보기 선택", + "Selected model: {{modelName}}": "선택된 모델: {{modelName}}", "Selected model(s) do not support image inputs": "선택한 모델은 이미지 입력을 지원하지 않습니다.", - "Selected Models": "", + "Selected Models": "선택된 모델들", "semantic": "의미적", "Send": "보내기", "Send a Message": "메시지 보내기", "Send message": "메시지 보내기", - "Send now": "", + "Send now": "지금 보내기", "Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.": "'stream_options: { include_usage: true }' 요청 보내기 \n지원되는 제공자가 토큰 사용 정보를 응답할 예정입니다", "September": "9월", "SerpApi API Key": "SerpApi API 키", @@ -1814,16 +1787,16 @@ "Serper API Key": "Serper API 키", "Serply API Key": "Serply API 키", "Serpstack API Key": "Serpstack API 키", - "Server connection failed": "", + "Server connection failed": "서버 연결 실패", "Server connection verified": "서버 연결 확인됨", "Session": "세션", "Set as default": "기본값으로 설정", - "Set as Production": "", + "Set as Production": "프로덕션으로 설정", "Set embedding model": "임베딩 모델 설정", "Set embedding model (e.g. {{model}})": "임베딩 모델 설정 (예: {{model}})", "Set reranking model (e.g. {{model}})": "Reranking 모델 설정 (예: {{model}})", - "Set the default models that are automatically selected for all users when a new chat is created.": "", - "Set the models that are automatically pinned to the sidebar for all users.": "", + "Set the default models that are automatically selected for all users when a new chat is created.": "새 채팅이 생성될 때 모든 사용자에게 자동으로 선택되는 기본 모델을 설정합니다.", + "Set the models that are automatically pinned to the sidebar for all users.": "모든 사용자에게 자동으로 사이드바에 고정되는 모델을 설정합니다.", "Set the number of layers, which will be off-loaded to GPU. Increasing this value can significantly improve performance for models that are optimized for GPU acceleration but may also consume more power and GPU resources.": "GPU에 오프로드될 레이어 수를 설정합니다. 이 값을 높이면 GPU 가속에 최적화된 모델의 성능이 크게 향상될 수 있지만 더 많은 전력과 GPU 리소스를 소비할 수도 있습니다.", "Set the number of worker threads used for computation. This option controls how many threads are used to process incoming requests concurrently. Increasing this value can improve performance under high concurrency workloads but may also consume more CPU resources.": "계산에 사용되는 작업자 스레드 수를 설정합니다. 이 옵션은 들어오는 요청을 동시에 처리하는 데 사용되는 스레드 수를 제어합니다. 이 값을 높이면 동시성이 높은 워크로드에서 성능을 향상시킬 수 있지만 더 많은 CPU 리소스를 소비할 수도 있습니다.", "Set Voice": "음성 설정", @@ -1837,29 +1810,29 @@ "Sets the stop sequences to use. When this pattern is encountered, the LLM will stop generating text and return. Multiple stop patterns may be set by specifying multiple separate stop parameters in a modelfile.": "중단 시퀀스를 설정합니다. 이 패턴이 발생하면 LLM은 텍스트 생성을 중단하고 반환합니다. 여러 중단 패턴은 모델 파일에서 여러 개의 별도 중단 매개변수를 지정하여 설정할 수 있습니다.", "Setting": "설정", "Settings": "설정", - "Settings Permissions": "", + "Settings Permissions": "설정 권한", "Settings saved successfully!": "설정이 성공적으로 저장되었습니다!", "Share": "공유", "Share Chat": "채팅 공유", - "Share link copied to clipboard.": "", + "Share link copied to clipboard.": "공유 링크가 클립보드에 복사되었습니다.", "Share to Open WebUI Community": "OpenWebUI 커뮤니티에 공유", "Share your background and interests": "당신의 배경과 관심사를 공유하세요", - "Shared Chats": "", - "Shared with you": "", + "Shared Chats": "공유된 채팅", + "Shared with you": "당신과 공유됨", "Sharing Permissions": "권한 공유", "Show": "보기", "Show \"What's New\" modal on login": "로그인시 \"새로운 기능\" 모달 보기", "Show Admin Details in Account Pending Overlay": "사용자용 계정 보류 설명창에, 관리자 상세 정보 노출", - "Show All": "", - "Show all ({{COUNT}} characters)": "", - "Show Files": "", + "Show All": "모두 보기", + "Show all ({{COUNT}} characters)": "모든 ({{COUNT}} 문자) 보기", + "Show Files": "파일 보기", "Show Formatting Toolbar": "서식 툴바 표시", "Show image preview": "이미지 미리보기", "Show Model": "모델 보기", "Show Shortcuts": "단축키 보기", "Show your support!": "당신의 응원을 보내주세요!", "Showcased creativity": "창의성 발휘", - "Showing all messages (user + assistant) per user.": "", + "Showing all messages (user + assistant) per user.": "사용자당 모든 메시지(사용자 + 어시스턴트) 표시.", "Sign in": "로그인", "Sign in to {{WEBUI_NAME}}": "{{WEBUI_NAME}} 로그인", "Sign in to {{WEBUI_NAME}} with LDAP": "LDAP로 {{WEBUI_NAME}}에 로그인", @@ -1868,72 +1841,69 @@ "Sign up to {{WEBUI_NAME}}": "{{WEBUI_NAME}} 가입", "Significantly improves accuracy by using an LLM to enhance tables, forms, inline math, and layout detection. Will increase latency. Defaults to False.": "LLM을 활용하여 표, 양식, 인라인 수식 및 레이아웃 감지 정확도를 대폭 개선합니다. 하지만 지연 시간이 증가할 수 있습니다. 기본값은 False입니다.", "Signing in to {{WEBUI_NAME}}": "{{WEBUI_NAME}}로 가입중", - "Single": "", + "Single": "단일", "Sink List": "리스트 내리기", - "sk-1234": "", - "Skill created successfully": "", - "Skill deleted successfully": "", - "Skill Description": "", - "Skill ID": "", - "Skill imported successfully": "", - "Skill Instructions": "", - "Skill Name": "", - "Skill updated successfully": "", - "Skills": "", - "Skills Access": "", - "Skills Public Sharing": "", - "Skills Sharing": "", + "sk-1234": "sk-1234", + "Skill created successfully": "스킬이 성공적으로 생성되었습니다.", + "Skill deleted successfully": "스킬이 성공적으로 삭제되었습니다.", + "Skill Description": "스킬 설명", + "Skill ID": "스킬 ID", + "Skill imported successfully": "스킬이 성공적으로 가져와졌습니다.", + "Skill Instructions": "스킬 지침", + "Skill Name": "스킬 이름", + "Skill updated successfully": "스킬이 성공적으로 업데이트되었습니다.", + "Skills": "스킬", + "Skills Access": "스킬 접근", + "Skills Public Sharing": "스킬 공개 공유", + "Skills Sharing": "스킬 공유", "Skip Cache": "캐시 무시", "Skip the cache and re-run the inference. Defaults to False.": "캐시를 무시하고 추론을 다시 실행합니다. 기본값은 False입니다.", "Something went wrong :/": "무언가 잘못 되었습니다 :/", - "Sonar": "", - "Sonar Deep Research": "", - "Sonar Pro": "", - "Sonar Reasoning": "", - "Sonar Reasoning Pro": "", - "Sort": "", - "Sort by": "", - "Sougou Search API sID": "", - "Sougou Search API SK": "", + "Sonar": "Sonar", + "Sonar Deep Research": "Sonar Deep Research", + "Sonar Pro": "Sonar Pro", + "Sonar Reasoning": "Sonar Reasoning", + "Sonar Reasoning Pro": "Sonar Reasoning Pro", + "Sort": "정렬", + "Sort by": "정렬 기준", + "Sougou Search API sID": "Sougou Search API sID", + "Sougou Search API SK": "Sougou Search API SK", "Source": "출처", "Speech Playback Speed": "음성 재생 속도", "Speech recognition error: {{error}}": "음성 인식 오류: {{error}}", "Speech-to-Text": "음성-텍스트 변환", "Speech-to-Text Engine": "음성-텍스트 변환 엔진", - "Speech-to-Text Language": "", - "Split documents by markdown headers before applying character/token splitting.": "", + "Speech-to-Text Language": "음성-텍스트 변환 언어", + "Split documents by markdown headers before applying character/token splitting.": "문자/토큰 분할을 적용하기 전에 마크다운 헤더로 문서를 분할합니다.", "Start a new conversation": "새 대화 시작", "Start of the channel": "채널 시작", "Start Tag": "시작 태그", - "Starting in {{count}} minutes_other": "", - "Starting in 1 minute": "", - "Starting kernel...": "", - "Starting now": "", - "State": "", + "Starting kernel...": "커널 시작 중...", + "State": "상태", "Status": "상태", "Status cleared successfully": "상태 초기화에 성공했습니다", "Status updated successfully": "상태 업데이트에 성공했습니다", "Status Updates": "상태 업데이트", "STDOUT/STDERR": "STDOUT/STDERR", - "Steps": "", + "Steps": "단계", "Stop": "정지", - "Stop Download": "", + "Stop Download": "다운로드 중지", "Stop Generating": "생성 중지", "Stop Sequence": "중지 시퀀스", - "Storage": "", + "Storage": "저장소", "Stream Chat Response": "스트림 채팅 응답", "Stream Delta Chunk Size": "스트림 델타 청크 크기", - "Streamable HTTP": "", + "Streamable HTTP": "스트림 가능한 HTTP", "Strikethrough": "취소선", "Strip Existing OCR": "기존 OCR 제거", "Strip existing OCR text from the PDF and re-run OCR. Ignored if Force OCR is enabled. Defaults to False.": "PDF에서 기존 OCR 텍스트를 제거하고 OCR을 다시 실행합니다. Force OCR이 활성화된 경우 무시됩니다. 기본값은 False입니다.", "STT Model": "STT 모델", "STT Settings": "STT 설정", "Stylized PDF Export": "서식이 적용된 PDF 내보내기", - "Su_day_of_week": "", - "Submit question": "", - "Submit suggestion": "", - "Subtitle": "", + "Su_day_of_week": "Su_day_of_week", + "Submit question": "질문 제출", + "Submit suggestion": "제안 제출", + "Subtitle": "부제목", "Success": "성공", "Successfully imported {{userCount}} users.": "성공적으로 {{userCount}}명의 사용자를 가져왔습니다.", "Successfully updated.": "성공적으로 업데이트되었습니다.", @@ -1942,14 +1912,14 @@ "Support": "지원", "Support this plugin:": "플러그인 지원", "Supported MIME Types": "지원하는 MIME 타입", - "Sync": "", - "Sync Complete!": "", + "Sync": "동기화", + "Sync Complete!": "동기화 완료!", "Sync directory": "디렉토리 연동", - "Sync Failed": "", - "Sync Usage Stats": "", - "Syncing stats...": "", - "Syncing...": "", - "Syncs only chats with updates after your last sync timestamp. Disable to re-sync all chats.": "", + "Sync Failed": "동기화 실패", + "Sync Usage Stats": "동기화 사용 통계", + "Syncing stats...": "동기화 통계...", + "Syncing...": "동기화 중...", + "Syncs only chats with updates after your last sync timestamp. Disable to re-sync all chats.": "마지막 동기화 타임스탬프 이후 업데이트된 채팅만 동기화합니다. 모든 채팅을 다시 동기화하려면 비활성화하세요.", "System": "시스템", "System Instructions": "시스템 지침", "System Prompt": "시스템 프롬프트", @@ -1958,25 +1928,25 @@ "Tags Generation": "태그 생성", "Tags Generation Prompt": "태그 생성 프롬프트", "Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting.": "꼬리 자유 샘플링은 출력에서 확률이 낮은 토큰의 영향을 줄이기 위해 사용됩니다. 값이 클수록(예: 2.0) 이러한 토큰의 영향이 더 줄어들며, 1.0으로 설정하면 이 기능은 비활성화됩니다.", - "Talk to Model": "", + "Talk to Model": "모델과 대화", "Tap to interrupt": "탭하여 중단", "Task List": "작업 목록", - "Task Management": "", + "Task Management": "작업 관리", "Task Model": "작업 모델", "Tasks": "작업", - "tasks completed": "", + "tasks completed": "작업 완료", "Tavily API Key": "Tavily API 키", "Tavily Extract Depth": "Tabily 깊이 추출", "Tell us more:": "더 알려주세요:", "Temperature": "온도", "Temporary Chat": "임시 채팅", "Temporary Chat by Default": "임시 채팅을 기본값으로", - "Terminal": "", - "Terminal servers saved": "", + "Terminal": "터미널", + "Terminal servers saved": "터미널 서버 저장됨", "Text Splitter": "텍스트 나누기", "Text-to-Speech": "텍스트-음성 변환", "Text-to-Speech Engine": "텍스트-음성 변환 엔진", - "Th_day_of_week": "", + "Th_day_of_week": "Th_day_of_week", "Thanks for your feedback!": "피드백 감사합니다!", "The Application Account DN you bind with for search": "검색을 위해 바인딩하는 애플리케이션 계정 DN", "The base to search for users": "사용자를 검색할 수 있는 기반", @@ -1994,20 +1964,20 @@ "The output format for the text. Can be 'json', 'markdown', or 'html'. Defaults to 'markdown'.": "텍스트의 출력 형식입니다. 'json', 'markdown', 또는 'html'이 될 수 있습니다. 기본값은 'markdown'입니다.", "The passwords you entered don't quite match. Please double-check and try again.": "입력한 비밀번호가 일치하지 않습니다. 확인 후 다시 시도해 주세요.", "The score should be a value between 0.0 (0%) and 1.0 (100%).": "점수는 0.0(0%)에서 1.0(100%) 사이의 값이어야 합니다.", - "The stream delta chunk size for the model. Increasing the chunk size will make the model respond with larger pieces of text at once.": "", + "The stream delta chunk size for the model. Increasing the chunk size will make the model respond with larger pieces of text at once.": "모델의 스트림 델타 청크 크기입니다. 청크 크기를 늘리면 모델이 한 번에 더 큰 텍스트 조각으로 응답하게 됩니다.", "The temperature of the model. Increasing the temperature will make the model answer more creatively.": "모델의 온도. 온도를 높이면 모델이 더 창의적으로 답변할 수 있습니다.", "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "BM25 하이브리드 검색의 가중치. 0에 가까울수록 의미(semantic) 기반, 1에 가까울수록 어휘(lexical) 기반. 기본값 0.5", "The width in pixels to compress images to. Leave empty for no compression.": "이미지를 압축할 픽셀 너비입니다. 압축하지 않으려면 비워 두세요.", "Theme": "테마", - "There was an error syncing your stats. Please try again.": "", + "There was an error syncing your stats. Please try again.": "통계 동기화 중 오류가 발생했습니다. 다시 시도해 주세요.", "Thinking...": "생각 중...", "This action cannot be undone. Do you wish to continue?": "이 행동은 되돌릴 수 없습니다. 계속 하시겠습니까?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "{{createdAt}}에 {{channelName}} 채널이 처음 만들어졌습니다. 대화를 시작해보세요.", "This chat won't appear in history and your messages will not be saved.": "이 채팅은 기록에 나타나지 않으며 메시지가 저장되지 않습니다.", "This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "이렇게 하면 소중한 대화 내용이 백엔드 데이터베이스에 안전하게 저장됩니다. 감사합니다!", - "This feature is currently experimental and may not work as expected.": "", + "This feature is currently experimental and may not work as expected.": "이 기능은 현재 실험 중이며 예상대로 작동하지 않을 수 있습니다.", "This feature is experimental and may be modified or discontinued without notice.": "이 기능은 실험 중이며, 사전 통보 없이 수정되거나 중단될 수 있습니다.", - "This folder is empty": "", + "This folder is empty": "이 폴더는 비어 있습니다.", "This is a default user permission and will remain enabled.": "이것은 기본 사용자 권한이며 계속 활성화됩니다.", "This is an experimental feature, it may not function as expected and is subject to change at any time.": "이것은 실험적 기능으로, 예상대로 작동하지 않을 수 있으며 언제든지 변경될 수 있습니다.", "This model is not publicly available. Please select another model.": "이 모델은 공개적으로 사용할 수 없습니다. 다른 모델을 선택해주세요.", @@ -2021,50 +1991,48 @@ "This will delete {{NAME}} and all its contents.": "{{NAME}}모든 내용을 삭제합니다.", "This will delete all models including custom models": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제됩니다", "This will delete all models including custom models and cannot be undone.": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제되며 실행 취소할 수 없습니다.", - "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "지식 기반과 모든 파일 연동을 초기화합니다. 계속 하시겠습니까?", "Thorough explanation": "완전한 설명", - "Thought": "", + "Thought": "생각", "Thought for {{DURATION}}": "{{DURATION}} 동안 생각함", "Thought for {{DURATION}} seconds": "{{DURATION}}초 동안 생각함", "Thought for less than a second": "1초 미만 동안 생각함", "Thread": "스레드", - "Thumbs up/down ratings from users on model responses": "", - "Tika": "", + "Thumbs up/down ratings from users on model responses": "모델 응답에 대한 사용자들의 좋아요/싫어요 평가", + "Tika": "Tika", "Tika Server URL required.": "Tika 서버 URL이 필요합니다.", "Tiktoken": "틱토큰 (Tiktoken)", - "Time": "", - "Time & Calculation": "", - "Timeout": "", + "Time": "시간", + "Time & Calculation":"시간 및 계산", + "Timeout": "시간 초과", "Title": "제목", "Title Auto-Generation": "제목 자동 생성", "Title cannot be an empty string.": "제목은 빈 문자열일 수 없습니다.", "Title Generation": "제목 생성", "Title Generation Prompt": "제목 생성 프롬프트", - "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "다운로드 가능한 모델명을 확인하려면,", "To access the GGUF models available for downloading,": "다운로드 가능한 GGUF 모델을 확인하려면,", "To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "WebUI에 접속하려면 관리자에게 문의하십시오. 관리자는 관리자 패널에서 사용자 상태를 관리할 수 있습니다.", "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "지식 기반을 여기에 첨부하려면. \"지식 기반\" 워크스페이스에 먼저 추가하세요", "To learn more about available endpoints, visit our documentation.": "사용 가능한 엔드포인트에 대해 자세히 알아보려면 문서를 방문하세요.", - "To select skills here, add them to the \"Skills\" workspace first.": "", + "To select skills here, add them to the \"Skills\" workspace first.": "여기서 스킬을 선택하려면, \"스킬\" 워크스페이스에 먼저 추가하세요.", "To select toolkits here, add them to the \"Tools\" workspace first.": "여기서 도구를 선택하려면, \"도구\" 워크스페이스에 먼저 추가하세요.", "Toast notifications for new updates": "새 업데이트 알림", "Today": "오늘", - "Today at": "", + "Today at": "오늘은", "Today at {{LOCALIZED_TIME}}": "오늘 {{LOCALIZED_TIME}}", - "Toggle {{COUNT}} sources": "", - "Toggle 1 source": "", - "Toggle details": "", - "Toggle Dictation": "", - "Toggle Sidebar": "", - "Toggle status history": "", + "Toggle {{COUNT}} sources": "{{COUNT}} 소스 토글", + "Toggle 1 source": "1 소스 토글", + "Toggle details": "세부 정보 토글", + "Toggle Dictation": "음성 입력 토글", + "Toggle Sidebar": "사이드바 토글", + "Toggle status history": "상태 기록 토글", "Toggle whether current connection is active.": "현재 연결 활성화 여부 설정", "Token": "토큰", - "Token counts are estimates and may not reflect actual API usage": "", - "tokens": "", - "Tokens": "", + "Token counts are estimates and may not reflect actual API usage": "토큰 수는 추정치이며 실제 API 사용량을 반영하지 않을 수 있습니다.", + "tokens": "토큰", + "Tokens": "토큰", "Too verbose": "너무 장황합니다", "Tool created successfully": "성공적으로 도구가 생성되었습니다.", "Tool deleted successfully": "성공적으로 도구가 삭제되었습니다.", @@ -2081,7 +2049,7 @@ "Tools have a function calling system that allows arbitrary code execution.": "도구에 임의 코드 실행을 허용하는 함수가 포함되어 있습니다.", "Tools Public Sharing": "도구 공개 및 공유", "Tools Sharing": "도구 공유", - "Top": "", + "Top": "상위", "Top K": "Top K", "Top K Reranker": "Top K 리랭커", "Transformers": "트랜스포머", @@ -2092,13 +2060,13 @@ "TTS Model": "TTS 모델", "TTS Settings": "TTS 설정", "TTS Voice": "TTS 음성", - "Tu_day_of_week": "", + "Tu_day_of_week": "Tu_day_of_week", "Type": "입력", - "Type here...": "", + "Type here...": "여기에 입력하세요...", "Type Hugging Face Resolve (Download) URL": "Hugging Face Resolve (다운로드) URL 입력", "Uh-oh! There was an issue with the response.": "이런! 응답에 문제가 발생했습니다.", "UI": "UI", - "UI Scale": "", + "UI Scale": "UI 크기", "Unarchive All": "모두 보관 해제", "Unarchive All Archived Chats": "보관된 모든 채팅을 보관 해제", "Unarchive Chat": "채팅 보관 해제", @@ -2108,9 +2076,8 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} 언로드", "Unlock mysteries": "미스터리 풀기", "Unpin": "고정 해제", - "Unpin from Sidebar": "", "Unravel secrets": "비밀 풀기", - "Unshare Chat": "", + "Unshare Chat": "채팅 공유 해제", "Unsupported file type.": "지원하지 않는 파일 형식", "Untagged": "태그 해제", "Untitled": "제목 없음", @@ -2131,32 +2098,32 @@ "Upload Files": "파일 업로드", "Upload Model": "모델 업로드", "Upload Pipeline": "업로드 파이프라인", - "Upload profile image": "", + "Upload profile image": "프로필 이미지 업로드", "Upload Progress": "업로드 진행 상황", - "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", - "Uploaded files or images": "", + "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "업로드 진행 상황: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "업로드된 파일 또는 이미지", "Uploading file...": "파일 업로드중...", - "Uploading...": "", + "Uploading...": "업로드 중...", "URL": "URL", "URL is required": "URL이 필요합니다.", "URL Mode": "URL 모드", "Usage": "사용량", - "Use": "", + "Use": "사용", "Use '#' in the prompt input to load and include your knowledge.": "프롬프트 입력에서 '#'를 사용하여 지식 기반을 불러오고 포함하세요.", "Use /v1/chat/completions endpoint instead of /v1/audio/transcriptions for potentially better accuracy.": "더 정확한 결과를 얻으려면 /v1/audio/transcriptions 대신 /v1/chat/completions 엔드포인트를 사용해 보세요.", "Use Chat Completions API": "Chat Completions API 사용", - "Use groups to organize your users and assign permissions.": "", + "Use groups to organize your users and assign permissions.": "그룹을 사용하여 사용자를 조직하고 권한을 할당하세요.", "Use LLM": "LLM 사용", "Use no proxy to fetch page contents.": "페이지 콘텐츠를 가져오려면 프록시를 사용하지 마세요.", "Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "http_proxy 및 https_proxy 환경 변수로 지정된 프록시를 사용하여 페이지 콘텐츠를 가져옵니다.", "user": "사용자", "User": "사용자", - "User Activity": "", + "User Activity": "사용자 활동", "User Groups": "사용자 그룹", "User location successfully retrieved.": "성공적으로 사용자의 위치를 불러왔습니다", "User menu": "사용자 메뉴", - "User ratings (thumbs up/down)": "", - "User Status": "", + "User ratings (thumbs up/down)": "사용자 평가 (좋아요/싫어요)", + "User Status": "사용자 상태", "User Webhooks": "사용자 웹훅", "Username": "사용자 이름", "users": "사용자", @@ -2176,27 +2143,27 @@ "Verify SSL Certificate": "SSL 인증서 확인", "Version": "버전", "Version {{selectedVersion}} of {{totalVersions}}": "버전 {{totalVersions}}의 {{selectedVersion}}", - "Version deleted": "", + "Version deleted": "버전이 삭제되었습니다", "View Replies": "답글 보기", "View Result from **{{NAME}}**": "**{{NAME}}**의 결과 보기", - "View source: {{name}}": "", - "View source: {{title}}": "", + "View source: {{name}}": "소스 보기: {{name}}", + "View source: {{title}}": "소스 보기: {{title}}", "Visibility": "공개 범위", - "Visible": "", - "Visible to all users": "", + "Visible": "공개", + "Visible to all users": "모든 사용자에게 공개", "Vision": "비전", "Voice": "음성", "Voice Input": "음성 입력", "Voice mode": "음성 모드 사용", "Voice Mode Custom Prompt": "음성 모드 사용자 지정 프롬프트", - "Voice Mode Prompt": "", - "Waiting for upload...": "", + "Voice Mode Prompt": "음성 모드 프롬프트", + "Waiting for upload...": "업로드 기다리는 중...", "Warning": "경고", "Warning:": "주의:", - "Warning: Enabling this will allow users to run scheduled prompts automatically.": "", + "Warning: Enabling this will allow users to run scheduled prompts automatically.": "주의: 이 기능을 활성화하면 사용자가 예약된 프롬프트를 자동으로 실행할 수 있습니다.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "주의: 이 기능을 활성화하면 사용자가 서버에 임의 코드를 업로드할 수 있습니다.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "경고: Jupyter 실행은 임의의 코드 실행을 가능하게 하여 심각한 보안 위험을 초래합니다. — 매우 신중하게 진행하세요.", - "We_day_of_week": "", + "We_day_of_week": "We_day_of_week", "Web": "웹", "Web API": "웹 API", "Web Loader Engine": "웹 로더 엔진", @@ -2204,50 +2171,48 @@ "Web Search Engine": "웹 검색 엔진", "Web Search in Chat": "채팅에서 웹 검색", "Web Search Query Generation": "웹 검색 쿼리 생성", - "Webhook Name": "", + "Webhook Name": "웹훅 이름", "Webhook URL": "웹훅 URL", - "Webhooks": "", - "Webpage URLs": "", + "Webhooks": "웹훅", + "Webpage URLs": "웹페이지 URL", "WebUI Settings": "WebUI 설정", - "WebUI URL": "", + "WebUI URL": "WebUI URL", "WebUI will make requests to \"{{url}}\"": "WebUI가 \"{{url}}\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI가 \"{{url}}/api/chat\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI가 \"{{url}}/chat/completions\"로 요청을 보냅니다", - "Week": "", - "Weekly": "", + "Weekly": "주간", "What are you trying to achieve?": "무엇을 성취하고 싶으신가요?", "What are you working on?": "어떤 작업을 하고 계신가요?", - "What is NOT shared:": "", - "What is shared:": "", + "What is NOT shared:": "공유되지 않는 것:", + "What is shared:": "공유되는 것:", "What's New in": "새로운 기능:", "What's on your mind?": "무슨 생각을 하고 계신가요?", - "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "활성화하면 모델이 각 채팅 메시지에 실시간으로 응답하여 사용자가 메시지를 보내는 즉시 응답을 생성합니다. 이 모드는 실시간 채팅 애플리케이션에 유용하지만, 느린 하드웨어에서는 성능에 영향을 미칠 수 있습니다.", "wherever you are": "당신이 어디에 있든", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "출력을 페이지로 나눌지 여부입니다. 각 페이지는 구분선과 페이지 번호로 구분됩니다. 기본값은 False입니다.", "Whisper (Local)": "Whisper (로컬)", - "Who can share to this group": "", + "Who can share to this group": "누가 이 그룹에 공유할 수 있나요", "Why?": "이유는?", "Widescreen Mode": "와이드스크린 모드", - "Width": "", - "Wikipedia": "", + "Width": "너비", + "Wikipedia": "위키피디아", "Won": "승리", - "Working Directory": "", + "Working Directory": "작업 디렉토리", "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.": "top-k와 함께 작동합니다. 값이 높을수록(예: 0.95) 더 다양한 텍스트가 생성되고, 값이 낮을수록(예: 0.5) 더 집중적이고 보수적인 텍스트가 생성됩니다.", "Workspace": "워크스페이스", "Workspace Permissions": "워크스페이스 권한", "Write": "작성", - "Write a summary in 50 words that summarizes {{topic}}.": "[주제 또는 키워드]에 대한 50단어 요약문을 작성하시오.", + "Write a summary in 50 words that summarizes {{topic}}.": "{{topic}}에 대한 50단어 요약문을 작성하시오.", "Write something...": "내용을 입력하세요…", "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "여기에 모델 시스템 프롬프트 내용을 작성하세요\n예: 당신은 Super Mario Bros의 마리오로서, 어시스턴트 역할을 합니다.", "Yacy Instance URL": "Yacy 인스턴스 URL", "Yacy Password": "Yacy 비밀번호", "Yacy Username": "Yacy 사용자 이름", - "Yahoo": "", - "Yandex": "", - "Yandex Web Search API Key": "", - "Yandex Web Search config": "", - "Yandex Web Search URL": "", + "Yahoo": "야후", + "Yandex": "얀덱스", + "Yandex Web Search API Key": "얀덱스 웹 검색 API 키", + "Yandex Web Search config": "얀덱스 웹 검색 구성", + "Yandex Web Search URL": "얀덱스 웹 검색 URL", "Yesterday": "어제", "Yesterday at {{LOCALIZED_TIME}}": "어제 {{LOCALIZED_TIME}}", "You": "당신", @@ -2255,29 +2220,29 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "최대 {{maxCount}}개의 파일과만 동시에 대화할 수 있습니다 ", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "아래 '관리' 버튼으로 메모리를 추가하여 LLM들과의 상호작용을 개인화할 수 있습니다. 이를 통해 더 유용하고 맞춤화된 경험을 제공합니다.", "You cannot upload an empty file.": "빈 파일을 업로드 할 수 없습니다", - "You do not have permission to edit this model": "", - "You do not have permission to edit this prompt.": "", - "You do not have permission to edit this skill.": "", - "You do not have permission to edit this tool": "", - "You do not have permission to make this public": "", - "You do not have permission to send messages in this channel.": "", - "You do not have permission to send messages in this thread.": "", - "You do not have permission to upload files to this knowledge base.": "", + "You do not have permission to edit this model": "이 모델을 편집할 권한이 없습니다", + "You do not have permission to edit this prompt.": "이 프롬프트를 편집할 권한이 없습니다", + "You do not have permission to edit this skill.": "이 기술을 편집할 권한이 없습니다", + "You do not have permission to edit this tool": "이 도구를 편집할 권한이 없습니다", + "You do not have permission to make this public": "이 것을 공개할 권한이 없습니다", + "You do not have permission to send messages in this channel.": "이 채널에 메시지를 보내할 권한이 없습니다", + "You do not have permission to send messages in this thread.": "이 스레드에 메시지를 보내할 권한이 없습니다", + "You do not have permission to upload files to this knowledge base.": "이 지식 베이스에 파일을 업로드할 권한이 없습니다", "You do not have permission to upload files.": "파일을 업로드할 권한이 없습니다.", - "You do not have permission to upload web content.": "", + "You do not have permission to upload web content.": "웹 콘텐츠를 업로드할 권한이 없습니다", "You have no archived conversations.": "채팅을 보관한 적이 없습니다.", - "You have no shared conversations.": "", + "You have no shared conversations.": "공유된 대화가 없습니다.", "You have shared this chat": "이 채팅을 공유했습니다.", - "You.com API Key": "", + "You.com API Key": "You.com API 키", "You're a helpful assistant.": "당신은 유용한 어시스턴트입니다.", "You're now logged in.": "로그인되었습니다.", "Your Account": "계정", "Your account status is currently pending activation.": "현재 계정은 아직 활성화되지 않았습니다.", - "Your browser does not support the audio tag.": "", - "Your browser does not support the video tag.": "", + "Your browser does not support the audio tag.": "당신의 브라우저는 오디오 태그를 지원하지 않습니다.", + "Your browser does not support the video tag.": "당신의 브라우저는 비디오 태그를 지원하지 않습니다.", "Your entire contribution will go directly to the plugin developer; Open WebUI does not take any percentage. However, the chosen funding platform might have its own fees.": "당신의 모든 기여는 곧바로 플러그인 개발자에게 갑니다; Open WebUI는 수수료를 받지 않습니다. 다만, 선택한 후원 플랫폼은 수수료를 가져갈 수 있습니다.", - "Your message text or inputs": "", - "Your usage stats have been successfully synced.": "", + "Your message text or inputs": "당신의 메시지 텍스트 또는 입력값", + "Your usage stats have been successfully synced.": "당신의 사용 통계가 성공적으로 동기화되었습니다.", "YouTube": "유튜브", "Youtube Language": "Youtube 언어", "Youtube Proxy URL": "Youtube 프록시 URL" From 9b577868c81a690c700a913206ae5d1ffcfd55e8 Mon Sep 17 00:00:00 2001 From: joaoback <156559121+joaoback@users.noreply.github.com> Date: Fri, 24 Apr 2026 02:38:33 -0300 Subject: [PATCH 359/404] i18n: add pt-BR translations for newly added UI items and consistency pass (#23954) New **pt-BR** translations for items introduced in the latest releases, plus a consistency/quality pass across existing strings (grammar, tone, capitalization, pluralization). Placeholders and hotkeys preserved. No logic changes. --- src/lib/i18n/locales/pt-BR/translation.json | 72 ++++++++++----------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index bde1024811..ca721304fe 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -34,13 +34,13 @@ "{{user}}'s Chats": "Chats de {{user}}", "{{webUIName}} Backend Required": "Backend {{webUIName}} necessário", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) são obrigatórios para gerar imagens", - "1 hour before": "", + "1 hour before": "1 hora antes", "1 Source": "1 Origem", - "10 minutes before": "", - "15 minutes before": "", + "10 minutes before": "10 minutos antes", + "15 minutes before": "15 minutos antes", "1m_time_ago": "1m atrás", - "30 minutes before": "", - "5 minutes before": "", + "30 minutes before": "30 minutos antes", + "5 minutes before": "5 minutos antes", "A collaboration channel where people join as members": "Um canal de colaboração onde as pessoas se juntam como membros.", "A discussion channel where access is controlled by groups and permissions": "Um canal de discussão onde o acesso é controlado por grupos e permissões.", "A new version (v{{LATEST_VERSION}}) is now available.": "Uma nova versão (v{{LATEST_VERSION}}) está disponível.", @@ -79,11 +79,11 @@ "Add content here": "Adicionar conteúdo aqui", "Add Custom Parameter": "Adicionar parâmetro personalizado", "Add Custom Prompt": "Adicionar prompt personalizado", - "Add description": "", + "Add description": "Adicionar descrição", "Add Details": "Adicionar detalhes", "Add Files": "Adicionar Arquivos", "Add Image": "Adicionar imagem", - "Add location": "", + "Add location": "Adicionar localização", "Add Member": "Adicionar membro", "Add Members": "Adicionar membros", "Add Memory": "Adicionar Memória", @@ -119,7 +119,7 @@ "AI": "IA", "All": "Tudo", "All chats have been unarchived.": "Todos os chats foram desarquivados.", - "All day": "", + "All day": "O dia todo", "All models are now hidden": "Todos os modelos estão agora ocultos", "All models are now visible": "Todos os modelos estão agora visíveis", "All models deleted successfully": "Todos os modelos foram excluídos com sucesso", @@ -208,7 +208,7 @@ "Ask a question": "Faça uma pergunta", "Assistant": "Assistente", "Async Embedding Processing": "Processamento de Embedding assíncrono", - "At time of event": "", + "At time of event": "No horário do evento", "Attach File From Knowledge": "Anexar arquivo da base de conhecimento", "Attach Files": "Anexar arquivos", "Attach Knowledge": "Anexar Base de Conhecimento", @@ -283,8 +283,8 @@ "Bypass Web Loader": "Ignorar carregador da Web", "Cache Base Model List": "Lista de modelos base de cache", "Calendar": "Calendário", - "Calendar deleted": "", - "Calendars": "", + "Calendar deleted": "Calendário excluído", + "Calendars": "Calendários", "Call": "Chamada", "Call feature is not supported when using Web STT engine": "O recurso de chamada não é suportado ao usar o mecanismo Web STT", "Camera": "Câmera", @@ -421,7 +421,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "Conecte-se aos seus próprios servidores de ferramentas externas compatíveis com OpenAPI.", "Connected ({{type}})": "Conectado ({{type}})", "Connection failed": "Falha na conexão", - "Connection lost. Reconnecting...": "", + "Connection lost. Reconnecting...": "Conexão perdida. Reconectando...", "Connection successful": "Conexão bem-sucedida", "Connection Type": "Tipo de conexão", "Connections": "Conexões", @@ -534,11 +534,11 @@ "Delete All Chats": "Excluir Todos os Chats", "Delete all contents inside this folder": "Apague todo o conteúdo desta pasta.", "Delete automation?": "Excluir automação?", - "Delete calendar": "", - "Delete Calendar": "", + "Delete calendar": "Excluir calendário", + "Delete Calendar": "Excluir Calendário", "Delete Chat": "Excluir Chat", "Delete chat?": "Excluir chat?", - "Delete Event": "", + "Delete Event": "Excluir Evento", "Delete File": "Excluir arquivo", "Delete folder?": "Excluir pasta?", "Delete function?": "Excluir função?", @@ -845,10 +845,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Erro: Já existe um modelo com o ID '{{modelId}}'. Selecione um ID diferente para prosseguir.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Erro: O ID do modelo não pode estar vazio. Insira um ID válido para prosseguir.", "Evaluations": "Avaliações", - "Event created": "", - "Event deleted": "", - "Event title": "", - "Event updated": "", + "Event created": "Evento criado", + "Event deleted": "Evento excluído", + "Event title": "Título do evento", + "Event updated": "Evento atualizado", "Exa API Key": "Chave da API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Exemplo: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Exemplo: ALL", @@ -897,7 +897,7 @@ "Failed to connect to {{URL}} terminal server": "Falha ao conectar ao servidor de terminal {{URL}}", "Failed to copy link": "Falha ao copiar o link", "Failed to create API Key.": "Falha ao criar a Chave API.", - "Failed to delete calendar": "", + "Failed to delete calendar": "Falha ao excluir calendário", "Failed to delete note": "Falha ao excluir a nota", "Failed to download image": "Falha ao baixar a imagem", "Failed to extract content from the file: {{error}}": "Falha ao extrair conteúdo do arquivo: {{error}}", @@ -1219,7 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limitar consultas de pesquisa simultâneas. 0 = ilimitado (padrão). Defina como 1 para execução sequencial (recomendado para APIs com limites de taxa rígidos, como o nível gratuito do Brave).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Limita o número de solicitações simultâneas de embedding. Defina como 0 para ilimitado.", "List": "Lista", - "List calendars, search, create, update, and delete calendar events": "", + "List calendars, search, create, update, and delete calendar events": "Listar calendários, pesquisar, criar, atualizar e excluir eventos do calendário", "Listening...": "Escutando...", "Live": "Ao vivo", "Llama.cpp": "Llama.cpp", @@ -1230,7 +1230,7 @@ "local": "local", "Local": "Local", "Local Task Model": "Modelo de Tarefa Local", - "Location": "", + "Location": "Localização", "Location access not allowed": "Acesso ao local não permitido", "Lost": "Perdeu", "Low": "Baixo", @@ -1340,7 +1340,7 @@ "Models Sharing": "Compartilhamento de Modelos", "Mojeek": "Mojeek", "Mojeek Search API Key": "Chave de API Mojeek Search", - "Month": "", + "Month": "Mês", "Monthly": "Mensal", "More": "Mais", "More Concise": "Mais conciso", @@ -1359,7 +1359,7 @@ "New Automation": "Nova Automação", "New Button": "Novo Botão", "New Chat": "Novo Chat", - "New Event": "", + "New Event": "Novo Evento", "New File": "Novo Arquivo", "New Folder": "Nova Pasta", "New Function": "Nova Função", @@ -1637,7 +1637,7 @@ "Reasoning Effort": "Esforço de raciocínio", "Reasoning Tags": "Tags de raciocínio", "Recently Used": "Usado recentemente", - "Reconnected": "", + "Reconnected": "Reconectado", "Record": "Gravar", "Record voice": "Gravar voz", "Redirecting you to Open WebUI Community": "Redirecionando você para a Comunidade OpenWebUI", @@ -1661,7 +1661,7 @@ "Relevance": "Relevância", "Relevance Threshold": "Limiar de Relevância", "Remember Dismissal": "Lembrar da dispensa", - "Reminder": "", + "Reminder": "Lembrete", "Remove": "Remover", "Remove {{MODELID}} from list.": "Remover {{MODELID}} da lista.", "Remove action": "Remover ação", @@ -1909,12 +1909,12 @@ "Start a new conversation": "Iniciar uma nova conversa", "Start of the channel": "Início do canal", "Start Tag": "Tag inicial", - "Starting in {{count}} minutes_one": "", - "Starting in {{count}} minutes_many": "", - "Starting in {{count}} minutes_other": "", - "Starting in 1 minute": "", + "Starting in {{count}} minutes_one": "Começando em {{count}} minuto", + "Starting in {{count}} minutes_many": "Começando em {{count}} minutos", + "Starting in {{count}} minutes_other": "Começando em {{count}} minutos", + "Starting in 1 minute": "Começando em 1 minuto", "Starting kernel...": "Iniciando kernel...", - "Starting now": "", + "Starting now": "Começando agora", "State": "Estado", "Status": "Status", "Status cleared successfully": "Status liberado com sucesso", @@ -2027,7 +2027,7 @@ "This will delete {{NAME}} and all its contents.": "Esta ação excluirá {{NAME}} e todos seus conteúdos.", "This will delete all models including custom models": "Isto vai excluir todos os modelos, incluindo personalizados", "This will delete all models including custom models and cannot be undone.": "Isto vai excluir todos os modelos, incluindo personalizados e não pode ser desfeito.", - "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "Esta ação excluirá permanentemente o calendário \"{{name}}\" e todos os seus eventos. Esta ação não pode ser desfeita.", "This will reset the knowledge base and sync all files. Do you wish to continue?": "Esta ação resetará a base de conhecimento e sincronizará todos os arquivos. Deseja continuar?", "Thorough explanation": "Explicação detalhada", "Thought": "Pensamento", @@ -2047,7 +2047,7 @@ "Title cannot be an empty string.": "O Título não pode ser uma string vazia.", "Title Generation": "Geração de Títulos", "Title Generation Prompt": "Prompt de Geração de Título", - "Title is required": "", + "Title is required": "O título é obrigatório", "TLS": "TLS", "To access the available model names for downloading,": "Para acessar os nomes de modelos disponíveis para download,", "To access the GGUF models available for downloading,": "Para acessar os modelos GGUF disponíveis para download,", @@ -2114,7 +2114,7 @@ "Unloads {{FROM_NOW}}": "Descarrega {{FROM_NOW}}", "Unlock mysteries": "Desvendar mistérios", "Unpin": "Desfixar", - "Unpin from Sidebar": "", + "Unpin from Sidebar": "Desfixar da barra lateral", "Unravel secrets": "Desvendar segredos", "Unshare Chat": "Cancelar compartilhamento do chat", "Unsupported file type.": "Tipo de arquivo não suportado.", @@ -2219,7 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "A WebUI fará requisições para \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "A WebUI fará requisições para \"{{url}}/api/chat\".", "WebUI will make requests to \"{{url}}/chat/completions\"": "A WebUI fará requisições para \"{{url}}/chat/completions\".", - "Week": "", + "Week": "Semana", "Weekly": "Semanal", "What are you trying to achieve?": "O que está tentando alcançar?", "What are you working on?": "No que está trabalhando?", @@ -2227,7 +2227,7 @@ "What is shared:": "O que é compartilhado", "What's New in": "O que há de novo em", "What's on your mind?": "O que você tem em mente?", - "When": "", + "When": "Quando", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Quando habilitado, o modelo responderá a cada mensagem de chat em tempo real, gerando uma resposta assim que o usuário enviar uma mensagem. Este modo é útil para aplicativos de chat ao vivo, mas pode impactar o desempenho em hardware mais lento.", "wherever you are": "onde quer que você esteja.", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Se a saída deve ser paginada. Cada página será separada por uma régua horizontal e um número de página. O padrão é Falso.", From f6bd08c852f65683d6357a935993f6ce5d3e4c37 Mon Sep 17 00:00:00 2001 From: tcx4c70 Date: Fri, 24 Apr 2026 13:39:45 +0800 Subject: [PATCH 360/404] fix(utils): Switch throttle decorator to async (#23979) After migration to async db operations, the throttle decorator also needs to support async. Since the decorator is only used for async funcs now, we can just switch it to async instead of supporting sync and async at the same time. Signed-off-by: Adam Tao --- backend/open_webui/utils/misc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index 670a94b512..5af84dd5cd 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -843,9 +843,9 @@ def throttle(interval: float = 10.0): last_calls = {} lock = threading.Lock() - def wrapper(*args, **kwargs): + async def wrapper(*args, **kwargs): if interval is None: - return func(*args, **kwargs) + return await func(*args, **kwargs) key = (args, freeze(kwargs)) now = time.time() @@ -855,7 +855,7 @@ def throttle(interval: float = 10.0): if now - last_calls.get(key, 0) < interval: return None last_calls[key] = now - return func(*args, **kwargs) + return await func(*args, **kwargs) return wrapper From 89669f3fa1a75ca2b38afe4dd345ae97132af302 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 14:40:17 +0900 Subject: [PATCH 361/404] refac --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index e405188cb4..3d458de753 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "aiocache==0.12.3", "aiofiles==25.1.0", "starlette-compress==1.7.0", - "Brotli==1.1.0", + "Brotli==1.2.0", "httpx[socks,http2,zstd,cli,brotli]==0.28.1", "starsessions[redis]==2.2.1", "python-mimeparse==2.0.0", From 4dc5c1eb4f885e0ace1d676d87ae34d9c82e1266 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:00:47 +0900 Subject: [PATCH 362/404] refac --- backend/open_webui/utils/telemetry/metrics.py | 107 +++++++++++++----- backend/open_webui/utils/telemetry/setup.py | 2 +- 2 files changed, 81 insertions(+), 28 deletions(-) diff --git a/backend/open_webui/utils/telemetry/metrics.py b/backend/open_webui/utils/telemetry/metrics.py index 26216b6ca4..a1d1dcb7cb 100644 --- a/backend/open_webui/utils/telemetry/metrics.py +++ b/backend/open_webui/utils/telemetry/metrics.py @@ -17,8 +17,10 @@ high-cardinality label sets. from __future__ import annotations +import datetime +import logging import time -from typing import Dict, List, Sequence, Any +from typing import Dict, Iterable, List, Optional from base64 import b64encode from fastapi import FastAPI, Request @@ -36,6 +38,8 @@ from opentelemetry.sdk.metrics.export import ( PeriodicExportingMetricReader, ) from opentelemetry.sdk.resources import Resource +from sqlalchemy import Engine, func, select +from sqlalchemy.orm import Session from open_webui.env import ( OTEL_SERVICE_NAME, @@ -46,7 +50,47 @@ from open_webui.env import ( OTEL_METRICS_EXPORTER_OTLP_INSECURE, OTEL_METRICS_EXPORT_INTERVAL_MILLIS, ) -from open_webui.models.users import Users +from open_webui.models.users import User + +logger = logging.getLogger(__name__) + + +# --------------------------------------------------------------------------- +# Sync DB helpers for OTel gauge callbacks +# +# The OTel Python SDK calls observable-instrument callbacks *synchronously* +# from a background collection thread — async callbacks are NOT supported +# (the SDK does not ``await`` the return value). +# +# Rather than bridging into the async event loop, we run plain synchronous +# SQL queries using the sync engine that is already available at setup time. +# This avoids any cross-thread / cross-loop concerns entirely. +# --------------------------------------------------------------------------- + + +def _count_total_users(db_engine: Engine) -> Optional[int]: + """Return the total number of registered users (sync).""" + with Session(db_engine) as session: + return session.execute(select(func.count()).select_from(User)).scalar() + + +def _count_active_users(db_engine: Engine) -> Optional[int]: + """Return the number of users active within the last 3 minutes (sync).""" + three_minutes_ago = int(time.time()) - 180 + with Session(db_engine) as session: + return session.execute( + select(func.count()).select_from(User).filter(User.last_active_at >= three_minutes_ago) + ).scalar() + + +def _count_users_active_today(db_engine: Engine) -> Optional[int]: + """Return the number of users active since midnight today (sync).""" + now = int(datetime.datetime.now().timestamp()) + today_midnight = now - (now % 86400) + with Session(db_engine) as session: + return session.execute( + select(func.count()).select_from(User).filter(User.last_active_at > today_midnight) + ).scalar() def _build_meter_provider(resource: Resource) -> MeterProvider: @@ -106,7 +150,7 @@ def _build_meter_provider(resource: Resource) -> MeterProvider: return provider -def setup_metrics(app: FastAPI, resource: Resource) -> None: +def setup_metrics(app: FastAPI, resource: Resource, db_engine: Engine) -> None: """Attach OTel metrics middleware to *app* and initialise provider.""" metrics.set_meter_provider(_build_meter_provider(resource)) @@ -124,32 +168,46 @@ def setup_metrics(app: FastAPI, resource: Resource) -> None: unit='ms', ) - async def observe_active_users( - options: metrics.CallbackOptions, - ) -> Sequence[metrics.Observation]: - return [ - metrics.Observation( - value=await Users.get_active_user_count(), - ) - ] + # -- Observable gauge callbacks ---------------------------------------- + # These are called synchronously by the OTel SDK from a background + # collection thread. They use the sync DB engine directly — no async + # bridging required. - async def observe_total_registered_users( + def observe_total_users( options: metrics.CallbackOptions, - ) -> Sequence[metrics.Observation]: - # IMPORTANT: Use get_num_users() for efficient COUNT(*) query. - # Do NOT use len(get_users()["users"]) - it loads ALL user records into memory, - # causing connection pool exhaustion on high-latency databases (e.g., Aurora). - return [ - metrics.Observation( - value=await Users.get_num_users() or 0, - ) - ] + ) -> Iterable[metrics.Observation]: + try: + value = _count_total_users(db_engine) + if value is not None: + yield metrics.Observation(value=value) + except Exception: + logger.debug('Failed to observe total users', exc_info=True) + + def observe_active_users( + options: metrics.CallbackOptions, + ) -> Iterable[metrics.Observation]: + try: + value = _count_active_users(db_engine) + if value is not None: + yield metrics.Observation(value=value) + except Exception: + logger.debug('Failed to observe active users', exc_info=True) + + def observe_users_active_today( + options: metrics.CallbackOptions, + ) -> Iterable[metrics.Observation]: + try: + value = _count_users_active_today(db_engine) + if value is not None: + yield metrics.Observation(value=value) + except Exception: + logger.debug('Failed to observe users active today', exc_info=True) meter.create_observable_gauge( name='webui.users.total', description='Total number of registered users', unit='users', - callbacks=[observe_total_registered_users], + callbacks=[observe_total_users], ) meter.create_observable_gauge( @@ -159,11 +217,6 @@ def setup_metrics(app: FastAPI, resource: Resource) -> None: callbacks=[observe_active_users], ) - async def observe_users_active_today( - options: metrics.CallbackOptions, - ) -> Sequence[metrics.Observation]: - return [metrics.Observation(value=await Users.get_num_users_active_today())] - meter.create_observable_gauge( name='webui.users.active.today', description='Number of users active since midnight today', diff --git a/backend/open_webui/utils/telemetry/setup.py b/backend/open_webui/utils/telemetry/setup.py index 744dced2d0..14f10ef97f 100644 --- a/backend/open_webui/utils/telemetry/setup.py +++ b/backend/open_webui/utils/telemetry/setup.py @@ -55,4 +55,4 @@ def setup(app: FastAPI, db_engine: Engine): # set up metrics only if enabled if ENABLE_OTEL_METRICS: - setup_metrics(app, resource) + setup_metrics(app, resource, db_engine) From d0e51bde5d23a23c8bcfe526bf2f6f4aca0ac557 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:03:29 +0900 Subject: [PATCH 363/404] refac --- backend/open_webui/routers/audio.py | 17 ++++++++++------- src/lib/components/admin/Settings/Audio.svelte | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py index 5260bd873c..c69be124e5 100644 --- a/backend/open_webui/routers/audio.py +++ b/backend/open_webui/routers/audio.py @@ -576,7 +576,7 @@ async def speech(request: Request, user=Depends(get_verified_user)): async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: mistral_payload = { 'input': payload.get('input', ''), - 'model': request.app.state.config.TTS_MODEL or 'mistral-tts-latest', + 'model': request.app.state.config.TTS_MODEL or 'voxtral-mini-tts-2603', 'voice_id': payload.get('voice', ''), 'response_format': 'mp3', } @@ -1345,7 +1345,7 @@ async def get_available_models(request: Request) -> list[dict]: except Exception as e: log.error(f'Error fetching models: {str(e)}') elif request.app.state.config.TTS_ENGINE == 'mistral': - available_models = [{'id': 'mistral-tts-latest'}] + available_models = [{'id': 'voxtral-mini-tts-2603'}] return available_models @@ -1431,11 +1431,14 @@ async def get_available_voices(request) -> dict: response.raise_for_status() voices_data = await response.json() - for voice in voices_data: - voice_id = voice.get('voice_id', voice.get('id', '')) - voice_name = voice.get('name', voice_id) - if voice_id: - available_voices[voice_id] = voice_name + # Mistral returns a paginated response: {"items": [...], "page": ..., "total": ...} + voices_list = voices_data.get('items', []) if isinstance(voices_data, dict) else voices_data + for voice in voices_list: + if isinstance(voice, dict): + voice_id = voice.get('voice_id', voice.get('id', '')) + voice_name = voice.get('name', voice_id) + if voice_id: + available_voices[voice_id] = voice_name except Exception as e: log.error(f'Error fetching Mistral voices: {str(e)}') diff --git a/src/lib/components/admin/Settings/Audio.svelte b/src/lib/components/admin/Settings/Audio.svelte index 427f2e6965..271c5b8fa9 100644 --- a/src/lib/components/admin/Settings/Audio.svelte +++ b/src/lib/components/admin/Settings/Audio.svelte @@ -525,7 +525,7 @@ TTS_MODEL = 'tts-1'; } else if (e.target?.value === 'mistral') { TTS_VOICE = ''; - TTS_MODEL = 'mistral-tts-latest'; + TTS_MODEL = 'voxtral-mini-tts-2603'; } else { TTS_VOICE = ''; TTS_MODEL = ''; From 0e311a95a7ba953aceaa1eac3525af83fe2fb980 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:16:37 +0900 Subject: [PATCH 364/404] refac --- backend/open_webui/retrieval/web/firecrawl.py | 4 ++-- backend/open_webui/retrieval/web/utils.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/retrieval/web/firecrawl.py b/backend/open_webui/retrieval/web/firecrawl.py index 4af302c0de..8cd18e1ef2 100644 --- a/backend/open_webui/retrieval/web/firecrawl.py +++ b/backend/open_webui/retrieval/web/firecrawl.py @@ -30,7 +30,7 @@ def search_firecrawl( timeout=count * 3 + 10, ) response.raise_for_status() - data = response.json().get('data', {}) + data = response.json().get('data', []) results = [ SearchResult( @@ -38,7 +38,7 @@ def search_firecrawl( title=r.get('title', ''), snippet=r.get('description', ''), ) - for r in data.get('web', []) + for r in (data if isinstance(data, list) else []) ] if filter_list: diff --git a/backend/open_webui/retrieval/web/utils.py b/backend/open_webui/retrieval/web/utils.py index cd5c3a946d..9cb0c1abd7 100644 --- a/backend/open_webui/retrieval/web/utils.py +++ b/backend/open_webui/retrieval/web/utils.py @@ -5,6 +5,8 @@ import socket import ssl import urllib.parse import urllib.request + +import requests from datetime import datetime, time, timedelta from typing import ( Any, From 58bc254809bac2432f1af6927e2cf24e09707d51 Mon Sep 17 00:00:00 2001 From: goodbey857 <76645482+goodbey857@users.noreply.github.com> Date: Fri, 24 Apr 2026 14:19:37 +0800 Subject: [PATCH 365/404] feat: add PaddleOCR-vl loader support and implement retrieval router infrastructure (#23945) Co-authored-by: Tim Baek Co-authored-by: joaoback <156559121+joaoback@users.noreply.github.com> --- README.md | 2 +- backend/open_webui/config.py | 12 ++ backend/open_webui/main.py | 4 + backend/open_webui/retrieval/loaders/main.py | 11 +- .../retrieval/loaders/paddleocr_vl.py | 127 ++++++++++++++++++ backend/open_webui/retrieval/utils.py | 2 + backend/open_webui/routers/retrieval.py | 16 +++ .../admin/Settings/Documents.svelte | 21 +++ src/lib/i18n/locales/en-US/translation.json | 3 + src/lib/i18n/locales/zh-CN/translation.json | 3 + 10 files changed, 199 insertions(+), 2 deletions(-) create mode 100644 backend/open_webui/retrieval/loaders/paddleocr_vl.py diff --git a/README.md b/README.md index 1885f4f6f1..3c4bee98c9 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ For more information, be sure to check out our [Open WebUI Documentation](https: - 💾 **Persistent Artifact Storage**: Built-in key-value storage API for artifacts, enabling features like journals, trackers, leaderboards, and collaborative tools with both personal and shared data scopes across sessions. -- 📚 **Local RAG Integration**: Dive into the future of chat interactions with groundbreaking Retrieval Augmented Generation (RAG) support using your choice of 9 vector databases and multiple content extraction engines (Tika, Docling, Document Intelligence, Mistral OCR, External loaders). Load documents directly into chat or add files to your document library, effortlessly accessing them using the `#` command before a query. +- 📚 **Local RAG Integration**: Dive into the future of chat interactions with groundbreaking Retrieval Augmented Generation (RAG) support using your choice of 9 vector databases and multiple content extraction engines (Tika, Docling, Document Intelligence, Mistral OCR, PaddleOCR-vl, External loaders). Load documents directly into chat or add files to your document library, effortlessly accessing them using the `#` command before a query. - 🔍 **Web Search for RAG**: Perform web searches using 15+ providers including `SearXNG`, `Google PSE`, `Brave Search`, `Kagi`, `Mojeek`, `Tavily`, `Perplexity`, `serpstack`, `serper`, `Serply`, `DuckDuckGo`, `SearchApi`, `SerpApi`, `Bing`, `Jina`, `Exa`, `Sougou`, `Azure AI Search`, and `Ollama Cloud`, injecting results directly into your chat experience. diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index d2c88cb2fb..06178d385c 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -2827,6 +2827,18 @@ MISTRAL_OCR_API_KEY = PersistentConfig( os.getenv('MISTRAL_OCR_API_KEY', ''), ) +PADDLEOCR_VL_BASE_URL = PersistentConfig( + 'PADDLEOCR_VL_BASE_URL', + 'rag.paddleocr_vl_base_url', + os.getenv('PADDLEOCR_VL_BASE_URL', 'http://localhost:8080'), +) + +PADDLEOCR_VL_TOKEN = PersistentConfig( + 'PADDLEOCR_VL_TOKEN', + 'rag.paddleocr_vl_token', + os.getenv('PADDLEOCR_VL_TOKEN', ''), +) + BYPASS_EMBEDDING_AND_RETRIEVAL = PersistentConfig( 'BYPASS_EMBEDDING_AND_RETRIEVAL', 'rag.bypass_embedding_and_retrieval', diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index ba7f74c830..d6f4f4c7af 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -303,6 +303,8 @@ from open_webui.config import ( DOCUMENT_INTELLIGENCE_MODEL, MISTRAL_OCR_API_BASE_URL, MISTRAL_OCR_API_KEY, + PADDLEOCR_VL_BASE_URL, + PADDLEOCR_VL_TOKEN, RAG_TEXT_SPLITTER, ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER, TIKTOKEN_ENCODING_NAME, @@ -1023,6 +1025,8 @@ app.state.config.DOCUMENT_INTELLIGENCE_KEY = DOCUMENT_INTELLIGENCE_KEY app.state.config.DOCUMENT_INTELLIGENCE_MODEL = DOCUMENT_INTELLIGENCE_MODEL app.state.config.MISTRAL_OCR_API_BASE_URL = MISTRAL_OCR_API_BASE_URL app.state.config.MISTRAL_OCR_API_KEY = MISTRAL_OCR_API_KEY +app.state.config.PADDLEOCR_VL_BASE_URL = PADDLEOCR_VL_BASE_URL +app.state.config.PADDLEOCR_VL_TOKEN = PADDLEOCR_VL_TOKEN app.state.config.MINERU_API_MODE = MINERU_API_MODE app.state.config.MINERU_API_URL = MINERU_API_URL app.state.config.MINERU_API_KEY = MINERU_API_KEY diff --git a/backend/open_webui/retrieval/loaders/main.py b/backend/open_webui/retrieval/loaders/main.py index 7dc9df37ce..27c81f7f81 100644 --- a/backend/open_webui/retrieval/loaders/main.py +++ b/backend/open_webui/retrieval/loaders/main.py @@ -23,7 +23,7 @@ from open_webui.retrieval.loaders.external_document import ExternalDocumentLoade from open_webui.retrieval.loaders.mistral import MistralLoader from open_webui.retrieval.loaders.datalab_marker import DatalabMarkerLoader from open_webui.retrieval.loaders.mineru import MinerULoader - +from open_webui.retrieval.loaders.paddleocr_vl import PaddleOCRVLLoader from open_webui.env import GLOBAL_LOG_LEVEL, REQUESTS_VERIFY @@ -399,6 +399,15 @@ class Loader: api_key=self.kwargs.get('MISTRAL_OCR_API_KEY'), file_path=file_path, ) + elif ( + self.engine == 'paddleocr_vl' + and self.kwargs.get('PADDLEOCR_VL_TOKEN') != '' + ): + loader = PaddleOCRVLLoader( + api_url=self.kwargs.get('PADDLEOCR_VL_BASE_URL'), + token=self.kwargs.get('PADDLEOCR_VL_TOKEN'), + file_path=file_path, + ) else: if file_ext == 'pdf': loader = PyPDFLoader( diff --git a/backend/open_webui/retrieval/loaders/paddleocr_vl.py b/backend/open_webui/retrieval/loaders/paddleocr_vl.py new file mode 100644 index 0000000000..ab7632b3f8 --- /dev/null +++ b/backend/open_webui/retrieval/loaders/paddleocr_vl.py @@ -0,0 +1,127 @@ +import base64 +import os +import requests +import logging +import sys +from typing import List + +from langchain_core.documents import Document +from open_webui.env import GLOBAL_LOG_LEVEL + +logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) +log = logging.getLogger(__name__) + +class PaddleOCRVLLoader: + """Loader that uses PaddleOCR-vl API to extract text from PDF/images.""" + + def __init__( + self, + api_url: str, + token: str, + file_path: str, + ): + if not api_url or not token: + raise ValueError("PaddleOCR-vl API URL and Token are required.") + if not os.path.exists(file_path): + raise FileNotFoundError(f"File not found at {file_path}") + + self.api_url = api_url.rstrip('/') + self.token = token + self.file_path = file_path + self.file_name = os.path.basename(file_path) + + def load(self) -> List[Document]: + log.info(f"Processing with PaddleOCR-vl: {self.file_path}") + + try: + with open(self.file_path, "rb") as file: + file_bytes = file.read() + file_data = base64.b64encode(file_bytes).decode("ascii") + except Exception as e: + log.error(f"Failed to read file {self.file_path}: {e}") + raise + + headers = { + "Authorization": f"token {self.token}", + "Content-Type": "application/json" + } + + # Detect fileType based on file extension + ext = self.file_path.lower().split('.')[-1] + image_extensions = ['png', 'jpg', 'jpeg', 'bmp', 'tiff', 'webp'] + file_type = 1 if ext in image_extensions else 0 + + payload = { + "file": file_data, + "fileType": file_type, + "useDocOrientationClassify": False, + "useDocUnwarping": False, + "useChartRecognition": False, + } + + try: + response = requests.post(f"{self.api_url}/layout-parsing", json=payload, headers=headers) + response.raise_for_status() + + result = response.json().get("result", {}) + layout_results = result.get("layoutParsingResults", []) + + documents = [] + total_pages = len(layout_results) + skipped_pages = 0 + + for i, res in enumerate(layout_results): + markdown_text = res.get("markdown", {}).get("text", "") + + if isinstance(markdown_text, str): + cleaned_content = markdown_text.strip() + else: + cleaned_content = str(markdown_text).strip() + + if not cleaned_content: + skipped_pages += 1 + continue + + documents.append( + Document( + page_content=cleaned_content, + metadata={ + "page": i, + "page_label": i + 1, + "total_pages": total_pages, + "file_name": self.file_name, + "processing_engine": "paddleocr-vl" + } + ) + ) + + if skipped_pages > 0: + log.info(f"PaddleOCR-vl: Processed {len(documents)} pages, skipped {skipped_pages} empty pages.") + + if not documents: + log.warning("No valid text content found by PaddleOCR-vl.") + return [ + Document( + page_content="No valid text content found in document", + metadata={ + "error": "no_valid_pages", + "file_name": self.file_name, + "processing_engine": "paddleocr-vl" + } + ) + ] + + return documents + + except Exception as e: + log.error(f"Error calling PaddleOCR-vl: {e}") + return [ + Document( + page_content=f"Error during OCR processing: {e}", + metadata={ + "error": "processing_failed", + "file_name": self.file_name, + "processing_engine": "paddleocr-vl" + } + ) + ] diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index fb5a46c2b0..b1aec78656 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -114,6 +114,8 @@ def build_loader_from_config(request): DOCUMENT_INTELLIGENCE_MODEL=config.DOCUMENT_INTELLIGENCE_MODEL, MISTRAL_OCR_API_BASE_URL=config.MISTRAL_OCR_API_BASE_URL, MISTRAL_OCR_API_KEY=config.MISTRAL_OCR_API_KEY, + PADDLEOCR_VL_BASE_URL=config.PADDLEOCR_VL_BASE_URL, + PADDLEOCR_VL_TOKEN=config.PADDLEOCR_VL_TOKEN, MINERU_API_MODE=config.MINERU_API_MODE, MINERU_API_URL=config.MINERU_API_URL, MINERU_API_KEY=config.MINERU_API_KEY, diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index fea00143e6..01ef1d8886 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -480,6 +480,8 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): 'DOCUMENT_INTELLIGENCE_MODEL': request.app.state.config.DOCUMENT_INTELLIGENCE_MODEL, 'MISTRAL_OCR_API_BASE_URL': request.app.state.config.MISTRAL_OCR_API_BASE_URL, 'MISTRAL_OCR_API_KEY': request.app.state.config.MISTRAL_OCR_API_KEY, + 'PADDLEOCR_VL_BASE_URL': request.app.state.config.PADDLEOCR_VL_BASE_URL, + 'PADDLEOCR_VL_TOKEN': request.app.state.config.PADDLEOCR_VL_TOKEN, # MinerU settings 'MINERU_API_MODE': request.app.state.config.MINERU_API_MODE, 'MINERU_API_URL': request.app.state.config.MINERU_API_URL, @@ -686,6 +688,8 @@ class ConfigForm(BaseModel): DOCUMENT_INTELLIGENCE_MODEL: Optional[str] = None MISTRAL_OCR_API_BASE_URL: Optional[str] = None MISTRAL_OCR_API_KEY: Optional[str] = None + PADDLEOCR_VL_BASE_URL: Optional[str] = None + PADDLEOCR_VL_TOKEN: Optional[str] = None # MinerU settings MINERU_API_MODE: Optional[str] = None @@ -887,6 +891,16 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend if form_data.MISTRAL_OCR_API_KEY is not None else request.app.state.config.MISTRAL_OCR_API_KEY ) + request.app.state.config.PADDLEOCR_VL_BASE_URL = ( + form_data.PADDLEOCR_VL_BASE_URL + if form_data.PADDLEOCR_VL_BASE_URL is not None + else request.app.state.config.PADDLEOCR_VL_BASE_URL + ) + request.app.state.config.PADDLEOCR_VL_TOKEN = ( + form_data.PADDLEOCR_VL_TOKEN + if form_data.PADDLEOCR_VL_TOKEN is not None + else request.app.state.config.PADDLEOCR_VL_TOKEN + ) # MinerU settings request.app.state.config.MINERU_API_MODE = ( @@ -1152,6 +1166,8 @@ async def update_rag_config(request: Request, form_data: ConfigForm, user=Depend 'DOCUMENT_INTELLIGENCE_MODEL': request.app.state.config.DOCUMENT_INTELLIGENCE_MODEL, 'MISTRAL_OCR_API_BASE_URL': request.app.state.config.MISTRAL_OCR_API_BASE_URL, 'MISTRAL_OCR_API_KEY': request.app.state.config.MISTRAL_OCR_API_KEY, + 'PADDLEOCR_VL_BASE_URL': request.app.state.config.PADDLEOCR_VL_BASE_URL, + 'PADDLEOCR_VL_TOKEN': request.app.state.config.PADDLEOCR_VL_TOKEN, # MinerU settings 'MINERU_API_MODE': request.app.state.config.MINERU_API_MODE, 'MINERU_API_URL': request.app.state.config.MINERU_API_URL, diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index eeb6b18b10..a2349e78e5 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -184,6 +184,13 @@ toast.error($i18n.t('Mistral OCR API Key required.')); return; } + if ( + RAGConfig.CONTENT_EXTRACTION_ENGINE === 'paddleocr_vl' && + RAGConfig.PADDLEOCR_VL_BASE_URL === '' + ) { + toast.error($i18n.t('PaddleOCR-vl API URL required.')); + return; + } if ( RAGConfig.CONTENT_EXTRACTION_ENGINE === 'mineru' && @@ -356,6 +363,7 @@ +
@@ -657,6 +665,19 @@ bind:value={RAGConfig.MISTRAL_OCR_API_KEY} />
+ {:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'paddleocr_vl'} +
+ + +
{:else if RAGConfig.CONTENT_EXTRACTION_ENGINE === 'mineru'}
diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index ad0f42f733..36ad93ad61 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -775,6 +775,8 @@ "Enter prompt here.": "", "Enter proxy URL (e.g. https://user:password@host:port)": "", "Enter reasoning effort": "", + "Enter PaddleOCR-vl API Token": "", + "Enter PaddleOCR-vl API Base URL": "", "Enter Score": "", "Enter SearchApi API Key": "", "Enter SearchApi Engine": "", @@ -1518,6 +1520,7 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index ce09ad948c..9678d24eeb 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -774,6 +774,8 @@ "Enter prompt here.": "在此输入提示词。", "Enter proxy URL (e.g. https://user:password@host:port)": "输入代理地址(例如:https://用户名:密码@主机名:端口)", "Enter reasoning effort": "输入推理努力", + "Enter PaddleOCR-vl API Token": "输入 PaddleOCR-vl 接口密钥", + "Enter PaddleOCR-vl API Base URL": "输入 PaddleOCR-vl API 基础地址", "Enter Score": "输入评分", "Enter SearchApi API Key": "输入 SearchApi 接口密钥", "Enter SearchApi Engine": "输入 SearchApi 引擎", @@ -1517,6 +1519,7 @@ "Output format": "输出格式", "Output Format": "输出格式", "Overview": "概述", + "PaddleOCR-vl": "PaddleOCR-vl", "page": "页", "Page": "页模式", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "页模式将为每个页面创建一个文档;单文档模式则将所有页面合并为一个文档,以便更好地进行跨页分块。", From 90584ab6f317ea71719dc0a5dfce8a2418f17fb6 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:21:37 +0900 Subject: [PATCH 366/404] refac --- backend/open_webui/main.py | 74 +++++++++++++------------- backend/open_webui/utils/middleware.py | 50 ++++++++++------- 2 files changed, 67 insertions(+), 57 deletions(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index d6f4f4c7af..d75f1af4f4 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1869,17 +1869,15 @@ async def chat_completion( except asyncio.CancelledError: log.info('Chat processing was cancelled') try: - event_emitter = await get_event_emitter(metadata) - if event_emitter: - await asyncio.shield( - event_emitter( - {'type': 'chat:tasks:cancel'}, - ) - ) - except Exception as e: + async def emit_cancel_event(): + event_emitter = await get_event_emitter(metadata) + if event_emitter: + await event_emitter({'type': 'chat:tasks:cancel'}) + + await asyncio.shield(emit_cancel_event()) + except Exception: pass - finally: - raise # re-raise to ensure proper task cancellation handling + raise # re-raise to ensure proper task cancellation handling except Exception as e: error_detail = e.detail if isinstance(e, HTTPException) else str(e) log.error('Error processing chat payload: %s', error_detail) @@ -1911,36 +1909,38 @@ async def chat_completion( except Exception: pass finally: - # Clean up MCP clients. Shield the entire block from - # CancelledError so disconnect() can finish even when the - # task is being stopped. Each client is isolated so one - # failure doesn't skip the rest. - try: - if mcp_clients := metadata.get('mcp_clients'): + # Clean up MCP clients and emit chat:active=false. + # Shield the entire block from CancelledError so cleanup + # can finish even when the task is being stopped. + async def cleanup_process_chat(): + try: + if mcp_clients := metadata.get('mcp_clients'): - async def _cleanup_mcp(): - for client in reversed(list(mcp_clients.values())): - try: - await client.disconnect() - except Exception as e: - log.debug(f'Error disconnecting MCP client: {e}') + async def cleanup_mcp_clients(): + for client in reversed(list(mcp_clients.values())): + try: + await client.disconnect() + except Exception as e: + log.debug(f'Error disconnecting MCP client: {e}') + + await asyncio.wait_for(cleanup_mcp_clients(), timeout=10.0) + except asyncio.TimeoutError: + log.warning('MCP client cleanup timed out after 10 s') + except Exception as e: + log.debug(f'Error cleaning up MCP clients: {e}') + + try: + if metadata.get('chat_id'): + event_emitter = await get_event_emitter(metadata, update_db=False) + if event_emitter: + await event_emitter({'type': 'chat:active', 'data': {'active': False}}) + except Exception as e: + log.debug(f'Error emitting chat:active: {e}') - await asyncio.wait_for( - asyncio.shield(_cleanup_mcp()), - timeout=10.0, - ) - except asyncio.TimeoutError: - log.warning('MCP client cleanup timed out after 10 s') - except Exception as e: - log.debug(f'Error cleaning up MCP clients: {e}') - # Emit chat:active=false when task completes try: - if metadata.get('chat_id'): - event_emitter = await get_event_emitter(metadata, update_db=False) - if event_emitter: - await event_emitter({'type': 'chat:active', 'data': {'active': False}}) - except Exception as e: - log.debug(f'Error emitting chat:active: {e}') + await asyncio.shield(cleanup_process_chat()) + except (asyncio.CancelledError, Exception): + pass # Fan out: one task per model if metadata.get('session_id') and metadata.get('chat_id'): diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 8d3b6dd267..fa6c65f36d 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -4269,6 +4269,8 @@ async def streaming_chat_response_handler(response, ctx): 'data': data, } ) + except (asyncio.CancelledError, KeyboardInterrupt): + raise except Exception as e: done = 'data: [DONE]' in line if done: @@ -4971,31 +4973,39 @@ async def streaming_chat_response_handler(response, ctx): await outlet_filter_handler(ctx) except asyncio.CancelledError: log.warning('Task was cancelled!') - try: - await asyncio.shield(event_emitter({'type': 'chat:tasks:cancel'})) + # Close the response body iterator to trigger cleanup + # in stream_wrapper's finally block and release the + # upstream connection. Without this, the async + # generator is orphaned and may spin in anyio internals. + if hasattr(response, 'body_iterator') and hasattr(response.body_iterator, 'aclose'): + try: + await asyncio.shield(response.body_iterator.aclose()) + except (asyncio.CancelledError, Exception): + pass + + async def save_cancelled_state(): + await event_emitter({'type': 'chat:tasks:cancel'}) if not ENABLE_REALTIME_CHAT_SAVE: - # Save message in the database - await asyncio.shield( - Chats.upsert_message_to_chat_by_id_and_message_id( - metadata['chat_id'], - metadata['message_id'], - { - 'done': True, - 'content': serialize_output(output), - 'output': output, - }, - ) + await Chats.upsert_message_to_chat_by_id_and_message_id( + metadata['chat_id'], + metadata['message_id'], + { + 'done': True, + 'content': serialize_output(output), + 'output': output, + }, ) else: - await asyncio.shield( - Chats.upsert_message_to_chat_by_id_and_message_id( - metadata['chat_id'], - metadata['message_id'], - {'done': True}, - ) + await Chats.upsert_message_to_chat_by_id_and_message_id( + metadata['chat_id'], + metadata['message_id'], + {'done': True}, ) - except Exception: + + try: + await asyncio.shield(save_cancelled_state()) + except (asyncio.CancelledError, Exception): pass raise # re-raise CancelledError for proper propagation From 6ecba194474d770225da6a9b2cb6a067204b0719 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:21:52 +0900 Subject: [PATCH 367/404] refac --- backend/open_webui/utils/redis.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/utils/redis.py b/backend/open_webui/utils/redis.py index cb570cb45a..e14a0079ec 100644 --- a/backend/open_webui/utils/redis.py +++ b/backend/open_webui/utils/redis.py @@ -21,6 +21,8 @@ from open_webui.env import ( log = logging.getLogger(__name__) +MAX_RETRY_COUNT = REDIS_SENTINEL_MAX_RETRY_COUNT + # Let not our connections be timed out but deliver them from # partition. For the cache and the socket and the uptime @@ -38,7 +40,7 @@ class SentinelRedisProxy: def _master(self): return self._sentinel.master_for(self._service, **self._kw) - async def __getattr__(self, item): + def __getattr__(self, item): master = self._master() orig_attr = getattr(master, item) From 258e9f917bc17def60e0800d5872396da9427e18 Mon Sep 17 00:00:00 2001 From: Jacob Leksan <63938553+jmleksan@users.noreply.github.com> Date: Fri, 24 Apr 2026 02:25:54 -0400 Subject: [PATCH 368/404] Enhance image loading performance by adding preload links and setting loading attributes for logos in app.html (#24011) --- src/app.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/app.html b/src/app.html index d75d1ead00..285164d02f 100644 --- a/src/app.html +++ b/src/app.html @@ -71,6 +71,16 @@ metaThemeColorTag.setAttribute('content', '#171717'); } + const preloadHref = document.documentElement.classList.contains('dark') + ? '/static/splash-dark.png' + : '/static/splash.png'; + const preload = document.createElement('link'); + preload.rel = 'preload'; + preload.as = 'image'; + preload.href = preloadHref; + preload.setAttribute('fetchpriority', 'high'); + document.head.appendChild(preload); + window.matchMedia('(prefers-color-scheme: dark)').addListener((e) => { if (localStorage.theme === 'system') { if (e.matches) { @@ -90,6 +100,8 @@ logo.id = 'logo'; logo.style = 'position: absolute; width: auto; height: 6rem; top: 44%; left: 50%; transform: translateX(-50%); display:block;'; + logo.loading = 'eager'; + logo.fetchPriority = 'high'; logo.src = isDarkMode ? '/static/splash-dark.png' : '/static/splash.png'; document.addEventListener('DOMContentLoaded', function () { @@ -139,6 +151,8 @@ id="logo-her" style="width: auto; height: 13rem" src="/static/splash.png" + loading="eager" + fetchpriority="high" class="animate-pulse-fast" /> From b73538ece7611902f86d5b1152eeccc3b31d1bde Mon Sep 17 00:00:00 2001 From: RomualdYT Date: Fri, 24 Apr 2026 08:26:53 +0200 Subject: [PATCH 369/404] feat(ui): add citation source overflow badge (#23918) --- src/lib/components/chat/Messages/Citations.svelte | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/lib/components/chat/Messages/Citations.svelte b/src/lib/components/chat/Messages/Citations.svelte index 8f0d93ce6d..fab5dae51e 100644 --- a/src/lib/components/chat/Messages/Citations.svelte +++ b/src/lib/components/chat/Messages/Citations.svelte @@ -183,6 +183,14 @@ }} /> {/each} + {#if citations.length > 3} + + {/if}
{/if}
From b87c7555740dc87c69eea9704750bbbfdcb3db0f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:29:36 +0900 Subject: [PATCH 370/404] refac --- backend/open_webui/main.py | 50 +++++++++++--------------- backend/open_webui/utils/mcp/client.py | 22 ++++++------ 2 files changed, 31 insertions(+), 41 deletions(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index d75f1af4f4..b56659e721 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1909,37 +1909,29 @@ async def chat_completion( except Exception: pass finally: - # Clean up MCP clients and emit chat:active=false. - # Shield the entire block from CancelledError so cleanup - # can finish even when the task is being stopped. - async def cleanup_process_chat(): - try: - if mcp_clients := metadata.get('mcp_clients'): - - async def cleanup_mcp_clients(): - for client in reversed(list(mcp_clients.values())): - try: - await client.disconnect() - except Exception as e: - log.debug(f'Error disconnecting MCP client: {e}') - - await asyncio.wait_for(cleanup_mcp_clients(), timeout=10.0) - except asyncio.TimeoutError: - log.warning('MCP client cleanup timed out after 10 s') - except Exception as e: - log.debug(f'Error cleaning up MCP clients: {e}') - - try: - if metadata.get('chat_id'): - event_emitter = await get_event_emitter(metadata, update_db=False) - if event_emitter: - await event_emitter({'type': 'chat:active', 'data': {'active': False}}) - except Exception as e: - log.debug(f'Error emitting chat:active: {e}') + # MCP cleanup — MUST run in the SAME asyncio task as + # connect() because the MCP SDK's streamablehttp_client + # uses anyio task groups whose cancel scopes enforce + # same-task exit. Do NOT wrap in asyncio.shield() or + # asyncio.wait_for() — both create a new task. + # MCPClient.disconnect() self-shields via + # anyio.CancelScope(shield=True). + try: + if mcp_clients := metadata.get('mcp_clients'): + for client in reversed(list(mcp_clients.values())): + try: + await client.disconnect() + except Exception as e: + log.debug(f'Error disconnecting MCP client: {e}') + except Exception as e: + log.debug(f'Error cleaning up MCP clients: {e}') try: - await asyncio.shield(cleanup_process_chat()) - except (asyncio.CancelledError, Exception): + if metadata.get('chat_id'): + event_emitter = await get_event_emitter(metadata, update_db=False) + if event_emitter: + await event_emitter({'type': 'chat:active', 'data': {'active': False}}) + except Exception: pass # Fan out: one task per model diff --git a/backend/open_webui/utils/mcp/client.py b/backend/open_webui/utils/mcp/client.py index effe4b1637..759bcc0a31 100644 --- a/backend/open_webui/utils/mcp/client.py +++ b/backend/open_webui/utils/mcp/client.py @@ -155,20 +155,18 @@ class MCPClient: self.session = None try: - await asyncio.wait_for( - asyncio.shield(exit_stack.aclose()), - timeout=5.0, - ) - except asyncio.TimeoutError: + # IMPORTANT: Do NOT use asyncio.shield() or asyncio.wait_for() + # here — both create a new asyncio task. The MCP SDK's + # streamablehttp_client uses anyio task groups / cancel scopes + # that MUST be exited in the same task they were entered in. + # Using anyio.CancelScope(shield=True) protects from + # CancelledError while staying in the current task. + with anyio.CancelScope(shield=True): + with anyio.fail_after(5.0): + await exit_stack.aclose() + except TimeoutError: log.warning('MCPClient.disconnect() timed out after 5 s') except RuntimeError as exc: - # The MCP SDK's streamable_http transport uses anyio task - # groups and async generators internally. When we close - # a session that was interrupted mid-flight these can - # raise RuntimeError ("aclose(): asynchronous generator is - # already running" or "Attempted to exit cancel scope in a - # different task"). Swallowing the error here prevents the - # orphaned coroutines from spinning at 100 % CPU. log.debug('MCPClient.disconnect() suppressed RuntimeError: %s', exc) except Exception as exc: log.debug('MCPClient.disconnect() error: %s', exc) From 6089de0b1790275d13834a62c5598611217b7147 Mon Sep 17 00:00:00 2001 From: Lucas Date: Fri, 24 Apr 2026 08:30:06 +0200 Subject: [PATCH 371/404] i18n: enhance and expand Dutch language translations (#23944) --- src/lib/i18n/locales/nl-NL/translation.json | 2454 +++++++++---------- 1 file changed, 1227 insertions(+), 1227 deletions(-) diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index 4651d33fc5..dbaf9bcb13 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -1,228 +1,228 @@ { - "-1 for no limit, or a positive integer for a specific limit": "-1 voor geen limiet, of een positief getal voor een specifiek limiet", - "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w', of '-1' for geen vervaldatum.", + "-1 for no limit, or a positive integer for a specific limit": "-1 voor geen limiet, of een positief getal voor een specifieke limiet", + "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w', of '-1' voor geen vervaldatum.", "(e.g. `sh webui.sh --api --api-auth username_password`)": "(bv. `sh webui.sh --api --api-auth gebruikersnaam_wachtwoord`)", "(e.g. `sh webui.sh --api`)": "(bv. `sh webui.sh --api`)", "(latest)": "(nieuwste)", - "(leave blank for to use commercial endpoint)": "(laat leeg voor een comercieel endpoint)", - "[Last] dddd [at] h:mm A": "", - "[Today at] h:mm A": "", - "[Yesterday at] h:mm A": "", - "{{ models }}": "{{ modellen }}", + "(leave blank for to use commercial endpoint)": "(laat leeg om een commercieel endpoint te gebruiken)", + "[Last] dddd [at] h:mm A": "[Vorige] dddd [om] h:mm A", + "[Today at] h:mm A": "[Vandaag om] h:mm A", + "[Yesterday at] h:mm A": "[Gisteren om] h:mm A", + "{{ models }}": "{{ models }}", "{{COUNT}} Available Tools": "{{COUNT}} beschikbare tools", "{{COUNT}} characters": "{{COUNT}} karakters", - "{{COUNT}} extracted lines": "", - "{{COUNT}} files": "", + "{{COUNT}} extracted lines": "{{COUNT}} geextraheerde regels", + "{{COUNT}} files": "{{COUNT}} bestanden", "{{COUNT}} hidden lines": "{{COUNT}} verborgen regels", - "{{COUNT}} members": "", + "{{COUNT}} members": "{{COUNT}} leden", "{{COUNT}} Replies": "{{COUNT}} antwoorden", - "{{COUNT}} Rows": "", - "{{count}} selected_one": "", - "{{count}} selected_other": "", - "{{COUNT}} Sources": "", + "{{COUNT}} Rows": "{{COUNT}} rijen", + "{{count}} selected_one": "{{count}} geselecteerd", + "{{count}} selected_other": "{{count}} geselecteerd", + "{{COUNT}} Sources": "{{COUNT}} bronnen", "{{COUNT}} words": "{{COUNT}} woorden", - "{{COUNT}}d_time_ago": "", - "{{COUNT}}h_time_ago": "", - "{{COUNT}}m_time_ago": "", - "{{COUNT}}w_time_ago": "", - "{{COUNT}}y_time_ago": "", - "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "", - "{{model}} download has been canceled": "", - "{{modelName}} profile image": "", - "{{NAMES}} reacted with {{REACTION}}": "", - "{{user}}'s Chats": "{{user}}'s chats", + "{{COUNT}}d_time_ago": "{{COUNT}}d geleden", + "{{COUNT}}h_time_ago": "{{COUNT}}u geleden", + "{{COUNT}}m_time_ago": "{{COUNT}}m geleden", + "{{COUNT}}w_time_ago": "{{COUNT}}w geleden", + "{{COUNT}}y_time_ago": "{{COUNT}}j geleden", + "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "{{LOCALIZED_DATE}} om {{LOCALIZED_TIME}}", + "{{model}} download has been canceled": "Download van {{model}} is geannuleerd", + "{{modelName}} profile image": "Profielafbeelding van {{modelName}}", + "{{NAMES}} reacted with {{REACTION}}": "{{NAMES}} reageerden met {{REACTION}}", + "{{user}}'s Chats": "Chats van {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend verplicht", - "*Prompt node ID(s) are required for image generation": "*Prompt node ID('s) zijn vereist voor het genereren van afbeeldingen", - "1 hour before": "", - "1 Source": "", - "10 minutes before": "", - "15 minutes before": "", - "1m_time_ago": "", - "30 minutes before": "", - "5 minutes before": "", - "A collaboration channel where people join as members": "", - "A discussion channel where access is controlled by groups and permissions": "", + "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) zijn vereist voor het genereren van afbeeldingen", + "1 Source": "1 bron", + "1m_time_ago": "1m geleden", + "A collaboration channel where people join as members": "Een samenwerkingskanaal waar mensen als leden kunnen deelnemen", + "A discussion channel where access is controlled by groups and permissions": "Een discussiekanaal waar toegang wordt beheerd via groepen en machtigingen", + "1 hour before": "1 uur voor", + "10 minutes before": "10 minuten voor", + "15 minutes before": "15 minuten voor", + "30 minutes before": "30 minuten voor", + "5 minutes before": "5 minuten voor", "A new version (v{{LATEST_VERSION}}) is now available.": "Een nieuwe versie (v{{LATEST_VERSION}}) is nu beschikbaar", - "A private conversation between you and selected users": "", + "A private conversation between you and selected users": "Een privégesprek tussen jou en geselecteerde gebruikers", "A task model is used when performing tasks such as generating titles for chats and web search queries": "Een taakmodel wordt gebruikt bij het uitvoeren van taken zoals het genereren van titels voor chats en zoekopdrachten op het internet", "a user": "een gebruiker", "About": "Over", - "Accept Autocomplete Generation\nJump to Prompt Variable": "", + "Accept Autocomplete Generation\nJump to Prompt Variable": "Accepteer automatische aanvulling\nGa naar promptvariabele", "Access": "Toegang", "Access Control": "Toegangsbeheer", - "Access Grants": "", - "Access List": "", - "Access updated": "", + "Access Grants": "Toegangsrechten", + "Access List": "Toegangslijst", + "Access updated": "Toegang bijgewerkt", "Accessible to all users": "Toegankelijk voor alle gebruikers", "Account": "Account", "Account Activation Pending": "Accountactivatie in afwachting", - "Accurate information": "Accurate informatie", + "Accurate information": "Nauwkeurige informatie", "Action": "Actie", - "Action not found": "", + "Action not found": "Actie niet gevonden", "Action Required for Chat Log Storage": "Actie vereist voor het opslaan van het chatlog", "Actions": "Acties", "Activate": "Activeren", "Activate this command by typing \"/{{COMMAND}}\" to chat input.": "Activeer dit commando door \"/{{COMMAND}}\" in de chat te typen", "Active": "Actief", "Active Users": "Actieve gebruikers", - "Activity": "", + "Activity": "Activiteit", "Add": "Toevoegen", "Add a model ID": "Voeg een model-ID toe", "Add a short description about what this model does": "Voeg een korte beschrijving toe over wat dit model doet", "Add a tag": "Voeg een tag toe", - "Add a tag...": "", - "Add Access": "", + "Add a tag...": "Voeg een tag toe...", + "Add Access": "Toegang toevoegen", "Add Arena Model": "Voeg arenamodel toe", "Add Connection": "Voeg verbinding toe", "Add Content": "Voeg content toe", "Add content here": "Voeg hier content toe", - "Add Custom Parameter": "", - "Add Custom Prompt": "", - "Add description": "", - "Add Details": "", + "Add Custom Parameter": "Aangepaste parameter toevoegen", + "Add Custom Prompt": "Aangepaste prompt toevoegen", + "Add Details": "Details toevoegen", "Add Files": "Voeg bestanden toe", - "Add Image": "", - "Add location": "", - "Add Member": "", - "Add Members": "", + "Add Image": "Afbeelding toevoegen", + "Add Member": "Lid toevoegen", + "Add Members": "Leden toevoegen", + "Add description": "Voeg beschrijving toe", + "Add location": "Voeg locatie toe", "Add Memory": "Voeg geheugen toe", "Add Model": "Voeg model toe", "Add Reaction": "Voeg reactie toe", - "Add tag": "", + "Add tag": "Tag toevoegen", "Add Tag": "Voeg tag toe", - "Add Terminal": "", - "Add Terminal Connection": "", + "Add Terminal": "Terminal toevoegen", + "Add Terminal Connection": "Terminalverbinding toevoegen", "Add text content": "Voeg tekstinhoud toe", - "Add to favorites": "", + "Add to favorites": "Aan favorieten toevoegen", "Add User": "Voeg gebruiker toe", "Add User Group": "Voeg gebruikersgroep toe", - "Add webpage": "", - "Add your Open Terminal URL and API key in Settings → Integrations.": "", + "Add webpage": "Webpagina toevoegen", + "Add your Open Terminal URL and API key in Settings → Integrations.": "Voeg je Open Terminal-URL en API-sleutel toe in Instellingen -> Integraties.", "Additional Config": "Extra configuratie", - "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": "", - "Additional feedback comments": "", - "Additional Parameters": "", - "Adds filenames, titles, sections, and snippets into the BM25 text to improve lexical recall.": "", + "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": "Aanvullende configuratieopties voor marker. Dit moet een JSON-string met key-value paren zijn. Bijvoorbeeld: '{\"key\": \"value\"}'. Ondersteunde sleutels zijn: 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": "Aanvullende feedbackopmerkingen", + "Additional Parameters": "Aanvullende parameters", + "Adds filenames, titles, sections, and snippets into the BM25 text to improve lexical recall.": "Voegt bestandsnamen, titels, secties en fragmenten toe aan de BM25-tekst om lexicale herkenning te verbeteren.", "Adjusting these settings will apply changes universally to all users.": "Het aanpassen van deze instellingen zal universeel worden toegepast op alle gebruikers.", "admin": "beheerder", "Admin": "Beheerder", - "Admin Contact Email": "", + "Admin Contact Email": "E-mailadres van beheerder", "Admin Panel": "Beheerderspaneel", "Admin Settings": "Beheerdersinstellingen", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Beheerders hebben altijd toegang tot alle gereedschappen; gebruikers moeten gereedschap toegewezen krijgen per model in de werkruimte.", - "Advanced": "", + "Advanced": "Geavanceerd", "Advanced Parameters": "Geavanceerde parameters", - "Advanced parameters for MinerU parsing (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)": "", + "Advanced parameters for MinerU parsing (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)": "Geavanceerde parameters voor MinerU-parsing (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)", "Advanced Params": "Geavanceerde params", - "After updating or changing the embedding model, you must reindex the knowledge base for the changes to take effect. You can do this using the \"Reindex\" button below.": "", - "AI": "", + "After updating or changing the embedding model, you must reindex the knowledge base for the changes to take effect. You can do this using the \"Reindex\" button below.": "Na het bijwerken of wijzigen van het embeddingmodel moet je de kennisbank opnieuw indexeren voordat de wijzigingen van kracht worden. Je kunt dit doen met de knop \"Reindex\" hieronder.", + "AI": "AI", "All": "Alle", - "All chats have been unarchived.": "", - "All day": "", - "All models are now hidden": "", - "All models are now visible": "", + "All chats have been unarchived.": "Alle chats zijn gedearchiveerd.", + "All models are now hidden": "Alle modellen zijn nu verborgen", + "All models are now visible": "Alle modellen zijn nu zichtbaar", + "All day": "De hele dag", "All models deleted successfully": "Alle modellen zijn succesvol verwijderd", - "All time": "", - "All Users": "", + "All time": "Altijd", + "All Users": "Alle gebruikers", "Allow Call": "Bellen toestaan", "Allow Chat Controls": "Chatbesturing toestaan", "Allow Chat Delete": "Chatverwijdering toestaan", "Allow Chat Edit": "Chatwijziging toestaan", - "Allow Chat Export": "", - "Allow Chat Params": "", - "Allow Chat Share": "", - "Allow Chat System Prompt": "", - "Allow Chat Valves": "", - "Allow Continue Response": "", - "Allow Delete Messages": "", + "Allow Chat Export": "Chat exporteren toestaan", + "Allow Chat Params": "Chatparameters toestaan", + "Allow Chat Share": "Chat delen toestaan", + "Allow Chat System Prompt": "Systeemprompt voor chat toestaan", + "Allow Chat Valves": "Chatkleppen toestaan", + "Allow Continue Response": "Doorgaan met antwoord toestaan", + "Allow Delete Messages": "Berichten verwijderen toestaan", "Allow File Upload": "Bestandenupload toestaan", - "Allow Multiple Models in Chat": "", + "Allow Multiple Models in Chat": "Meerdere modellen in chat toestaan", "Allow non-local voices": "Niet-lokale stemmen toestaan", - "Allow public write access": "", - "Allow Rate Response": "", - "Allow Regenerate Response": "", - "Allow Sharing With Users": "", - "Allow Speech to Text": "", + "Allow public write access": "Openbare schrijftoegang toestaan", + "Allow Rate Response": "Reactiebeoordeling toestaan", + "Allow Regenerate Response": "Antwoord opnieuw genereren toestaan", + "Allow Sharing With Users": "Delen met gebruikers toestaan", + "Allow Speech to Text": "Spraak-naar-tekst toestaan", "Allow Temporary Chat": "Tijdelijke chat toestaan", - "Allow Text to Speech": "", + "Allow Text to Speech": "Tekst-naar-spraak toestaan", "Allow User Location": "Gebruikerslocatie toestaan", "Allow Voice Interruption in Call": "Stemonderbreking tijdens gesprek toestaan", - "Allow Web Upload": "", + "Allow Web Upload": "Webupload toestaan", "Allowed Endpoints": "Endpoints toestaan", - "Allowed File Extensions": "", - "Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.": "", + "Allowed File Extensions": "Toegestane bestandsextensies", + "Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.": "Toegestane bestandsextensies voor uploaden. Scheid meerdere extensies met komma's. Laat leeg voor alle bestandstypen.", "Already have an account?": "Heb je al een account?", - "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.": "Alternatief voor top_p, en streeft naar een evenwicht tussen kwaliteit en variatie. De parameter p vertegenwoordigt de minimumwaarschijnlijkheid dat een token in aanmerking wordt genomen, in verhouding tot de waarschijnlijkheid van het meest waarschijnlijke token. Bijvoorbeeld, met p=0,05 en het meest waarschijnlijke token met een waarschijnlijkheid van 0,9, worden logits met een waarde kleiner dan 0,045 uitgefilterd.", + "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.": "Alternatief voor top_p, en streeft naar een evenwicht tussen kwaliteit en variatie. De parameter p vertegenwoordigt de minimumwaarschijnlijkheid dat een token in aanmerking wordt genomen, in verhouding tot de waarschijnlijkheid van het meest waarschijnlijke token. Bijvoorbeeld, met p=0.05 en het meest waarschijnlijke token met een waarschijnlijkheid van 0.9, worden logits met een waarde kleiner dan 0.045 uitgefilterd.", "Always": "Altijd", "Always Collapse Code Blocks": "Codeblokken altijd inklappen", "Always Expand Details": "Details altijd uitklappen", - "Always Play Notification Sound": "", + "Always Play Notification Sound": "Meldingsgeluid altijd afspelen", "Amazing": "Geweldig", "an assistant": "een assistent", - "An error occurred while fetching the explanation": "", - "Analytics": "", + "An error occurred while fetching the explanation": "Er is een fout opgetreden bij het ophalen van de uitleg", + "Analytics": "Analyse", "Analyzed": "Geanalyseerd", "Analyzing...": "Aan het analyseren...", "and {{COUNT}} more": "en {{COUNT}} meer", "and create a new shared link.": "en maak een nieuwe gedeelde link.", - "Android": "", - "Anyone": "", + "Android": "Android", + "Anyone": "Iedereen", "API Base URL": "API Base URL", - "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", + "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "API base URL voor de Datalab Marker-service. Standaard: https://www.datalab.to/api/v1/marker", "API Key": "API-sleutel", "API Key created.": "API-sleutel aangemaakt.", "API Key Endpoint Restrictions": "API-sleutel endpoint-beperkingen", "API keys": "API-sleutels", - "API Keys": "", - "API Mode": "", - "API Timeout": "", - "API Type": "", - "API Version": "", - "API Version is required": "", + "API Keys": "API-sleutels", + "API Mode": "API-modus", + "API Timeout": "API-time-out", + "API Type": "API-type", + "API Version": "API-versie", + "API Version is required": "API-versie is vereist", "Application DN": "Applicatie DN", - "Application DN Password": "Applicatie", + "Application DN Password": "Applicatie-DN-wachtwoord", "applies to all users with the \"user\" role": "wordt op alle gebruikers met de \"gebruikersrol\" toegepast", - "April": "April", + "April": "april", "Archive": "Archief", - "Archive All": "", + "Archive All": "Alles archiveren", "Archive All Chats": "Archiveer alle chats", - "Archived Chats": "Chatrecord", + "Archived Chats": "Gearchiveerde chats", "archived-chat-export": "gearchiveerde-chat-export", - "Are you sure you want to archive all chats? This action cannot be undone.": "", + "Are you sure you want to archive all chats? This action cannot be undone.": "Weet je zeker dat je alle chats wilt archiveren? Deze actie kan niet ongedaan worden gemaakt.", "Are you sure you want to clear all memories? This action cannot be undone.": "Weet je zeker dat je alle herinneringen wil verwijderen? Deze actie kan niet ongedaan worden gemaakt.", - "Are you sure you want to delete \"{{NAME}}\"?": "", - "Are you sure you want to delete **{{modelName}}**?": "", - "Are you sure you want to delete all chats? This action cannot be undone.": "", + "Are you sure you want to delete \"{{NAME}}\"?": "Weet je zeker dat je \"{{NAME}}\" wilt verwijderen?", + "Are you sure you want to delete all chats? This action cannot be undone.": "Weet je zeker dat je alle chats wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", + "Are you sure you want to delete **{{modelName}}**?": "Weet je zeker dat je **{{modelName}}** wilt verwijderen?", "Are you sure you want to delete this channel?": "Weet je zeker dat je dit kanaal wil verwijderen?", - "Are you sure you want to delete this connection? This action cannot be undone.": "", - "Are you sure you want to delete this memory? This action cannot be undone.": "", + "Are you sure you want to delete this connection? This action cannot be undone.": "Weet je zeker dat je deze verbinding wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", + "Are you sure you want to delete this memory? This action cannot be undone.": "Weet je zeker dat je dit geheugen wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", "Are you sure you want to delete this message?": "Weet je zeker dat je dit bericht wil verwijderen?", - "Are you sure you want to delete this version? Child versions will be relinked to this version's parent.": "", - "Are you sure you want to delete this?": "", + "Are you sure you want to delete this version? Child versions will be relinked to this version's parent.": "Weet je zeker dat je deze versie wilt verwijderen? Onderliggende versies worden opnieuw gekoppeld aan de bovenliggende versie.", + "Are you sure you want to delete this?": "Weet je zeker dat je dit wilt verwijderen?", "Are you sure you want to unarchive all archived chats?": "Weet je zeker dat je alle gearchiveerde chats wil onarchiveren?", "Arena Models": "Arenamodellen", "Artifacts": "Artefacten", - "Asc": "", + "Asc": "Oplopend", "Ask": "Vraag", "Ask a question": "Stel een vraag", "Assistant": "Assistent", - "Async Embedding Processing": "", - "At time of event": "", - "Attach File From Knowledge": "", - "Attach Files": "", - "Attach Knowledge": "", - "Attach Notes": "", - "Attach Webpage": "", - "Attention to detail": "Attention to detail", + "Async Embedding Processing": "Asynchrone embeddingverwerking", + "Attach File From Knowledge": "Bestand uit kennis toevoegen", + "Attach Knowledge": "Kennis toevoegen", + "Attach Notes": "Notities toevoegen", + "Attach Webpage": "Webpagina toevoegen", + "Attention to detail": "Aandacht voor detail", + "Attach Files": "Bestanden toevoegen", + "At time of event": "Op het moment van de gebeurtenis", "Attribute for Mail": "Attribuut voor mail", "Attribute for Username": "Attribuut voor gebruikersnaam", "Audio": "Audio", - "August": "Augustus", - "Auth": "", + "August": "augustus", + "Auth": "Authenticatie", "Authenticate": "Authenticeer", "Authentication": "Authenticatie", - "Auto": "", - "Auto (Random)": "", + "Auto": "Automatisch", + "Auto (Random)": "Auto (Willekeurig)", "Auto-Copy Response to Clipboard": "Antwoord automatisch kopiëren naar klembord", "Auto-playback response": "Automatisch afspelen van antwoord", "Autocomplete Generation": "Automatische aanvullingsgeneratie", @@ -231,17 +231,17 @@ "AUTOMATIC1111 Api Auth String": "Automatic1111 Api Auth String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Basis-URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Basis-URL is verplicht", - "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", - "Automation": "", - "Automation created": "", - "Automation Name": "", - "Automation title": "", - "Automation triggered": "", - "Automation updated": "", - "Automations": "", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "Systeemtools automatisch injecteren in native functieaanroepmodus (bijv. tijdstempels, geheugen, chatgeschiedenis, notities, enz.)", + "Automation": "Automatisering", + "Automation created": "Automatisering aangemaakt", + "Automation Name": "Naam van automatisering", + "Automation title": "Titel van automatisering", + "Automation triggered": "Automatisering geactiveerd", + "Automation updated": "Automatisering bijgewerkt", + "Automations": "Automatiseringen", "Available list": "Beschikbare lijst", - "Available models": "", - "Available Tools": "", + "Available models": "Beschikbare modellen", + "Available Tools": "Beschikbare tools", "available users": "beschikbare gebruikers", "available!": "beschikbaar!", "Away": "Afwezig", @@ -253,93 +253,93 @@ "Bad Response": "Ongeldig antwoord", "Banners": "Banners", "Base Model (From)": "Basismodel (Vanaf)", - "Base Model List Cache speeds up access by fetching base models only at startup or on settings save—faster, but may not show recent base model changes.": "", - "Bearer": "", + "Base Model List Cache speeds up access by fetching base models only at startup or on settings save—faster, but may not show recent base model changes.": "Cache voor basismodellen versnelt de toegang door basismodellen alleen op te halen bij het opstarten of bij het opslaan van instellingen. Dit is sneller, maar toont mogelijk geen recente wijzigingen in basismodellen.", + "Bearer": "Bearer", "before": "voor", "Being lazy": "Lui zijn", "Beta": "Beta", - "Bing": "", + "Bing": "Bing", "Bing Search V7 Endpoint": "Bing Search V7 Endpoint", "Bing Search V7 Subscription Key": "Bing Search V7 Subscription Key", - "Bio": "", - "Birth Date": "", - "BM25 Weight": "", + "Bio": "Bio", + "Birth Date": "Geboortedatum", + "BM25 Weight": "BM25-gewicht", "Bocha Search API Key": "Bocha Search API-sleutel", - "Bold": "", + "Bold": "Vet", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Versterken of bestraffen van specifieke tokens voor beperkte reacties. Biaswaarden worden geklemd tussen -100 en 100 (inclusief). (Standaard: none)", - "Brave": "", + "Brave": "Brave", "Brave Search API Key": "Brave Search API-sleutel", - "Break down complex requests into trackable steps": "", - "Browse and query knowledge bases": "", - "Builtin Tools": "", - "Bullet List": "", - "Button ID": "", - "Button Label": "", - "Button Prompt": "", - "by {{name}}": "", - "By {{name}}": "Op {{name}}", - "Bypass Embedding and Retrieval": "Embedding en ophalen omzeilen ", - "Bypass Web Loader": "", - "Cache Base Model List": "", + "Browse and query knowledge bases": "Kennisbanken doorzoeken en bevragen", + "Builtin Tools": "Ingebouwde tools", + "Bullet List": "Lijst met opsommingstekens", + "Button ID": "Knop-ID", + "Button Label": "Knoplabel", + "Button Prompt": "Knopprompt", + "by {{name}}": "door {{name}}", + "By {{name}}": "Door {{name}}", + "Bypass Embedding and Retrieval": "Embedding en ophalen omzeilen", + "Bypass Web Loader": "Webloader omzeilen", + "Cache Base Model List": "Basismodellijst cachen", + "Break down complex requests into trackable steps": "Splits complexe verzoeken op in traceerbare stappen", "Calendar": "Agenda", - "Calendar deleted": "", - "Calendars": "", + "Calendar deleted": "Agenda verwijderd", + "Calendars": "Agenda's", "Call": "Oproep", "Call feature is not supported when using Web STT engine": "Belfunctie wordt niet ondersteund bij gebruik van de Web STT engine", "Camera": "Camera", "Cancel": "Annuleren", - "Cancel download of {{model}}": "", - "Cannot create an empty note.": "", - "Cannot delete the production version": "", + "Cancel download of {{model}}": "Download van {{model}} annuleren", + "Cannot create an empty note.": "Kan geen lege notitie maken.", + "Cannot delete the production version": "Kan de productieversie niet verwijderen", "Capabilities": "Mogelijkheden", "Capture": "Vastleggen", "Capture Audio": "Audio opnemen", "Certificate Path": "Pad naar certificaat", - "Change folder icon": "", + "Change folder icon": "Mappictogram wijzigen", "Change Password": "Wijzig Wachtwoord", - "Change User Role": "", - "Channel": "", - "Channel deleted successfully": "", + "Change User Role": "Gebruikersrol wijzigen", + "Channel": "Kanaal", + "Channel deleted successfully": "Kanaal succesvol verwijderd", "Channel Name": "Kanaalnaam", - "Channel name cannot be empty.": "", - "Channel name must be less than 128 characters": "", - "Channel Type": "", - "Channel updated successfully": "", + "Channel name cannot be empty.": "Kanaalnaam mag niet leeg zijn.", + "Channel name must be less than 128 characters": "Kanaalnaam moet korter zijn dan 128 tekens", + "Channel Type": "Kanaaltype", + "Channel updated successfully": "Kanaal succesvol bijgewerkt", "Channels": "Kanalen", "Character": "Karakter", "Character limit for autocomplete generation input": "Karakterlimiet voor automatische generatieinvoer", "Chart new frontiers": "Verken nieuwe grenzen", "Chat": "Chat", - "Chat archived.": "", + "Chat archived.": "Chat gearchiveerd.", "Chat Background Image": "Chatachtergrond", "Chat Bubble UI": "Chatbubble-UI", - "Chat Completions": "", - "Chat Conversation": "", + "Chat Completions": "Chataanvullingen", + "Chat Conversation": "Chatgesprek", "Chat direction": "Chatrichting", - "Chat exported successfully": "", - "Chat History": "", - "Chat ID": "", - "Chat moved successfully": "", + "Chat exported successfully": "Chat succesvol geexporteerd", + "Chat History": "Chatgeschiedenis", + "Chat ID": "Chat-ID", + "Chat moved successfully": "Chat succesvol verplaatst", "Chat Permissions": "Chattoestemmingen", "Chat Tags Auto-Generation": "Chatlabels automatisch genereren", - "Chat unshared successfully.": "", - "chats": "", + "Chat unshared successfully.": "Chatdeling succesvol opgeheven.", + "chats": "chats", "Chats": "Chats", "Check Again": "Controleer Opnieuw", "Check for updates": "Controleer op updates", "Checking for updates...": "Controleren op updates...", "Choose a model before saving...": "Kies een model voordat je opslaat...", - "Chunk Min Size Target": "", + "Chunk Min Size Target": "Target minimale chunkgrootte", "Chunk Overlap": "Chunkoverlap", "Chunk Size": "Chunkgrootte", - "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "Chunks die kleiner zijn dan deze drempel worden, waar mogelijk, samengevoegd met aangrenzende chunks. Stel in op 0 om samenvoegen uit te schakelen.", "Ciphers": "Versleutelingen", "Citation": "Citaat", "Citations": "Citaten", "Clear memory": "Geheugen wissen", "Clear Memory": "Geheugen wissen", - "Clear search": "", - "Clear status": "", + "Clear search": "Zoekopdracht wissen", + "Clear status": "Status wissen", "click here": "klik hier", "Click here for filter guides.": "Klik hier voor filterhulp.", "Click here for help.": "Klik hier voor hulp.", @@ -348,89 +348,89 @@ "Click here to learn more about faster-whisper and see the available models.": "Klik hier om meer te leren over faster-whisper en de beschikbare modellen te bekijken.", "Click here to see available models.": "Klik hier om beschikbare modellen te zien", "Click here to select": "Klik hier om te selecteren", - "Click here to select a csv file.": "Klik hier om een csv file te selecteren.", + "Click here to select a csv file.": "Klik hier om een csv bestand te selecteren.", "Click here to select a py file.": "Klik hier om een py-bestand te selecteren.", "Click here to upload a workflow.json file.": "Klik hier om een workflow.json-bestand te uploaden.", "click here.": "klik hier.", "Click on the user role button to change a user's role.": "Klik op de gebruikersrol knop om de rol van een gebruiker te wijzigen.", - "Click to connect": "", - "Click to copy ID": "", - "Client ID": "", - "Client Secret": "", + "Click to connect": "Klik om te verbinden", + "Click to copy ID": "Klik om ID te kopiëren", + "Client ID": "Client-ID", + "Client Secret": "Clientgeheim", "Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Klembord schrijftoestemming geweigerd. Kijk je browserinstellingen na om de benodigde toestemming te geven.", "Clone": "Kloon", "Clone Chat": "Kloon chat", "Clone of {{TITLE}}": "Kloon van {{TITLE}}", "Close": "Sluiten", - "Close Banner": "", - "Close chat controls": "", - "Close citation modal": "", - "Close Configure Connection Modal": "", - "Close feedback": "", - "Close modal": "", - "Close Modal": "", - "Close settings modal": "", - "Close Sidebar": "", - "cloud": "", - "CMU ARCTIC speaker embedding name": "", - "Code Block": "", - "Code Editor": "", + "Close Banner": "Banner sluiten", + "Close chat controls": "Chatbediening sluiten", + "Close citation modal": "Citatiemodal sluiten", + "Close Configure Connection Modal": "Modal Verbinding configureren sluiten", + "Close feedback": "Feedback sluiten", + "Close modal": "Modal sluiten", + "Close Modal": "Modal sluiten", + "Close settings modal": "Instellingenmodal sluiten", + "Close Sidebar": "Zijbalk sluiten", + "cloud": "cloud", + "CMU ARCTIC speaker embedding name": "CMU ARCTIC-spreker-embeddingnaam", + "Code Block": "Codeblok", + "Code Editor": "Code-editor", "Code execution": "Code uitvoeren", - "Code Execution": "", + "Code Execution": "Code-uitvoer", "Code Execution Engine": "Code-uitvoer engine", "Code Execution Timeout": "Code-uitvoer time-out", "Code formatted successfully": "Code succesvol geformateerd", "Code Interpreter": "Code-interpretatie", "Code Interpreter Engine": "Code-interpretatie engine", "Code Interpreter Prompt Template": "Code-interpretatie promptsjabloon", - "Collaboration channel where people join as members": "", + "Collaboration channel where people join as members": "Samenwerkingskanaal waar mensen als leden deelnemen", "Collapse": "Inklappen", "Collection": "Verzameling", - "Collections": "", + "Collections": "Verzamelingen", "Color": "Kleur", "ComfyUI": "ComfyUI", "ComfyUI API Key": "ComfyUI API-sleutel", "ComfyUI Base URL": "ComfyUI Base URL", - "ComfyUI Base URL is required.": "ComfyUI Base URL is required.", + "ComfyUI Base URL is required.": "ComfyUI-basis-URL is vereist.", "ComfyUI Workflow": "ComfyUI workflow", "ComfyUI Workflow Nodes": "ComfyUI workflowknopen", - "Comma separated Node Ids (e.g. 1 or 1,2)": "", - "command": "", + "Comma separated Node Ids (e.g. 1 or 1,2)": "Door komma's gescheiden node-ID's (bijv. 1 of 1,2)", + "command": "commando", "Command": "Commando", "Comment": "Reactie", - "Commit Message": "", - "Community Reviews": "", + "Commit Message": "Commitbericht", + "Community Reviews": "Communitybeoordelingen", "Completions": "Voltooiingen", - "Compress Images in Channels": "", + "Compress Images in Channels": "Afbeeldingen in kanalen comprimeren", "Concurrent Requests": "Gelijktijdige verzoeken", - "Config": "", - "Config imported successfully": "", - "Configuration": "", + "Config": "Configuratie", + "Config imported successfully": "Configuratie succesvol geimporteerd", + "Configuration": "Configuratie", "Configure": "Configureer", "Confirm": "Bevestigen", "Confirm Password": "Bevestig wachtwoord", - "Confirm Prompt from Embed": "", + "Confirm Prompt from Embed": "Prompt uit embed bevestigen", "Confirm your action": "Bevestig je actie", "Confirm your new password": "Bevestig je nieuwe wachtwoord", - "Confirm Your Password": "", - "Connect to an AI provider to start chatting": "", - "Connect to Open Terminal instances to browse files and use them as always-on tools. Only one can be active at a time.": "", - "Connect to Open Terminal instances. All users will have access to file browsing and terminal tools through these servers.": "", + "Confirm Your Password": "Bevestig je wachtwoord", + "Connect to an AI provider to start chatting": "Verbind met een AI-provider om te beginnen met chatten", + "Connect to Open Terminal instances to browse files and use them as always-on tools. Only one can be active at a time.": "Verbind met Open Terminal-instanties om bestanden te doorzoeken en ze te gebruiken als altijd-beschikbare tools. Slechts een kan tegelijk actief zijn.", + "Connect to Open Terminal instances. All users will have access to file browsing and terminal tools through these servers.": "Verbind met Open Terminal-instanties. Alle gebruikers krijgen via deze servers toegang tot bestandsverkenning en terminaltools.", "Connect to your own OpenAI compatible API endpoints.": "Verbind met je eigen OpenAI-compatibele API-endpoints", "Connect to your own OpenAPI compatible external tool servers.": "Verbind met je eigen OpenAPI-compatibele externe gereedschapservers", - "Connected ({{type}})": "", + "Connected ({{type}})": "Verbonden ({{type}})", "Connection failed": "Connectie mislukt", - "Connection lost. Reconnecting...": "", + "Connection lost. Reconnecting...": "Verbinding verbroken. Opnieuw verbinden...", "Connection successful": "Connectie succesvol", - "Connection Type": "Connectie type", + "Connection Type": "Connectietype", "Connections": "Verbindingen", - "Connections saved successfully": "", - "Connections settings updated": "", + "Connections saved successfully": "Verbindingen succesvol opgeslagen", + "Connections settings updated": "Verbindingsinstellingen bijgewerkt", "Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort.": "Beperkt de redeneerinspanning voor redeneermodellen. Alleen van toepassing op redeneermodellen van specifieke providers die redeneerinspanning ondersteunen.", "Contact Admin for WebUI Access": "Neem contact op met de beheerder voor WebUI-toegang", "Content": "Inhoud", "Content Extraction Engine": "Inhoudsextractie engine", - "Content lengths (character counts only)": "", + "Content lengths (character counts only)": "Inhoudslengtes (alleen tekentellingen)", "Continue Response": "Doorgaan met antwoord", "Continue with {{provider}}": "Ga verder met {{provider}}", "Continue with Email": "Ga door met E-mail", @@ -438,83 +438,83 @@ "Control how message text is split for TTS requests. 'Punctuation' splits into sentences, 'paragraphs' splits into paragraphs, and 'none' keeps the message as a single string.": "Bepaal hoe berichttekst wordt opgesplitst voor TTS-verzoeken. 'Leestekens' splitst op in zinnen, 'alinea's' splitst op in paragrafen en 'geen' houdt het bericht als een enkele string.", "Control the repetition of token sequences in the generated text. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 1.1) will be more lenient. At 1, it is disabled.": "Controleer de herhaling van tokenreeksen in de gegenereerde tekst. Een hogere waarde (bijv. 1,5) zal herhalingen sterker bestraffen, terwijl een lagere waarde (bijv. 1,1) milder zal zijn. Bij 1 is het uitgeschakeld.", "Controls": "Besturingselementen", - "Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text.": "", - "Conversation saved successfully": "", + "Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text.": "Regelt de balans tussen samenhang en diversiteit van de uitvoer. Een lagere waarde resulteert in meer gerichte en samenhangende tekst.", + "Conversation saved successfully": "Gesprek succesvol opgeslagen", "Copied": "Gekopieerd", - "Copied link to clipboard": "", + "Copied link to clipboard": "Link gekopieerd naar klembord", "Copied shared chat URL to clipboard!": "URL van gedeelde gesprekspagina gekopieerd naar klembord!", "Copied to clipboard": "Gekopieerd naar klembord", "Copy": "Kopieer", - "Copy API Key": "", - "Copy content": "", + "Copy API Key": "API-sleutel kopiëren", + "Copy content": "Inhoud kopiëren", "Copy Formatted Text": "Kopieer opgemaakte tekst", - "Copy Last Code Block": "", - "Copy Last Response": "", - "Copy link": "Kopiëer link", + "Copy Last Code Block": "Laatste codeblok kopiëren", + "Copy Last Response": "Laatste antwoord kopiëren", + "Copy link": "Kopieer link", "Copy Link": "Kopieer link", - "Copy Path": "", - "Copy Prompt": "", - "Copy Share Link": "", + "Copy Prompt": "Prompt kopiëren", + "Copy Share Link": "Deellink kopiëren", + "Copy Path": "Pad kopiëren", "Copy to clipboard": "Kopieer naar klembord", - "Copy Token": "", - "Copy URL": "", + "Copy Token": "Token kopiëren", + "Copy URL": "URL kopiëren", "Copying to clipboard was successful!": "Kopiëren naar klembord was succesvol!", "CORS must be properly configured by the provider to allow requests from Open WebUI.": "CORS moet goed geconfigureerd zijn bij de provider om verzoeken van Open WebUI toe te staan", - "Could not read file.": "", - "CPU": "", + "Could not read file.": "Kon bestand niet lezen.", + "CPU": "CPU", "Create": "Aanmaken", "Create a knowledge base": "Maak een kennisbasis aan", "Create a model": "Een model maken", - "Create a new note": "", + "Create a new note": "Een nieuwe notitie maken", "Create Account": "Maak account", "Create Admin Account": "Maak admin-account", - "Create and manage scheduled automations": "", + "Create and manage scheduled automations": "Maak en beheer geplande automatiseringen", "Create Channel": "Maak kanaal", - "Create Folder": "", - "Create Image": "", - "Create Knowledge": "Creër kennis", - "Create Model": "", + "Create Folder": "Map maken", + "Create Image": "Afbeelding maken", + "Create Knowledge": "Creëer kennis", + "Create Model": "Model maken", "Create new key": "Maak nieuwe sleutel", "Create new secret key": "Maak nieuwe geheime sleutel", - "Create note": "", + "Create note": "Notitie maken", "Create Note": "Maak notitie", - "Create scheduled prompts that run automatically on a recurring basis.": "", - "Create your first note by clicking on the plus button below.": "", + "Create your first note by clicking on the plus button below.": "Maak je eerste notitie door op de plusknop hieronder te klikken.", + "Create scheduled prompts that run automatically on a recurring basis.": "Maak geplande prompts die automatisch op terugkerende basis worden uitgevoerd.", "Created at": "Gemaakt op", "Created At": "Gemaakt op", "Created by": "Gemaakt door", - "Created by you": "", - "Created on {{date}}": "", + "Created by you": "Gemaakt door jou", + "Created on {{date}}": "Gemaakt op {{date}}", "CSV Import": "CSV import", "Ctrl+Enter to Send": "Ctrl+Enter om te sturen", "Current Model": "Huidig model", "Current Password": "Huidig wachtwoord", "Custom": "Aangepast", - "Custom description enabled": "", - "Custom Gender": "", - "Custom Parameter Name": "", - "Custom Parameter Value": "", - "Daily": "", - "Daily Messages": "", + "Custom description enabled": "Aangepaste beschrijving ingeschakeld", + "Custom Gender": "Aangepast geslacht", + "Custom Parameter Name": "Naam van aangepaste parameter", + "Custom Parameter Value": "Waarde van aangepaste parameter", + "Daily Messages": "Dagelijkse berichten", + "Daily": "Dagelijks", "Danger Zone": "Gevarenzone", "Dark": "Donker", - "Data Controls": "", + "Data Controls": "Gegevensbeheer", "Database": "Database", - "Datalab Marker API": "", - "Day": "", - "DD/MM/YYYY": "", - "DDGS Backend": "", - "December": "December", - "Decrease UI Scale": "", - "Deepgram": "", + "Datalab Marker API": "Datalab Marker-API", + "DD/MM/YYYY": "DD/MM/JJJJ", + "DDGS Backend": "DDGS-backend", + "December": "december", + "Decrease UI Scale": "UI-schaal verkleinen", + "Deepgram": "Deepgram", + "Day": "Dag", "Default": "Standaard", "Default (Open AI)": "Standaard (Open AI)", "Default (SentenceTransformers)": "Standaard (SentenceTransformers)", - "Default action buttons will be used.": "", - "Default description enabled": "", - "Default Features": "", - "Default Filters": "", - "Default Group": "", + "Default action buttons will be used.": "Standaardactieknoppen worden gebruikt.", + "Default description enabled": "Standaardbeschrijving ingeschakeld", + "Default Features": "Standaardfuncties", + "Default Filters": "Standaardfilters", + "Default Group": "Standaardgroep", "Default mode works with a wider range of models by calling tools once before execution. Native mode leverages the model's built-in tool-calling capabilities, but requires the model to inherently support this feature.": "De standaardmodus werkt met een breder scala aan modellen door gereedschappen één keer aan te roepen voordat ze worden uitgevoerd. De native modus maakt gebruik van de ingebouwde mogelijkheden van het model om gereedschappen aan te roepen, maar vereist dat het model deze functie inherent ondersteunt.", "Default Model": "Standaardmodel", "Default model updated": "Standaardmodel bijgewerkt", @@ -525,59 +525,59 @@ "Default to ALL": "Standaard op ALL", "Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.": "Standaard gesegmenteerd ophalen voor gerichte en relevante inhoudsextractie, dit wordt aanbevolen voor de meeste gevallen.", "Default User Role": "Standaard gebruikersrol", - "Defaults": "", + "Defaults": "Standaardwaarden", "Delete": "Verwijderen", - "Delete {{name}}": "", + "Delete {{name}}": "{{name}} verwijderen", "Delete a model": "Verwijder een model", - "Delete All": "", + "Delete All": "Alles verwijderen", "Delete All Chats": "Verwijder alle chats", - "Delete all contents inside this folder": "", - "Delete automation?": "", - "Delete calendar": "", - "Delete Calendar": "", + "Delete all contents inside this folder": "Alle inhoud in deze map verwijderen", + "Delete calendar": "Verwijder kalender", + "Delete Calendar": "Verwijder kalender", "Delete Chat": "Verwijder chat", "Delete chat?": "Verwijder chat?", - "Delete Event": "", - "Delete File": "", + "Delete File": "Bestand verwijderen", + "Delete automation?": "Verwijder automatisering?", + "Delete Event": "Verwijder gebeurtenis?", "Delete folder?": "Verwijder map?", "Delete function?": "Verwijder functie?", - "Delete Memory?": "", + "Delete Memory?": "Geheugen verwijderen?", "Delete Message": "Verwijder bericht", "Delete message?": "Bericht verwijderen?", - "Delete Model": "", + "Delete Model": "Model verwijderen", "Delete note?": "Notitie verwijderen?", "Delete prompt?": "Verwijder prompt?", - "Delete skill?": "", + "Delete skill?": "Vaardigheid verwijderen?", "delete this link": "verwijder deze link", "Delete tool?": "Verwijder tool?", "Delete User": "Verwijder gebruiker", - "Delete Version": "", - "Deleted": "", + "Delete Version": "Versie verwijderen", + "Deleted": "Verwijderd", "Deleted {{deleteModelTag}}": "{{deleteModelTag}} is verwijderd", "Deleted {{name}}": "{{name}} verwijderd", - "Deleted {{ok}} of {{total}} items": "", + "Deleted {{ok}} of {{total}} items": "{{ok}} van {{total}} items verwijderd", "Deleted User": "Gebruiker verwijderd", - "Deployment names are required for Azure OpenAI": "", - "Desc": "", - "Describe the edit...": "", - "Describe the image...": "", - "Describe what changed...": "", + "Deployment names are required for Azure OpenAI": "Implementatienamen zijn vereist voor Azure OpenAI", + "Desc": "Aflopend", + "Describe the edit...": "Beschrijf de bewerking...", + "Describe the image...": "Beschrijf de afbeelding...", + "Describe what changed...": "Beschrijf wat er is gewijzigd...", "Describe your knowledge base and objectives": "Beschrijf je kennisbasis en doelstellingen", "Description": "Beschrijving", - "Deselect": "", - "Detect Artifacts Automatically": "", - "Dictate": "", + "Deselect": "Deselecteren", + "Detect Artifacts Automatically": "Artefacten automatisch detecteren", + "Dictate": "Dicteren", "Didn't fully follow instructions": "Heeft niet alle instructies gevolgd", "Direct": "Direct", "Direct Connections": "Directe verbindingen", "Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "Directe verbindingen stellen gebruikers in staat om met hun eigen OpenAI compatibele API-endpoints te verbinden.", - "Direct Message": "", - "Direct Tool Servers": "", - "Directory selection was cancelled": "", - "Disable All": "", - "Disable Code Interpreter": "", - "Disable Image Extraction": "", - "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", + "Direct Message": "Direct bericht", + "Direct Tool Servers": "Directe toolservers", + "Directory selection was cancelled": "Mapselectie is geannuleerd", + "Disable All": "Alles uitschakelen", + "Disable Code Interpreter": "Code-interpretatie uitschakelen", + "Disable Image Extraction": "Afbeeldingsextractie uitschakelen", + "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Schakel afbeeldingsextractie uit de PDF uit. Als Use LLM is ingeschakeld, krijgen afbeeldingen automatisch beschrijvingen. Standaard is False.", "Disabled": "Uitgeschakeld", "Discover a function": "Ontdek een functie", "Discover a model": "Ontdek een model", @@ -589,126 +589,126 @@ "Discover, download, and explore custom prompts": "Ontdek, download en verken aangepaste prompts", "Discover, download, and explore custom tools": "Ontdek, download en verken aangepaste gereedschappen", "Discover, download, and explore model presets": "Ontdek, download en verken model presets", - "Discussion channel where access is based on groups and permissions": "", + "Discussion channel where access is based on groups and permissions": "Discussiekanaal waarbij toegang is gebaseerd op groepen en machtigingen", "Display": "Toon", - "Display chat title in tab": "", + "Display chat title in tab": "Chattitel weergeven in tabblad", "Display Emoji in Call": "Emoji tonen tijdens gesprek", - "Display Multi-model Responses in Tabs": "", + "Display Multi-model Responses in Tabs": "Multimodelantwoorden in tabbladen weergeven", "Display the username instead of You in the Chat": "Toon de gebruikersnaam in plaats van Jij in de Chat", "Displays citations in the response": "Toon citaten in het antwoord", - "Displays status updates (e.g., web search progress) in the response": "", - "Dive into knowledge": "Duik in kennis", + "Displays status updates (e.g., web search progress) in the response": "Toont statusupdates (bijv. voortgang van webzoekopdrachten) in het antwoord", + "Dive into knowledge": "Verken kennis", "Do not install functions from sources you do not fully trust.": "Installeer geen functies vanuit bronnen die je niet volledig vertrouwt", "Do not install tools from sources you do not fully trust.": "Installeer geen tools vanuit bronnen die je niet volledig vertrouwt.", - "Do you want to sync your usage stats with Open WebUI Community?": "", + "Do you want to sync your usage stats with Open WebUI Community?": "Wil je je gebruiksstatistieken synchroniseren met Open WebUI Community?", "Docling": "Docling", - "Docling Parameters": "", + "Docling Parameters": "Docling-parameters", "Docling Server URL required.": "Docling server-URL benodigd", "Document": "Document", "Document Intelligence": "Document Intelligence", - "Document Intelligence endpoint required.": "", - "Document Intelligence Model": "", + "Document Intelligence endpoint required.": "Document Intelligence-endpoint is vereist.", + "Document Intelligence Model": "Document Intelligence-model", "Documentation": "Documentatie", - "Documents": "", + "Documents": "Documenten", "does not make any external connections, and your data stays securely on your locally hosted server.": "maakt geen externe verbindingen, en je gegevens blijven veilig op je lokaal gehoste server.", "Domain Filter List": "Domein-filterlijst", "don't fetch random pipelines from sources you don't trust.": "Haal geen willekeurige pipelines op van onbetrouwbare bronnen.", "Don't have an account?": "Heb je geen account?", - "don't install random functions from sources you don't trust.": "installeer geen willekeurige functies van bronnen die je niet vertrouwd", - "don't install random tools from sources you don't trust.": "installeer geen willekeurige gereedschappen van bronnen die je niet vertrouwd", + "don't install random functions from sources you don't trust.": "installeer geen willekeurige functies van bronnen die je niet vertrouwt", + "don't install random tools from sources you don't trust.": "installeer geen willekeurige gereedschappen van bronnen die je niet vertrouwt", "Don't like the style": "Vind je de stijl niet mooi?", "Done": "Voltooid", "Download": "Download", "Download & Delete": "Downloaden en verwijderen", - "Download as JSON": "", + "Download as JSON": "Download als JSON", "Download as SVG": "Download als SVG", "Download canceled": "Download geannuleerd", "Download Database": "Download database", - "Downloading stats...": "", + "Downloading stats...": "Statistieken downloaden...", "Draw": "Teken", - "Drop any files here to upload": "", - "Drop files here": "", - "Drop files here to upload": "", - "DuckDuckGo": "", + "Drop any files here to upload": "Sleep bestanden hierheen om te uploaden", + "Drop files here": "Sleep bestanden hierheen", + "Drop files here to upload": "Sleep bestanden hierheen om te uploaden", + "DuckDuckGo": "DuckDuckGo", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "bijv. '30s', '10m'. Geldige tijdseenheden zijn 's', 'm', 'h'.", - "e.g. 'low', 'medium', 'high'": "", + "e.g. 'low', 'medium', 'high'": "bijv. 'laag', 'gemiddeld', 'hoog'", "e.g. \"json\" or a JSON schema": "bijv. \"json\" of een JSON-schema", "e.g. 60": "bijv. 60", - "e.g. A filter to remove profanity from text": "bijv. Een filter om gevloek uit tekst te verwijderen", - "e.g. about the Roman Empire": "", - "e.g. alloy, echo, shimmer": "", - "e.g. Code Review Guidelines": "", - "e.g. code-review-guidelines": "", - "e.g. en": "", + "e.g. A filter to remove profanity from text": "bijv. Een filter om uit tekst te verwijderen", + "e.g. about the Roman Empire": "bijv. over het Romeinse Rijk", + "e.g. alloy, echo, shimmer": "bijv. alloy, echo, shimmer", + "e.g. Code Review Guidelines": "bijv. Richtlijnen voor codebeoordeling", + "e.g. code-review-guidelines": "bijv. richtlijnen-voor-codebeoordeling", + "e.g. en": "bijv. en", "e.g. My Filter": "bijv. Mijn filter", "e.g. My Tools": "bijv. Mijn gereedschappen", "e.g. my_filter": "bijv. mijn_filter", "e.g. my_tools": "bijv. mijn_gereedschappen", - "e.g. pdf, docx, txt": "", - "e.g. Step-by-step instructions for code reviews": "", - "e.g. Tell me a fun fact": "", - "e.g. Tell me a fun fact about the Roman Empire": "", + "e.g. pdf, docx, txt": "bijv. pdf, docx, txt", + "e.g. Step-by-step instructions for code reviews": "bijv. Stapsgewijze instructies voor codebeoordelingen", + "e.g. Tell me a fun fact": "bijv. Vertel me een leuk weetje", + "e.g. Tell me a fun fact about the Roman Empire": "bijv. Vertel me een leuk weetje over het Romeinse Rijk", "e.g. Tools for performing various operations": "Gereedschappen om verschillende bewerkingen uit te voeren", - "e.g., 3, 4, 5 (leave blank for default)": "", - "e.g., audio/wav,audio/mpeg,video/* (leave blank for defaults)": "", - "e.g., en-US,ja-JP (leave blank for auto-detect)": "", - "e.g., westus (leave blank for eastus)": "", + "e.g., 3, 4, 5 (leave blank for default)": "bijv. 3, 4, 5 (laat leeg voor standaard)", + "e.g., audio/wav,audio/mpeg,video/* (leave blank for defaults)": "bijv. audio/wav,audio/mpeg,video/* (laat leeg voor standaardwaarden)", + "e.g., en-US,ja-JP (leave blank for auto-detect)": "bijv. en-US,ja-JP (laat leeg voor automatische detectie)", + "e.g., westus (leave blank for eastus)": "bijv. westus (laat leeg voor eastus)", "Edit": "Wijzig", "Edit Arena Model": "Bewerk arenamodel", "Edit Channel": "Bewerk kanaal", "Edit Connection": "Bewerk connectie", "Edit Default Permissions": "Bewerk standaardrechten", - "Edit Folder": "", - "Edit Image": "", - "Edit Last Message": "", + "Edit Folder": "Map bewerken", + "Edit Image": "Afbeelding bewerken", + "Edit Last Message": "Laatste bericht bewerken", "Edit Memory": "Bewerk geheugen", - "Edit Prompt": "", - "Edit Terminal Connection": "", + "Edit Prompt": "Prompt bewerken", + "Edit Terminal Connection": "Terminalverbinding bewerken", "Edit User": "Wijzig gebruiker", "Edit User Group": "Bewerk gebruikergroep", - "Edit workflow.json content": "", - "edited": "", - "Edited": "", - "Editing": "", - "Eject": "", - "Eject model": "", + "Edit workflow.json content": "workflow.json-inhoud bewerken", + "edited": "bewerkt", + "Edited": "Bewerkt", + "Editing": "Bewerken", + "Eject": "Uitwerpen", + "Eject model": "Model uitwerpen", "ElevenLabs": "ElevenLabs", "Email": "E-mail", "Embark on adventures": "Ga op avonturen", "Embedding": "Embedding", "Embedding Batch Size": "Embedding batchgrootte", - "Embedding Concurrent Requests": "", + "Embedding Concurrent Requests": "Gelijktijdige embeddingverzoeken", "Embedding Model": "Embedding Model", "Embedding Model Engine": "Embedding Model Engine", - "Emojis": "", - "Empty message": "", - "Enable All": "", - "Enable API Keys": "", + "Empty message": "Leeg bericht", + "Enable All": "Alles inschakelen", + "Enable API Keys": "API-sleutels inschakelen", + "Emojis": "Emojis", "Enable autocomplete generation for chat messages": "Automatische aanvullingsgeneratie voor chatberichten inschakelen", "Enable Code Execution": "Code-uitvoer inschakelen", "Enable Code Interpreter": "Code-interpretatie inschakelen", "Enable Community Sharing": "Delen via de community inschakelen", "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.": "Schakel Memory Locking (mlock) in om te voorkomen dat modelgegevens uit het RAM worden verwisseld. Deze optie vergrendelt de werkset pagina's van het model in het RAM, zodat ze niet naar de schijf worden uitgewisseld. Dit kan helpen om de prestaties op peil te houden door paginafouten te voorkomen en snelle gegevenstoegang te garanderen.", "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.": "Schakel Memory Mapping (mmap) in om modelgegevens te laden. Deze optie laat het systeem schijfopslag gebruiken als een uitbreiding van RAM door schijfbestanden te behandelen alsof ze in RAM zitten. Dit kan de prestaties van het model verbeteren door snellere gegevenstoegang mogelijk te maken. Het is echter mogelijk dat deze optie niet op alle systemen correct werkt en een aanzienlijke hoeveelheid schijfruimte in beslag kan nemen.", - "Enable Message Queue": "", + "Enable Message Queue": "Berichtenwachtrij inschakelen", "Enable Message Rating": "Schakel berichtbeoordeling in", "Enable Mirostat sampling for controlling perplexity.": "Mirostat-sampling in om perplexiteit te controleren inschakelen.", "Enable New Sign Ups": "Schakel nieuwe registraties in", - "Enable, disable, or customize the reasoning tags used by the model. \"Enabled\" uses default tags, \"Disabled\" turns off reasoning tags, and \"Custom\" lets you specify your own start and end tags.": "", + "Enable, disable, or customize the reasoning tags used by the model. \"Enabled\" uses default tags, \"Disabled\" turns off reasoning tags, and \"Custom\" lets you specify your own start and end tags.": "Schakel de redeneringstags die door het model worden gebruikt in, uit of pas ze aan. \"Ingeschakeld\" gebruikt standaardtags, \"Uitgeschakeld\" zet redeneringstags uit en \"Aangepast\" laat je je eigen begin- en eindtags instellen.", "Enabled": "Ingeschakeld", - "End Tag": "", - "Endpoint URL": "", + "End Tag": "Eindtag", + "Endpoint URL": "Endpoint-URL", "Enforce Temporary Chat": "Tijdelijke chat afdwingen", - "Enhance": "", - "Enrich Hybrid Search Text": "", - "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Zorg ervoor dat uw CSV-bestand de volgende vier kolommen in deze volgorde bevat: Naam, E-mail, Wachtwoord, Rol.", + "Enhance": "Verbeteren", + "Enrich Hybrid Search Text": "Hybride zoektekst verrijken", + "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Zorg ervoor dat je CSV-bestand de volgende vier kolommen in deze volgorde bevat: Naam, E-mail, Wachtwoord, Rol.", "Enter {{role}} message here": "Voeg {{role}} bericht hier toe", "Enter a detail about yourself for your LLMs to recall": "Voer een detail over jezelf in zodat LLM's het kunnen onthouden", - "Enter a title for the pending user info overlay. Leave empty for default.": "", - "Enter a watermark for the response. Leave empty for none.": "", - "Enter additional headers in JSON format": "", - "Enter additional headers in JSON format (e.g. {\"X-Custom-Header\": \"value\"}": "", - "Enter additional parameters in JSON format": "", + "Enter a title for the pending user info overlay. Leave empty for default.": "Voer een titel in voor de overlay met wachtende gebruikersinfo. Laat leeg voor standaard.", + "Enter a watermark for the response. Leave empty for none.": "Voer een watermerk in voor het antwoord. Laat leeg voor geen.", + "Enter additional headers in JSON format": "Voer extra headers in JSON-indeling in", + "Enter additional headers in JSON format (e.g. {\"X-Custom-Header\": \"value\"}": "Voer extra headers in JSON-indeling in (bijv. {\"X-Custom-Header\": \"value\"}", + "Enter additional parameters in JSON format": "Voer extra parameters in JSON-indeling in", "Enter api auth string (e.g. username:password)": "Voer api auth string in (bv. gebruikersnaam:wachtwoord)", "Enter Application DN": "Voer applicatie-DN in", "Enter Application DN Password": "Voer applicatie-DN wachtwoord in", @@ -717,69 +717,69 @@ "Enter Bocha Search API Key": "Voer Bocha Search API-sleutel in", "Enter Brave Search API Key": "Voer de Brave Search API-sleutel in", "Enter certificate path": "Voer pad naar certificaat in", - "Enter Chunk Min Size Target": "", + "Enter Chunk Min Size Target": "Voer doel voor minimale chunkgrootte in", "Enter Chunk Overlap": "Voeg Chunk Overlap toe", "Enter Chunk Size": "Voeg Chunk Size toe", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Voer kommagescheiden \"token:bias_waarde\" paren in (bijv. 5432:100, 413:-100)", - "Enter content for the pending user info overlay. Leave empty for default.": "", - "Enter coordinates (e.g. 51.505, -0.09)": "", - "Enter Datalab Marker API Base URL": "", - "Enter Datalab Marker API Key": "", + "Enter content for the pending user info overlay. Leave empty for default.": "Voer inhoud in voor de overlay met wachtende gebruikersinfo. Laat leeg voor standaard.", + "Enter coordinates (e.g. 51.505, -0.09)": "Voer coordinaten in (bijv. 51.505, -0.09)", + "Enter Datalab Marker API Base URL": "Voer Datalab Marker API-basis-URL in", + "Enter Datalab Marker API Key": "Voer Datalab Marker API-sleutel in", "Enter description": "Voer beschrijving in", - "Enter Docling API Key": "", + "Enter Docling API Key": "Voer Docling API-sleutel in", "Enter Docling Server URL": "Voer Docling Server-URL in", "Enter Document Intelligence Endpoint": "Voer Document Intelligence endpoint in", "Enter Document Intelligence Key": "Voer Document Intelligence sleutel in", - "Enter Document Intelligence Model": "", - "Enter domains separated by commas (e.g., example.com,site.org,!excludedsite.com)": "", + "Enter Document Intelligence Model": "Voer Document Intelligence-model in", + "Enter domains separated by commas (e.g., example.com,site.org,!excludedsite.com)": "Voer domeinen in, gescheiden door komma's (bijv. example.com,site.org,!excludedsite.com)", "Enter Exa API Key": "Voer Exa API-sleutel in", - "Enter External Document Loader API Key": "", - "Enter External Document Loader URL": "", - "Enter External Web Loader API Key": "", - "Enter External Web Loader URL": "", - "Enter External Web Search API Key": "", - "Enter External Web Search URL": "", - "Enter Firecrawl API Base URL": "", - "Enter Firecrawl API Key": "", - "Enter Firecrawl Timeout": "", - "Enter folder name": "", - "Enter function name filter list (e.g. func1, !func2)": "", + "Enter External Document Loader API Key": "Voer externe documentloader-API-sleutel in", + "Enter External Document Loader URL": "Voer externe documentloader-URL in", + "Enter External Web Loader API Key": "Voer externe webloader-API-sleutel in", + "Enter External Web Loader URL": "Voer externe webloader-URL in", + "Enter External Web Search API Key": "Voer externe webzoek-API-sleutel in", + "Enter External Web Search URL": "Voer externe webzoek-URL in", + "Enter Firecrawl API Base URL": "Voer Firecrawl API-basis-URL in", + "Enter Firecrawl API Key": "Voer Firecrawl API-sleutel in", + "Enter Firecrawl Timeout": "Voer Firecrawl-time-out in", + "Enter folder name": "Voer mapnaam in", + "Enter function name filter list (e.g. func1, !func2)": "Voer functienaamfilterlijst in (bijv. func1, !func2)", "Enter Github Raw URL": "Voer de Github Raw-URL in", "Enter Google PSE API Key": "Voer de Google PSE API-sleutel in", "Enter Google PSE Engine Id": "Voer Google PSE Engine-ID in", - "Enter hex color (e.g. #FF0000)": "", + "Enter hex color (e.g. #FF0000)": "Voer hexkleur in (bijv. #FF0000)", "Enter Image Size (e.g. 512x512)": "Voeg afbeelding formaat toe (Bijv. 512x512)", - "Enter Jina API Base URL": "", + "Enter Jina API Base URL": "Voer Jina API-basis-URL in", "Enter Jina API Key": "Voer Jina API-sleutel in", - "Enter JSON config (e.g., {\"disable_links\": true})": "", + "Enter JSON config (e.g., {\"disable_links\": true})": "Voer JSON-config in (bijv. {\"disable_links\": true})", "Enter Jupyter Password": "Voer Jupyter-wachtwoord in", "Enter Jupyter Token": "Voer Jupyter-token in", "Enter Jupyter URL": "Voer Jupyter-URL in", "Enter Kagi Search API Key": "Voer Kagi Search API-sleutel in", "Enter Key Behavior": "Voer sleutelgedrag in", "Enter language codes": "Voeg taalcodes toe", - "Enter MinerU API Key": "", - "Enter Mistral API Base URL": "", - "Enter Mistral API Key": "", + "Enter MinerU API Key": "Voer MinerU API-sleutel in", + "Enter Mistral API Base URL": "Voer Mistral API-basis-URL in", + "Enter Mistral API Key": "Voer Mistral API-sleutel in", "Enter Model ID": "Voer model-ID in", "Enter model tag (e.g. {{modelTag}})": "Voeg model-tag toe (Bijv. {{modelTag}})", "Enter Mojeek Search API Key": "Voer Mojeek Search API-sleutel in", - "Enter name": "", - "Enter New Password": "", + "Enter name": "Voer naam in", + "Enter New Password": "Voer nieuw wachtwoord in", "Enter Number of Steps (e.g. 50)": "Voeg aantal stappen toe (Bijv. 50)", - "Enter Ollama Cloud API Key": "", + "Enter Ollama Cloud API Key": "Voer Ollama Cloud API-sleutel in", "Enter Perplexity API Key": "Voer Perplexity API-sleutel in", - "Enter Perplexity Search API URL": "", - "Enter Playwright Timeout": "", - "Enter Playwright WebSocket URL": "", - "Enter prompt here.": "", + "Enter Perplexity Search API URL": "Voer Perplexity Search API-URL in", + "Enter Playwright Timeout": "Voer Playwright-time-out in", + "Enter Playwright WebSocket URL": "Voer Playwright WebSocket-URL in", + "Enter prompt here.": "Voer hier je prompt in.", "Enter proxy URL (e.g. https://user:password@host:port)": "Voer proxy-URL in (bijv. https://gebruiker:wachtwoord@host:port)", "Enter reasoning effort": "Voer redeneerinspanning in", "Enter Score": "Voeg score toe", "Enter SearchApi API Key": "Voer SearchApi API-sleutel in", "Enter SearchApi Engine": "Voer SearchApi-Engine in", "Enter Searxng Query URL": "Voer de URL van de Searxng-query in", - "Enter Searxng search language": "", + "Enter Searxng search language": "Voer Searxng-zoektaal in", "Enter Seed": "Voer Seed in", "Enter SerpApi API Key": "Voer SerpApi API-sleutel in", "Enter SerpApi Engine": "Voer SerpApi-engine in", @@ -789,211 +789,225 @@ "Enter server host": "Voer serverhost in", "Enter server label": "Voer serverlabel in", "Enter server port": "Voer serverpoort in", - "Enter skill instructions in markdown...": "", - "Enter Sougou Search API sID": "", - "Enter Sougou Search API SK": "", + "Enter skill instructions in markdown...": "Voer vaardigheidsinstructies in markdown in...", + "Enter Sougou Search API sID": "Voer Sougou Search API sID in", + "Enter Sougou Search API SK": "Voer Sougou Search API SK in", "Enter stop sequence": "Voer stopsequentie in", "Enter system prompt": "Voer systeem prompt in", - "Enter system prompt here": "", + "Enter system prompt here": "Voer hier de systeemprompt in", "Enter Tavily API Key": "Voer Tavily API-sleutel in", - "Enter Tavily Extract Depth": "", - "Enter the prompt instructions for this automation...": "", + "Enter Tavily Extract Depth": "Voer Tavily extractiediepte in", + "Enter the prompt instructions for this automation...": "Voer de prompt-instructies in voor deze automatisering...", "Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Voer de publieke URL van je WebUI in. Deze URL wordt gebruikt om links in de notificaties te maken.", - "Enter the URL of the function to import": "", - "Enter the URL to import": "", + "Enter the URL of the function to import": "Voer de URL in van de functie die je wilt importeren", + "Enter the URL to import": "Voer de URL in om te importeren", "Enter Tika Server URL": "Voer Tika Server URL in", "Enter timeout in seconds": "Voer time-out in seconden in", "Enter to Send": "Enter om te sturen", "Enter Top K": "Voeg Top K toe", - "Enter Top K Reranker": "Voer Tok K reranker in", + "Enter Top K Reranker": "Voer Top K-reranker in", "Enter URL (e.g. http://127.0.0.1:7860/)": "Voer URL in (Bijv. http://127.0.0.1:7860/)", "Enter URL (e.g. http://localhost:11434)": "Voer URL in (Bijv. http://localhost:11434)", - "Enter value": "", - "Enter value (true/false)": "", - "Enter Yacy Password": "", - "Enter Yacy URL (e.g. http://yacy.example.com:8090)": "", - "Enter Yacy Username": "", - "Enter Yandex Web Search API Key": "", - "Enter Yandex Web Search URL": "", - "Enter You.com API Key": "", + "Enter value": "Voer waarde in", + "Enter value (true/false)": "Voer waarde in (true/false)", + "Enter Yacy Password": "Voer Yacy-wachtwoord in", + "Enter Yacy URL (e.g. http://yacy.example.com:8090)": "Voer Yacy-URL in (bijv. http://yacy.example.com:8090)", + "Enter Yacy Username": "Voer Yacy-gebruikersnaam in", + "Enter Yandex Web Search API Key": "Voer Yandex Web Search API-sleutel in", + "Enter Yandex Web Search URL": "Voer Yandex Web Search-URL in", + "Enter You.com API Key": "Voer You.com API-sleutel in", "Enter your code here...": "Voer hier je code in...", "Enter your current password": "Voer je huidige wachtwoord in", "Enter Your Email": "Voer je Email in", "Enter Your Full Name": "Voer je Volledige Naam in", - "Enter your gender": "", + "Enter your gender": "Voer je geslacht in", "Enter your message": "Voer je bericht in", - "Enter your name": "", - "Enter Your Name": "", + "Enter your name": "Voer je naam in", + "Enter Your Name": "Voer je naam in", "Enter your new password": "Voer je nieuwe wachtwoord in", "Enter Your Password": "Voer je wachtwoord in", "Enter Your Role": "Voer je rol in", "Enter Your Username": "Voer je gebruikersnaam in", "Enter your webhook URL": "Voer je webhook-URL in", - "Entra ID": "", - "Environment Variables": "", - "Ephemeral": "", + "Entra ID": "Entra-ID", + "Environment Variables": "Omgevingsvariabelen", + "Ephemeral": "Tijdelijk", "Error": "Fout", "ERROR": "ERROR", - "Error accessing directory": "", + "Error accessing directory": "Fout bij toegang tot map", "Error accessing Google Drive: {{error}}": "Fout bij het benaderen van Google Drive: {{error}}", - "Error accessing media devices.": "", - "Error deleting model: {{error}}": "", - "Error starting recording.": "", - "Error unloading model: {{error}}": "", - "Error uploading file: {{error}}": "Error bij het uploaden van bestand: {{error}}", - "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "", - "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "", + "Error accessing media devices.": "Fout bij toegang tot media-apparaten.", + "Error starting recording.": "Fout bij het starten van de opname.", + "Error unloading model: {{error}}": "Fout bij het ontladen van model: {{error}}", + "Error deleting model: {{error}}": "Fout bij het verwijderen van model: {{error}}", + "Error uploading file: {{error}}": "Fout bij het uploaden van bestand: {{error}}", + "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Fout: Een model met de ID '{{modelId}}' bestaat al. Selecteer een andere ID om door te gaan.", + "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Fout: Model-ID mag niet leeg zijn. Voer een geldige ID in om door te gaan.", "Evaluations": "Beoordelingen", - "Event created": "", - "Event deleted": "", - "Event title": "", - "Event updated": "", + "Event created": "Gebeurtenis aangemaakt", + "Event deleted": "Gebeurtenis verwijderd", + "Event title": "Gebeurtenis titel", + "Event updated": "Gebeurtenis bijgewerkt", "Exa API Key": "Exa API-sleutel", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Voorbeeld: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Voorbeeld: ALL", "Example: mail": "Voorbeeld: mail", "Example: ou=users,dc=foo,dc=example": "Voorbeeld: ou=users,dc=foo,dc=example", "Example: sAMAccountName or uid or userPrincipalName": "Voorbeeld: sAMAccountName or uid or userPrincipalName", - "Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "Het aantal seats in uw licentie is overschreden. Neem contact op met support om het aantal seats te verhogen.", + "Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "Het aantal seats in je licentie is overschreden. Neem contact op met support om het aantal seats te verhogen.", "Exclude": "Sluit uit", - "Execute code": "", + "Execute code": "Code uitvoeren", "Execute code for analysis": "Voer code uit voor analyse", - "Executing **{{NAME}}**...": "", - "Execution Logs": "", + "Executing **{{NAME}}**...": "**{{NAME}}** uitvoeren...", + "Execution Logs": "Uitvoerlogs", "Expand": "Uitbreiden", "Experimental": "Experimenteel", "Explain": "Leg uit", "Explore the cosmos": "Ontdek de kosmos", - "Explored": "", - "Exploring": "", + "Explored": "Verkend", + "Exploring": "Verkennen", "Export": "Exporteren", "Export All Archived Chats": "Exporteer alle gearchiveerde chats", "Export All Chats (All Users)": "Exporteer alle chats (Alle gebruikers)", - "Export as CSV": "", - "Export as JSON": "", + "Export as CSV": "Exporteer als CSV", + "Export as JSON": "Exporteer als JSON", "Export chat (.json)": "Exporteer chat (.json)", "Export Chats": "Exporteer chats", - "Export Config": "", - "Export Models": "", - "Export Prompts": "", + "Export Config": "Configuratie exporteren", + "Export Models": "Modellen exporteren", + "Export Prompts": "Prompts exporteren", "Export to CSV": "Exporteer naar CSV", - "Export Tools": "", - "Export Users": "", + "Export Tools": "Tools exporteren", + "Export Users": "Gebruikers exporteren", "External": "Extern", - "External Document Loader URL required.": "", - "External Task Model": "", - "External Web Loader API Key": "", - "External Web Loader URL": "", - "External Web Search API Key": "", - "External Web Search URL": "", - "Fade Effect for Streaming Text": "", + "External Document Loader URL required.": "Externe documentloader-URL is vereist.", + "External Task Model": "Extern taakmodel", + "External Web Loader API Key": "Externe webloader-API-sleutel", + "External Web Loader URL": "Externe webloader-URL", + "External Web Search API Key": "Externe webzoek-API-sleutel", + "External Web Search URL": "Externe webzoek-URL", + "Fade Effect for Streaming Text": "Fade-effect voor streamende tekst", "Failed to add file.": "Het is niet gelukt om het bestand toe te voegen.", - "Failed to add members": "", - "Failed to archive chat.": "", - "Failed to attach file": "", - "Failed to clear status": "", + "Failed to add members": "Leden toevoegen mislukt", + "Failed to archive chat.": "Chat archiveren mislukt.", + "Failed to attach file": "Bestand toevoegen mislukt", + "Failed to clear status": "Status wissen mislukt", "Failed to connect to {{URL}} OpenAPI tool server": "Kan geen verbinding maken met {{URL}} OpenAPI gereedschapserver", - "Failed to connect to {{URL}} terminal server": "", - "Failed to copy link": "", + "Failed to connect to {{URL}} terminal server": "Kan geen verbinding maken met {{URL}} terminalserver", + "Failed to copy link": "Link kopiëren mislukt", "Failed to create API Key.": "Kan API Key niet aanmaken.", - "Failed to delete calendar": "", - "Failed to delete note": "", - "Failed to download image": "", - "Failed to extract content from the file: {{error}}": "", - "Failed to extract content from the file.": "", + "Failed to delete note": "Notitie verwijderen mislukt", + "Failed to download image": "Afbeelding downloaden mislukt", + "Failed to extract content from the file: {{error}}": "Inhoud uit bestand extraheren mislukt: {{error}}", + "Failed to extract content from the file.": "Inhoud uit bestand extraheren mislukt.", + "Failed to delete calendar": "Kalender verwijderen mislukt", "Failed to fetch models": "Kan modellen niet ophalen", - "Failed to generate title": "", - "Failed to import models": "", - "Failed to load chat preview": "", - "Failed to load DOCX file. Please try downloading it instead.": "", - "Failed to load Excel/CSV file. Please try downloading it instead.": "", - "Failed to load file content.": "", - "Failed to load Interface settings": "", - "Failed to load PPTX file. Please try downloading it instead.": "", - "Failed to move chat": "", - "Failed to process URL: {{url}}": "", + "Failed to generate title": "Titel genereren mislukt", + "Failed to import models": "Modellen importeren mislukt", + "Failed to load chat preview": "Voorvertoning van chat laden mislukt", + "Failed to load DOCX file. Please try downloading it instead.": "DOCX-bestand laden mislukt. Probeer het in plaats daarvan te downloaden.", + "Failed to load Excel/CSV file. Please try downloading it instead.": "Excel/CSV-bestand laden mislukt. Probeer het in plaats daarvan te downloaden.", + "Failed to load file content.": "Bestandsinhoud laden mislukt.", + "Failed to load Interface settings": "Interface-instellingen laden mislukt", + "Failed to load PPTX file. Please try downloading it instead.": "PPTX-bestand laden mislukt. Probeer het in plaats daarvan te downloaden.", + "Failed to move chat": "Chat verplaatsen mislukt", + "Failed to process URL: {{url}}": "URL verwerken mislukt: {{url}}", "Failed to read clipboard contents": "Kan klembord inhoud niet lezen", - "Failed to remove member": "", - "Failed to render diagram": "", - "Failed to render visualization": "", - "Failed to save connections": "", + "Failed to remove member": "Lid verwijderen mislukt", + "Failed to render diagram": "Diagram renderen mislukt", + "Failed to render visualization": "Visualisatie renderen mislukt", + "Failed to save connections": "Verbindingen opslaan mislukt", "Failed to save conversation": "Het is niet gelukt om het gesprek op te slaan", "Failed to save models configuration": "Het is niet gelukt om de modelconfiguratie op te slaan", - "Failed to save policy: {{error}}": "", - "Failed to save terminal servers": "", - "Failed to unshare chat.": "", + "Failed to save policy: {{error}}": "Beleid opslaan mislukt: {{error}}", + "Failed to save terminal servers": "Terminalservers opslaan mislukt", + "Failed to unshare chat.": "Delen van chat opheffen mislukt.", "Failed to update settings": "Instellingen konden niet worden bijgewerkt.", - "Failed to update status": "", + "Failed to update status": "Status bijwerken mislukt", "Failed to upload file.": "Bestand kon niet worden geüpload.", "Features": "Functies", "Features Permissions": "Functietoestemmingen", - "February": "Februari", - "Feedback": "", - "Feedback Activity": "", - "Feedback deleted successfully": "", - "Feedback Details": "", + "February": "februari", + "Feedback": "Feedback", + "Feedback Activity": "Feedbackactiviteit", + "Feedback deleted successfully": "Feedback succesvol verwijderd", + "Feedback Details": "Feedbackdetails", "Feedback History": "Feedback geschiedenis", "Feel free to add specific details": "Voeg specifieke details toe", - "Female": "", - "Fetch URL Content Length Limit": "", + "Female": "Vrouw", + "Fetch URL Content Length Limit": "Limiet voor URL-inhoudslengte ophalen", "File": "Bestand", "File added successfully.": "Bestand succesvol toegevoegd.", - "File attached to chat": "", - "File browser": "", - "File content": "", + "File attached to chat": "Bestand toegevoegd aan chat", + "File browser": "Bestandsverkenner", + "File content": "Bestandsinhoud", "File content updated successfully.": "Bestandsinhoud succesvol bijgewerkt.", - "File Context": "", - "File deleted successfully.": "", + "File Context": "Bestandscontext", + "File deleted successfully.": "Bestand succesvol verwijderd.", "File Mode": "Bestandsmodus", - "File name": "", + "File name": "Bestandsnaam", "File not found.": "Bestand niet gevonden.", "File removed successfully.": "Bestand succesvol verwijderd.", "File size should not exceed {{maxSize}} MB.": "Bestandsgrootte mag niet groter zijn dan {{maxSize}} MB.", - "File Upload": "", + "File Upload": "Bestandsupload", "File uploaded successfully": "Bestand succesvol geüpload", - "File uploaded!": "", - "Filename": "", + "File uploaded!": "Bestand geüpload!", + "Filename": "Bestandsnaam", "Files": "Bestanden", - "Filter": "", + "Filter": "Filter", "Filter is now globally disabled": "Filter is nu globaal uitgeschakeld", "Filter is now globally enabled": "Filter is nu globaal ingeschakeld", "Filters": "Filters", "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Vingerafdruk spoofing gedetecteerd: kan initialen niet gebruiken als avatar. Standaardprofielafbeelding wordt gebruikt.", - "Firecrawl API Base URL": "", - "Firecrawl API Key": "", - "Firecrawl Timeout (s)": "", - "Floating Quick Actions": "", - "Focus Chat Input": "", - "Folder": "", - "Folder Background Image": "", - "Folder created successfully": "", + "Firecrawl API Base URL": "Firecrawl API-basis-URL", + "Firecrawl API Key": "Firecrawl API-sleutel", + "Firecrawl Timeout (s)": "Firecrawl-time-out (s)", + "Floating Quick Actions": "Zwevende snelle acties", + "Focus Chat Input": "Focus op chatinvoer", + "Folder": "Map", + "Folder Background Image": "Achtergrondafbeelding map", + "Folder created successfully": "Map succesvol aangemaakt", "Folder deleted successfully": "Map succesvol verwijderd", - "Folder Max File Count": "", - "Folder name": "", - "Folder Name": "", + "Folder Max File Count": "Maximaal aantal bestanden in map", + "Folder name": "Mapnaam", + "Folder Name": "Mapnaam", "Folder name cannot be empty.": "Mapnaam kan niet leeg zijn", "Folder name updated successfully": "Mapnaam succesvol aangepast", - "Folder options": "", - "Folder updated successfully": "", - "Folders": "", - "Follow up": "", - "Follow Up Generation": "", - "Follow Up Generation Prompt": "", - "Follow up: {{question}}": "", - "Follow-Up Auto-Generation": "", + "Folder options": "Mapopties", + "Folder updated successfully": "Map succesvol bijgewerkt", + "Folders": "Mappen", + "Follow up": "Vervolg", + "Follow Up Generation": "Vervolggeneratie", + "Follow Up Generation Prompt": "Prompt voor vervolggeneratie", + "Follow up: {{question}}": "Vervolg: {{question}}", + "Follow-Up Auto-Generation": "Automatische vervolggeneratie", + "for placeholders": "voor placeholders", + "Force OCR": "OCR forceren", + "Force OCR on all pages of the PDF. This can lead to worse results if you have good text in your PDFs. Defaults to False.": "Forceer OCR op alle pagina's van de PDF. Dit kan slechtere resultaten geven als je PDF's al goede tekst bevatten. Standaard is False.", + "Format Lines": "Regels opmaken", + "Format the lines in the output. Defaults to False. If set to True, the lines will be formatted to detect inline math and styles.": "Formatteer de regels in de uitvoer. Standaard is False. Als ingesteld op True worden regels opgemaakt om inline wiskunde en stijlen te detecteren.", + "Formatting may be inconsistent from source.": "Opmaak kan afwijken van de bron.", + "Forward": "Vooruit", + "Forwards system user OAuth access token to authenticate": "Stuurt OAuth-toegangstoken van systeemgebruiker door voor authenticatie", + "Forwards system user session credentials to authenticate": "Stuurt sessiegegevens van systeemgebruiker door voor authenticatie", + "Model accepts file inputs": "Model accepteert bestandsinvoer", + "Model can execute code and perform calculations": "Model kan code uitvoeren en berekeningen maken", + "Model can generate images based on text prompts": "Model kan afbeeldingen genereren op basis van tekstprompts", + "Model can search the web for information": "Model kan het web doorzoeken naar informatie", + "Model Capabilities": "Modelmogelijkheden", + "New File": "Nieuw bestand", + "New Function": "Nieuwe functie", + "New Group": "Nieuwe groep", + "New Knowledge": "Nieuwe kennis", + "New Model": "Nieuw model", + "New Note": "Nieuwe notitie", + "New Prompt": "Nieuwe prompt", + "Generated Image": "Gegenereerde afbeelding", + "Generated images will appear here": "Gegenereerde afbeeldingen verschijnen hier", "Followed instructions perfectly": "Volgde instructies perfect", - "for placeholders": "", - "Force OCR": "", - "Force OCR on all pages of the PDF. This can lead to worse results if you have good text in your PDFs. Defaults to False.": "", - "Forge new paths": "Smeed nieuwe paden", + "Forge new paths": "Baan nieuwe paden", "Form": "Formulier", - "Format Lines": "", - "Format the lines in the output. Defaults to False. If set to True, the lines will be formatted to detect inline math and styles.": "", - "Formatting may be inconsistent from source.": "", - "Forward": "", - "Forwards system user OAuth access token to authenticate": "", - "Forwards system user session credentials to authenticate": "", - "Fr_day_of_week": "", + "Fr_day_of_week": "vr", "Full Context Mode": "Volledige contextmodus", "Function": "Functie", "Function Calling": "Functieaanroep", @@ -1001,274 +1015,272 @@ "Function deleted successfully": "Functie succesvol verwijderd", "Function Description": "Functiebeschrijving", "Function ID": "Functie-ID", - "Function imported successfully": "", + "Function imported successfully": "Functie succesvol geimporteerd", "Function is now globally disabled": "Functie is nu globaal uitgeschakeld", "Function is now globally enabled": "Functie is nu globaal ingeschakeld", "Function Name": "Functienaam", - "Function Name Filter List": "", + "Function Name Filter List": "Filterlijst voor functienamen", "Function updated successfully": "Functienaam succesvol aangepast", "Functions": "Functies", "Functions allow arbitrary code execution.": "Functies staan willekeurige code-uitvoering toe", "Functions imported successfully": "Functies succesvol geïmporteerd", "Gemini": "Gemini", - "Gemini API Key": "", + "Gemini API Key": "Gemini API-sleutel", "Gemini API Key is required.": "Gemini API-sleutel is vereisd", - "Gemini Base URL": "", - "Gemini Endpoint Method": "", - "Gender": "", + "Gemini Base URL": "Gemini basis-URL", + "Gemini Endpoint Method": "Gemini endpointmethode", + "Gender": "Geslacht", "General": "Algemeen", - "Generate": "", + "Generate": "Genereren", "Generate an image": "Genereer een afbeelding", - "Generate and edit images": "", - "Generate Message Pair": "", - "Generated Image": "", - "Generated images will appear here": "", + "Generate and edit images": "Afbeeldingen genereren en bewerken", + "Generate Message Pair": "Berichtenpaar genereren", "Generating search query": "Zoekopdracht genereren", - "Generating...": "", - "Get current time and perform date/time calculations": "", - "Get information on {{name}} in the UI": "", + "Generating...": "Genereren...", + "Get current time and perform date/time calculations": "Haal de huidige tijd op en voer datum-/tijdberekeningen uit", + "Get information on {{name}} in the UI": "Haal informatie op over {{name}} in de UI", "Get started": "Begin", "Get started with {{WEBUI_NAME}}": "Begin met {{WEBUI_NAME}}", "Global": "Globaal", "Good Response": "Goed antwoord", - "Google": "", + "Google": "Google", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API-sleutel", "Google PSE Engine Id": "Google PSE-engine-ID", - "Gravatar": "", - "Grid": "", - "Grokipedia": "", - "Group Channel": "", + "Gravatar": "Gravatar", + "Grid": "Raster", + "Grokipedia": "Grokipedia", + "Group Channel": "Groepskanaal", "Group created successfully": "Groep succesvol aangemaakt", "Group deleted successfully": "Groep succesvol verwijderd", "Group Description": "Groepsbeschrijving", "Group Name": "Groepsnaam", "Group updated successfully": "Groep succesvol bijgewerkt", - "groups": "", + "groups": "groepen", "Groups": "Groepen", - "H1": "", - "H2": "", - "H3": "", + "H1": "H1", + "H2": "H2", + "H3": "H3", "Haptic Feedback": "Haptische feedback", - "Headers": "", - "Headers must be a valid JSON object": "", - "Height": "", + "Headers": "headers", + "Headers must be a valid JSON object": "Headers moeten een geldig JSON-object zijn", + "Height": "Hoogte", "Hello, {{name}}": "Hallo, {{name}}", "Help": "Help", - "Help the community discover great models": "", + "Help the community discover great models": "Help de community geweldige modellen te ontdekken", "Hex Color": "Hex-kleur", "Hex Color - Leave empty for default color": "Hex-kleur - laat leeg voor standaardkleur", - "Hidden": "", + "Hidden": "Verborgen", "Hide": "Verberg", - "Hide All": "", - "Hide from Sidebar": "", + "Hide All": "Verberg alles", + "Hide from Sidebar": "Verberg in zijbalk", "Hide Model": "Verberg model", - "High": "", - "High Contrast Mode": "", - "History": "", + "High": "Hoog", + "High Contrast Mode": "Hoog contrastmodus", + "History": "Geschiedenis", "Home": "Thuis", "Host": "Host", - "Hourly": "", - "Hourly Messages": "", + "Hourly": "Per uur", + "Hourly Messages": "Berichten per uur", "How can I help you today?": "Hoe kan ik je vandaag helpen?", "How would you rate this response?": "Hoe zou je dit antwoord beoordelen?", - "HTML": "", - "http://localhost:8000": "", - "https://mineru.net/api/v4": "", + "HTML": "HTML", + "http://localhost:8000": "http://localhost:8000", + "https://mineru.net/api/v4": "https://mineru.net/api/v4", "Hybrid Search": "Hybride Zoeken", "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.": "Ik bevestig dat ik de implicaties van mijn actie heb gelezen en begrepen. Ik ben me bewust van de risico's die gepaard gaan met het uitvoeren van willekeurige code en ik heb de betrouwbaarheid van de bron gecontroleerd.", "ID": "ID", - "ID cannot contain \":\" or \"|\" characters": "", - "ID copied to clipboard": "", - "Idle Timeout": "", - "iframe Sandbox Allow Forms": "", - "iframe Sandbox Allow Same Origin": "", + "ID cannot contain \":\" or \"|\" characters": "ID mag geen tekens \":\" of \"|\" bevatten", + "ID copied to clipboard": "ID gekopieerd naar klembord", + "Idle Timeout": "Inactiviteitstime-out", + "iframe Sandbox Allow Forms": "iframe-sandbox formulieren toestaan", + "iframe Sandbox Allow Same Origin": "iframe-sandbox zelfde oorsprong toestaan", "Ignite curiosity": "Wakker nieuwsgierigheid aan", "Image": "Afbeelding", "Image Compression": "Afbeeldingscompressie", - "Image Compression Height": "", - "Image Compression Width": "", - "Image Edit": "", - "Image Edit Engine": "", + "Image Compression Height": "Hoogte afbeeldingscompressie", + "Image Compression Width": "Breedte afbeeldingscompressie", + "Image Edit": "Afbeelding bewerken", + "Image Edit Engine": "Engine voor afbeeldingsbewerking", "Image Generation": "Afbeeldingsgeneratie", "Image Generation Engine": "Afbeeldingsgeneratie Engine", "Image Max Compression Size": "Maximale afbeeldingscompressiegrootte", - "Image Max Compression Size height": "", - "Image Max Compression Size width": "", + "Image Max Compression Size height": "Maximale afbeeldingscompressiegrootte hoogte", + "Image Max Compression Size width": "Maximale afbeeldingscompressiegrootte breedte", "Image Prompt Generation": "Afbeeldingspromptgeneratie", "Image Prompt Generation Prompt": "Afbeeldingspromptgeneratie prompt", - "Image Size": "", - "Images": "", - "Import": "", + "Image Size": "Afbeeldingsgrootte", + "Images": "Afbeeldingen", + "Import": "Importeren", "Import Chats": "Importeer Chats", - "Import Config": "", - "Import From Link": "", - "Import Models": "", - "Import Prompts": "", - "Import successful": "", - "Import Tools": "", + "Import Config": "Configuratie importeren", + "Import From Link": "Importeren via link", + "Import Models": "Modellen importeren", + "Import Prompts": "Prompts importeren", + "Import successful": "Importeren geslaagd", + "Import Tools": "Tools importeren", "Important Update": "Belangrijke update", - "Inactive": "", + "Inactive": "Inactief", "Include": "Voeg toe", - "Include `--api-auth` flag when running stable-diffusion-webui": "Voeg '--api-auth` toe bij het uitvoeren van stable-diffusion-webui", + "Include `--api-auth` flag when running stable-diffusion-webui": "Voeg de `--api-auth`-vlag toe bij het uitvoeren van stable-diffusion-webui", "Include `--api` flag when running stable-diffusion-webui": "Voeg `--api` vlag toe bij het uitvoeren van stable-diffusion-webui", "Includes SharePoint": "Inclusief SharePoint", - "Increase UI Scale": "", + "Increase UI Scale": "UI-schaal vergroten", "Influences how quickly the algorithm responds to feedback from the generated text. A lower learning rate will result in slower adjustments, while a higher learning rate will make the algorithm more responsive.": "Beïnvloedt hoe snel het algoritme reageert op feedback van de gegenereerde tekst. Een lagere leersnelheid resulteert in langzamere aanpassingen, terwijl een hogere leersnelheid het algoritme responsiever maakt.", "Info": "Info", - "Initials": "", - "Inject file content into conversation context": "", + "Initials": "Initialen", + "Inject file content into conversation context": "Bestandsinhoud in gesprekscontext injecteren", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injecteer de volledige inhoud als context voor uitgebreide verwerking, dit wordt aanbevolen voor complexe query's.", - "Input": "", - "Input Key (e.g. text, unet_name, steps)": "", - "Input Variables": "", - "Insert": "", - "Insert Follow-Up Prompt to Input": "", - "Insert Prompt as Rich Text": "", - "Insert Suggestion Prompt to Input": "", + "Input": "Invoer", + "Input Key (e.g. text, unet_name, steps)": "Invoersleutel (bijv. text, unet_name, steps)", + "Input Variables": "Invoervariabelen", + "Insert": "Invoegen", + "Insert Follow-Up Prompt to Input": "Vervolgprompt in invoer invoegen", + "Insert Prompt as Rich Text": "Prompt als rich text invoegen", + "Insert Suggestion Prompt to Input": "Suggestieprompt in invoer invoegen", "Install from Github URL": "Installeren vanaf Github-URL", "Instant Auto-Send After Voice Transcription": "Direct automatisch verzenden na spraaktranscriptie", - "Instructions": "", + "Instructions": "Instructies", "Integration": "Integratie", - "Integrations": "", + "Integrations": "Integraties", "Interface": "Interface", - "Interface Settings Access": "", - "Invalid file content": "", + "Interface Settings Access": "Toegang tot interface-instellingen", + "Invalid file content": "Ongeldige bestandsinhoud", "Invalid file format.": "Ongeldig bestandsformaat", - "Invalid JSON file": "", - "Invalid JSON format for ComfyUI Edit Workflow.": "", - "Invalid JSON format for ComfyUI Workflow.": "", - "Invalid JSON format for Parameters": "", - "Invalid JSON format in {{NAME}}": "", - "Invalid JSON format in Additional Config": "", - "Invalid JSON format in MinerU Parameters": "", + "Invalid JSON file": "Ongeldig JSON-bestand", + "Invalid JSON format for ComfyUI Edit Workflow.": "Ongeldig JSON-formaat voor ComfyUI Edit Workflow.", + "Invalid JSON format for ComfyUI Workflow.": "Ongeldig JSON-formaat voor ComfyUI Workflow.", + "Invalid JSON format for Parameters": "Ongeldig JSON-formaat voor parameters", + "Invalid JSON format in {{NAME}}": "Ongeldig JSON-formaat in {{NAME}}", + "Invalid JSON format in Additional Config": "Ongeldig JSON-formaat in aanvullende configuratie", + "Invalid JSON format in MinerU Parameters": "Ongeldig JSON-formaat in MinerU-parameters", "is typing...": "is aan het schrijven...", - "Italic": "", - "January": "Januari", - "Jina API Base URL": "", + "Italic": "Cursief", + "January": "januari", + "Jina API Base URL": "Jina API-basis-URL", "Jina API Key": "Jina API-sleutel", - "join our Discord for help.": "join onze Discord voor hulp.", + "join our Discord for help.": "word lid van onze Discord voor hulp.", "JSON": "JSON", "JSON Preview": "JSON-voorbeeld", - "JSON Spec": "", - "July": "Juli", - "June": "Juni", + "JSON Spec": "JSON-specificatie", + "July": "juli", + "June": "juni", "Jupyter Auth": "Jupyter Auth", "Jupyter URL": "Jupyter URL", "JWT Expiration": "JWT Expiration", "JWT Token": "JWT Token", "Kagi Search API Key": "Kagi Search API-sleutel", - "Keep Follow-Up Prompts in Chat": "", - "Keep in Sidebar": "", + "Keep Follow-Up Prompts in Chat": "Vervolgprompts in chat houden", + "Keep in Sidebar": "In zijbalk houden", "Key": "Sleutel", - "Key is required": "", - "Keyboard shortcuts": "Toetsenbord snelkoppelingen", - "Keyboard Shortcuts": "", + "Key is required": "Sleutel is vereist", + "Keyboard shortcuts": "Toetsenbordsnelkoppelingen", + "Keyboard Shortcuts": "Toetsenbordsnelkoppelingen", "Knowledge": "Kennis", "Knowledge Access": "Kennistoegang", - "Knowledge Base": "", + "Knowledge Base": "Kennisbank", "Knowledge created successfully.": "Kennis succesvol aangemaakt", "Knowledge deleted successfully.": "Kennis succesvol verwijderd", - "Knowledge Description": "", - "Knowledge exported successfully": "", - "Knowledge Name": "", + "Knowledge Description": "Kennisbeschrijving", + "Knowledge exported successfully": "Kennis succesvol geexporteerd", + "Knowledge Name": "Kennisnaam", "Knowledge Public Sharing": "Publieke kennisdeling", "Knowledge reset successfully.": "Kennis succesvol gereset", - "Knowledge Sharing": "", + "Knowledge Sharing": "Kennisdeling", "Knowledge updated successfully": "Kennis succesvol bijgewerkt", "Kokoro.js (Browser)": "Kokoro.js (Browser)", "Kokoro.js Dtype": "Kokoro.js Dtype", "Label": "Label", "Landing Page Mode": "Landingspaginamodus", "Language": "Taal", - "Language Locales": "", - "Last 24 hours": "", - "Last 30 days": "", - "Last 7 days": "", - "Last 90 days": "", + "Language Locales": "Taallocaties", + "Last 24 hours": "Laatste 24 uur", + "Last 30 days": "Laatste 30 dagen", + "Last 7 days": "Laatste 7 dagen", + "Last 90 days": "Laatste 90 dagen", "Last Active": "Laatst Actief", "Last Modified": "Laatst aangepast", - "Last ran": "", + "Last ran": "Laatst uitgevoerd", "Last reply": "Laatste antwoord", "LDAP": "LDAP", "LDAP server updated": "LDAP-server bijgewerkt", "Leaderboard": "Klassement", - "Learn more": "", - "Learn More": "", - "Learn more about Open Terminal": "", - "Learn more about OpenAPI tool servers.": "", - "Learn more about Voxtral transcription.": "", - "Leave a public review for {{modelName}}": "", - "Leave empty for no compression": "", + "Learn more": "Meer informatie", + "Learn More": "Meer informatie", + "Learn more about Open Terminal": "Meer informatie over Open Terminal", + "Learn more about OpenAPI tool servers.": "Meer informatie over OpenAPI-toolservers.", + "Learn more about Voxtral transcription.": "Meer informatie over Voxtral-transcriptie.", + "Leave a public review for {{modelName}}": "Laat een openbare beoordeling achter voor {{modelName}}", + "Leave empty for no compression": "Laat leeg voor geen compressie", "Leave empty for unlimited": "Laat leeg voor ongelimiteerd", - "Leave empty to include all models from \"{{url}}\" endpoint": "", + "Leave empty to include all models from \"{{url}}\" endpoint": "Laat leeg om alle modellen van het \"{{url}}\"-endpoint mee te nemen", "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Laat leeg om alle modellen van het \"{{url}}/api/tags\"-endpoint mee te nemen", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Laat leeg om alle modellen van \"{{url}}/models\"-endpoint mee te nemen", "Leave empty to include all models or select specific models": "Laat leeg om alle modellen mee te nemen, of selecteer specifieke modellen", - "Leave empty to use first admin user": "", - "Leave empty to use the default config, or enter a valid json (see https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest)": "", - "Leave empty to use the default model (voxtral-mini-latest).": "", + "Leave empty to use first admin user": "Laat leeg om de eerste beheerder te gebruiken", + "Leave empty to use the default config, or enter a valid json (see https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest)": "Laat leeg om de standaardconfiguratie te gebruiken, of voer geldige json in (zie https://yandex.cloud/en/docs/search-api/api-ref/WebSearch/search#yandex.cloud.searchapi.v2.WebSearchRequest)", + "Leave empty to use the default model (voxtral-mini-latest).": "Laat leeg om het standaardmodel te gebruiken (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Laat leeg om de standaard prompt te gebruiken, of selecteer een aangepaste prompt", "Leave model field empty to use the default model.": "Laat modelveld leeg om het standaardmodel te gebruiken.", - "Legacy": "", - "lexical": "", + "Legacy": "Legacy", + "lexical": "lexicaal", "License": "Licentie", - "Lift List": "", + "Lift List": "Lift-lijst", "Light": "Licht", - "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", - "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "", - "List": "", - "List calendars, search, create, update, and delete calendar events": "", + "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Beperk gelijktijdige zoekopdrachten. 0 = onbeperkt (standaard). Stel in op 1 voor sequentiele uitvoering (aanbevolen voor API's met strikte rate limits, zoals Brave free tier).", + "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "Beperkt het aantal gelijktijdige embeddingverzoeken. Stel in op 0 voor onbeperkt.", + "List": "Lijst", + "List calendars, search, create, update, and delete calendar events": "Agenda's weergeven, zoeken, maken, bijwerken en agenda-afspraken verwijderen", "Listening...": "Aan het luisteren...", - "Live": "", + "Live": "Live", "Llama.cpp": "Llama.cpp", "LLMs can make mistakes. Verify important information.": "LLMs kunnen fouten maken. Verifieer belangrijke informatie.", "Loader": "Lader", "Loading Kokoro.js...": "Kokoro.js aan het laden", "Loading...": "...", - "local": "", + "local": "lokaal", "Local": "Lokaal", - "Local Task Model": "", - "Location": "", + "Local Task Model": "Lokaal taakmodel", + "Location": "Locatie", "Location access not allowed": "Locatietoegang niet toegestaan", "Lost": "Verloren", - "Low": "", + "Low": "Laag", "LTR": "LNR", "Made by Open WebUI Community": "Gemaakt door OpenWebUI Community", - "Make password visible in the user interface": "", + "Make password visible in the user interface": "Maak wachtwoord zichtbaar in de gebruikersinterface", "Make sure to export a workflow.json file as API format from ComfyUI.": "Zorg ervoor dat je een workflow.json-bestand als API-formaat exporteert vanuit ComfyUI.", - "Male": "", + "Male": "Man", "Manage": "Beheren", - "Manage Connections": "", + "Manage Connections": "Verbindingen beheren", "Manage Direct Connections": "Beheer directe verbindingen", - "Manage Files": "", + "Manage Files": "Bestanden beheren", "Manage Models": "Beheer modellen", "Manage Ollama": "Beheer Ollama", "Manage Ollama API Connections": "Beheer Ollama API-verbindingen", "Manage OpenAI API Connections": "Beheer OpenAI API-verbindingen", "Manage Pipelines": "Pijplijnen beheren", "Manage Tool Servers": "Beheer gereedschapservers", - "Manage your account information.": "", - "March": "Maart", - "Markdown": "", - "Markdown Header Text Splitter": "", - "Max Speakers": "", + "Manage your account information.": "Beheer je accountinformatie.", + "March": "maart", + "Markdown": "Markdown", + "Markdown Header Text Splitter": "Markdown-koptekstsplitser", + "Max Speakers": "Maximale sprekers", "Max Upload Count": "Maximale Uploadhoeveelheid", "Max Upload Size": "Maximale Uploadgrootte", - "Maximum characters to return from fetched URLs. Leave empty for no limit.": "", - "Maximum number of files allowed per folder.": "", - "Maximum number of files per folder is {{max}}.": "", + "Maximum characters to return from fetched URLs. Leave empty for no limit.": "Maximaal aantal tekens dat wordt teruggegeven uit opgehaalde URL's. Laat leeg voor geen limiet.", + "Maximum number of files allowed per folder.": "Maximaal aantal toegestane bestanden per map.", + "Maximum number of files per folder is {{max}}.": "Maximum aantal bestanden per map is {{max}}.", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximaal 3 modellen kunnen tegelijkertijd worden gedownload. Probeer het later opnieuw.", + "MBR": "MBR", + "MCP": "MCP", + "MCP support is experimental and its specification changes often, which can lead to incompatibilities. OpenAPI specification support is directly maintained by the Open WebUI team, making it the more reliable option for compatibility.": "MCP-ondersteuning is experimenteel en de specificatie verandert vaak, wat tot incompatibiliteiten kan leiden. Ondersteuning voor de OpenAPI-specificatie wordt direct onderhouden door het Open WebUI-team, waardoor dit de betrouwbaardere optie voor compatibiliteit is.", + "Medium": "Gemiddeld", + "Member removed successfully": "Lid succesvol verwijderd", + "members": "leden", + "Members": "Leden", "May": "Mei", - "MBR": "", - "MCP": "", - "MCP support is experimental and its specification changes often, which can lead to incompatibilities. OpenAPI specification support is directly maintained by the Open WebUI team, making it the more reliable option for compatibility.": "", - "Medium": "", - "Member removed successfully": "", - "members": "", - "Members": "", - "Members added successfully": "", - "Memories": "", + "Members added successfully": "Leden succesvol toegevoegd", + "Memories": "Geheugen", "Memories accessible by LLMs will be shown here.": "Geheugen toegankelijk voor LLMs wordt hier getoond.", "Memory": "Geheugen", "Memory added successfully": "Geheugen succesvol toegevoegd", @@ -1277,410 +1289,398 @@ "Memory updated successfully": "Geheugen succesvol bijgewerkt", "Merge Responses": "Voeg antwoorden samen", "Merged Response": "Samengevoegd antwoord", - "Message": "", - "Message counts and response timestamps": "", - "Message counts are based on assistant responses.": "", + "Message": "Bericht", + "Message counts and response timestamps": "Berichtaantallen en tijdstempels van reacties", + "Message counts are based on assistant responses.": "Berichtaantallen zijn gebaseerd op reacties van de assistent.", "Message rating should be enabled to use this feature": "Berichtbeoordeling moet ingeschakeld zijn om deze functie te gebruiken", - "messages": "", - "Messages": "", + "messages": "berichten", + "Messages": "Berichten", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Berichten die je verzendt nadat je jouw link hebt gemaakt, worden niet gedeeld. Gebruikers met de URL kunnen de gedeelde chat bekijken.", - "Microsoft OneDrive": "", - "Microsoft OneDrive (personal)": "", - "Microsoft OneDrive (work/school)": "", - "min": "", - "MinerU": "", - "MinerU API Key required for Cloud API mode.": "", - "Mistral OCR": "", - "Mistral OCR API Key required.": "", - "MistralAI": "", - "Mo_day_of_week": "", + "Microsoft OneDrive": "Microsoft OneDrive", + "Microsoft OneDrive (personal)": "Microsoft OneDrive (persoonlijk)", + "Microsoft OneDrive (work/school)": "Microsoft OneDrive (werk/opleiding)", + "min": "min", + "MinerU": "MinerU", + "MinerU API Key required for Cloud API mode.": "MinerU API-sleutel vereist voor Cloud API-modus.", + "Mistral OCR": "Mistral OCR", + "Mistral OCR API Key required.": "Mistral OCR API-sleutel vereist.", + "MistralAI": "MistralAI", + "Mo_day_of_week": "ma", "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' is succesvol gedownload.", "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' staat al in de wachtrij voor downloaden.", - "Model {{modelId}} not found": "", - "Model {{modelName}} deleted successfully": "", + "Model {{modelId}} not found": "Model {{modelId}} niet gevonden", + "Model {{modelName}} deleted successfully": "Model {{modelName}} is succesvol verwijderd", "Model {{modelName}} is not vision capable": "Model {{modelName}} is niet geschikt voor visie", "Model {{name}} is now {{status}}": "Model {{name}} is nu {{status}}", - "Model {{name}} is now hidden": "Model {{naam}} is nu verborgen", - "Model {{name}} is now visible": "Model {{naam}} is nu zichtbaar", - "Model accepts file inputs": "", + "Model {{name}} is now hidden": "Model {{name}} is nu verborgen", + "Model {{name}} is now visible": "Model {{name}} is nu zichtbaar", "Model accepts image inputs": "Model accepteerd afbeeldingsinvoer", - "Model can access Open Terminal for command execution and file management": "", - "Model can execute code and perform calculations": "", - "Model can generate images based on text prompts": "", - "Model can search the web for information": "", - "Model Capabilities": "", + "Model can access Open Terminal for command execution and file management": "Model heeft toegang tot Open Terminal voor uitvoeren van opdrachten en bestandsbeheer", "Model created successfully!": "Model succesvol gecreëerd", "Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model filesystem path gedetecteerd. Model shortname is vereist voor update, kan niet doorgaan.", "Model Filtering": "Modelfiltratie", "Model ID": "Model-ID", - "Model ID is required.": "", + "Model ID is required.": "Model-ID is vereist", "Model IDs": "Model-IDs", "Model Name": "Modelnaam", - "Model name already exists, please choose a different one": "", - "Model Name is required.": "", - "Model names and usage frequency": "", - "Model not found": "", + "Model name already exists, please choose a different one": "Modelnaam bestaat al, kies een andere", + "Model Name is required.": "Modelnaam is vereist", + "Model names and usage frequency": "Modelnamen en gebruiksfrequentie", + "Model not found": "Model niet gevonden", "Model not selected": "Model niet geselecteerd", - "Model Parameters": "", + "Model Parameters": "Modelparameters", "Model Params": "Modelparams", "Model Permissions": "Modeltoestemmingen", - "Model responses or outputs": "", - "Model unloaded successfully": "", + "Model responses or outputs": "Modelantwoorden of uitvoer", + "Model unloaded successfully": "Model succesvol ontladen", "Model updated successfully": "Model succesvol bijgewerkt", - "Model Usage": "", - "Model(s) do not support file upload": "", + "Model Usage": "Modelgebruik", + "Model(s) do not support file upload": "Model(len) ondersteunen geen bestandsupload", "Modelfile Content": "Modelfile-inhoud", "Models": "Modellen", "Models Access": "Modellentoegang", "Models configuration saved successfully": "Modellenconfiguratie succesvol opgeslagen", - "Models imported successfully": "", + "Models imported successfully": "Modellen succesvol geimporteerd", "Models Public Sharing": "Modellen publiek delen", - "Models Sharing": "", - "Mojeek": "", + "Models Sharing": "Modellen delen", + "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API-sleutel", - "Month": "", - "Monthly": "", + "Month": "Maand", + "Monthly": "Maandelijks", "More": "Meer", - "More Concise": "", - "More options": "", - "More Options": "", - "Move": "", - "Moved {{name}}": "", - "My Terminal": "", + "More Concise": "Meer beknopt", + "More options": "Meer opties", + "More Options": "Meer opties", + "Move": "Verplaatsen", + "Moved {{name}}": "{{name}} verplaatst", + "My Terminal": "Mijn terminal", "Name": "Naam", - "Name and ID are required, please fill them out": "", + "Name and ID are required, please fill them out": "Naam en ID zijn vereist, vul deze in", "Name your knowledge base": "Geef je kennisbasis een naam", - "Name, prompt, and model are required": "", + "Name, prompt, and model are required": "Naam, prompt en model zijn verplicht", "Native": "Native", - "Never": "", - "New": "", - "New Automation": "", - "New Button": "", + "New": "Nieuw", + "New Button": "Nieuwe knop", "New Chat": "Nieuwe Chat", - "New Event": "", - "New File": "", + "Never": "Nooit", + "New Automation": "Nieuwe automatisering", + "New Event": "Nieuwe gebeurtenis", "New Folder": "Nieuwe map", - "New Function": "", - "New Group": "", - "New Knowledge": "", - "New Model": "", - "New Note": "", "New Password": "Nieuw Wachtwoord", - "New Prompt": "", - "New Skill": "", - "New Temporary Chat": "", - "New Terminal": "", - "New Tool": "", - "New Webhook": "", + "New Skill": "Nieuwe vaardigheid", + "New Temporary Chat": "Nieuwe tijdelijke chat", + "New Terminal": "Nieuwe terminal", + "New Tool": "Nieuwe tool", + "New Webhook": "Nieuwe webhook", "new-channel": "nieuw-kanaal", - "Next message": "", - "Next run": "", - "No access grants. Private to you.": "", - "No activity data": "", - "No authentication": "", - "No automations found": "", - "No chats found": "", - "No chats found for this user.": "", - "No chats found.": "", - "No content": "", + "Next message": "Volgend bericht", + "No access grants. Private to you.": "Geen toegangsrechten. Alleen privé voor jou.", + "No activity data": "Geen activiteitsgegevens", + "No authentication": "Geen authenticatie", + "No chats found": "Geen chats gevonden", + "No chats found for this user.": "Geen chats gevonden voor deze gebruiker.", + "No chats found.": "Geen chats gevonden.", + "No content": "Geen inhoud", + "Next run": "Volgende uitvoering", + "No automations found": "Geen automatiseringen gevonden", "No content found": "Geen content gevonden", "No content to speak": "Geen inhoud om over te spreken", - "No conversation to save": "", - "No data": "", - "No data found": "", + "No conversation to save": "Geen gesprek om op te slaan", + "No data": "Geen gegevens", + "No data found": "Geen gegevens gevonden", "No distance available": "Geen afstand beschikbaar", - "No execution logs available yet": "", - "No expiration can pose security risks.": "", - "No feedback found": "", + "No expiration can pose security risks.": "Geen vervaldatum kan veiligheidsrisico's opleveren.", + "No feedback found": "Geen feedback gevonden", + "No execution logs available yet": "Geen uitvoerlogs beschikbaar", "No file selected": "Geen bestand geselecteerd", - "No files found": "", - "No files in this knowledge base.": "", - "No files yet. Upload files or run Python code to create them.": "", - "No functions found": "", - "No groups found": "", - "No history available": "", + "No files found": "Geen bestanden gevonden", + "No files in this knowledge base.": "Geen bestanden in deze kennisbank.", + "No files yet. Upload files or run Python code to create them.": "Nog geen bestanden. Upload bestanden of voer Python-code uit om ze te maken.", + "No functions found": "Geen functies gevonden", + "No groups found": "Geen groepen gevonden", + "No history available": "Geen geschiedenis beschikbaar", "No HTML, CSS, or JavaScript content found.": "Geen HTML, CSS, of JavaScript inhoud gevonden", "No inference engine with management support found": "Geen inferentie-engine met beheerondersteuning gevonden", - "No kernel": "", - "No knowledge bases found.": "", + "No kernel": "Geen kernel", + "No knowledge bases found.": "Geen kennisbanken gevonden.", "No knowledge found": "Geen kennis gevonden", - "No limit": "", + "No limit": "Geen limiet", "No memories to clear": "Geen herinneringen om op te ruimen", "No model IDs": "Geen model-ID's", - "No models available": "", + "No models available": "Geen modellen beschikbaar", "No models found": "Geen modellen gevonden", "No models selected": "Geen modellen geselecteerd", - "No Notes": "", - "No notes found": "", - "No one": "", - "No pinned messages": "", - "No prompts found": "", + "No Notes": "Geen notities", + "No notes found": "Geen notities gevonden", + "No one": "Niemand", + "No pinned messages": "Geen vastgemaakte berichten", + "No prompts found": "Geen prompts gevonden", "No results": "Geen resultaten gevonden", "No results found": "Geen resultaten gevonden", "No search query generated": "Geen zoekopdracht gegenereerd", - "No servers detected": "", - "No skills found": "", + "No servers detected": "Geen servers gedetecteerd", + "No skills found": "Geen vaardigheden gevonden", "No source available": "Geen bron beschikbaar", - "No sources found": "", + "No sources found": "Geen bronnen gevonden", "No suggestion prompts": "Geen voorgestelde prompts", - "No Terminal connection configured.": "", - "No terminal connections configured.": "", - "No tool server connections configured.": "", - "No tools found": "", + "No Terminal connection configured.": "Geen terminalverbinding geconfigureerd.", + "No terminal connections configured.": "Geen terminalverbindingen geconfigureerd.", + "No tool server connections configured.": "Geen toolserververbindingen geconfigureerd.", + "No tools found": "Geen tools gevonden", "No users were found.": "Geen gebruikers gevonden", - "No valves": "", + "No valves": "Geen kleppen", "No valves to update": "Geen kleppen om bij te werken", - "No webhooks yet": "", - "Node Ids": "", + "No webhooks yet": "Nog geen webhooks", + "Node Ids": "Node-ID's", "None": "Geen", "Not factually correct": "Niet feitelijk juist", "Not helpful": "Niet nuttig", - "Not Registered": "", - "Not scheduled": "", - "Note": "", - "Note deleted successfully": "", + "Not Registered": "Niet geregistreerd", + "Note": "Notitie", + "Note deleted successfully": "Notitie succesvol verwijderd", + "Not scheduled": "Niet ingepland", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Opmerking: Als je een minimumscore instelt, levert de zoekopdracht alleen documenten op met een score groter dan of gelijk aan de minimumscore.", "Notes": "Aantekeningen", - "Notes Public Sharing": "", - "Notes Sharing": "", + "Notes Public Sharing": "Openbaar delen van notities", + "Notes Sharing": "Notities delen", "Notification Sound": "Notificatiegeluid", "Notification Webhook": "Notificatie-webhook", "Notifications": "Notificaties", - "November": "November", - "OAuth": "", - "OAuth 2.1": "", - "OAuth 2.1 (Static)": "", + "November": "november", + "OAuth": "OAuth", + "OAuth 2.1": "OAuth 2.1", + "OAuth 2.1 (Static)": "OAuth 2.1 (Statisch)", "OAuth ID": "OAuth ID", - "October": "Oktober", + "October": "oktober", "Off": "Uit", "Okay, Let's Go!": "Oké, laten we gaan!", "OLED Dark": "OLED Donker", "Ollama": "Ollama", "Ollama API": "Ollama API", "Ollama API settings updated": "Ollama API-instellingen bijgewerkt", - "Ollama Cloud API Key": "", + "Ollama Cloud API Key": "Ollama Cloud API-sleutel", "Ollama Version": "Ollama Versie", "On": "Aan", - "Once": "", + "Once": "Eenmalig", "OneDrive": "OneDrive", - "Only active when \"Paste Large Text as File\" setting is toggled on.": "", - "Only active when the chat input is in focus and an LLM is generating a response.": "", - "Only active when the chat input is in focus.": "", + "Only active when \"Paste Large Text as File\" setting is toggled on.": "Alleen actief wanneer de instelling \"Grote tekst als bestand plakken\" is ingeschakeld.", + "Only active when the chat input is in focus and an LLM is generating a response.": "Alleen actief wanneer de chatinvoer focus heeft en een LLM een antwoord genereert.", + "Only active when the chat input is in focus.": "Alleen actief wanneer de chatinvoer focus heeft.", "Only alphanumeric characters and hyphens are allowed": "Alleen alfanumerieke tekens en koppeltekens zijn toegestaan", "Only alphanumeric characters and hyphens are allowed in the command string.": "Alleen alfanumerieke karakters en streepjes zijn toegestaan in de commando string.", - "Only can be triggered when the chat input is in focus.": "", + "Only can be triggered when the chat input is in focus.": "Kan alleen worden geactiveerd wanneer de chatinvoer focus heeft.", "Only collections can be edited, create a new knowledge base to edit/add documents.": "Alleen verzamelinge kunnen gewijzigd worden, maak een nieuwe kennisbank aan om bestanden aan te passen/toe te voegen", - "Only invited users can access": "", - "Only markdown files are allowed": "", + "Only invited users can access": "Alleen uitgenodigde gebruikers hebben toegang", + "Only markdown files are allowed": "Alleen markdown-bestanden zijn toegestaan", "Only select users and groups with permission can access": "Alleen geselecteerde gebruikers en groepen met toestemming hebben toegang", - "Only sync new/updated chats": "", + "Only sync new/updated chats": "Alleen nieuwe/bijgewerkte chats synchroniseren", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oeps! Het lijkt erop dat de URL ongeldig is. Controleer het nogmaals en probeer opnieuw.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Oeps! Er zijn nog bestanden aan het uploaden. Wacht tot het uploaden voltooid is.", "Oops! There was an error in the previous response.": "Oeps! Er was een fout in de vorige reactie.", "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oeps! Je gebruikt een niet-ondersteunde methode (alleen frontend). Serveer de WebUI vanuit de backend.", "Open file": "Open bestand", "Open in full screen": "Open in volledig scherm", - "Open in new tab": "", - "Open link": "", - "Open modal to configure connection": "", - "Open Modal To Manage Floating Quick Actions": "", - "Open Modal To Manage Image Compression": "", - "Open Model Selector": "", - "Open Settings": "", - "Open Sidebar": "", - "Open Terminal": "", - "Open User Profile Menu": "", - "Open WebUI can use tools provided by any OpenAPI server.": "", + "Open in new tab": "Openen in nieuw tabblad", + "Open link": "Link openen", + "Open modal to configure connection": "Open modal om verbinding te configureren", + "Open Modal To Manage Floating Quick Actions": "Open modal om zwevende snelle acties te beheren", + "Open Modal To Manage Image Compression": "Open modal om afbeeldingscompressie te beheren", + "Open Model Selector": "Modelkiezer openen", + "Open Settings": "Instellingen openen", + "Open Sidebar": "Zijbalk openen", + "Open Terminal": "Terminal openen", + "Open User Profile Menu": "Gebruikersprofielmenu openen", + "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI kan tools gebruiken die door elke OpenAPI-server worden geleverd.", "Open WebUI uses faster-whisper internally.": "Open WebUI gebruikt faster-whisper intern", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI gebruikt SpeechT5 en CMU Arctic spreker-embeddings", - "Open WebUI version": "", + "Open WebUI version": "Open WebUI-versie", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI versie (v{{OPEN_WEBUI_VERSION}}) is kleiner dan de benodigde versie (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", - "OpenAI API Base URL": "", - "OpenAI API Key": "", + "OpenAI API Base URL": "OpenAI API-basis-URL", + "OpenAI API Key": "OpenAI API-sleutel", "OpenAI API Key is required.": "OpenAI API-sleutel is verplicht", - "OpenAI API settings updated": "OpenAI API-sleutel bijgewerkt", - "OpenAI API Version": "", + "OpenAI API settings updated": "OpenAI API-instellingen bijgewerkt", + "OpenAI API Version": "OpenAI API-versie", "OpenAI URL/Key required.": "OpenAI URL/Sleutel vereist.", - "OpenAPI": "", - "OpenAPI Spec": "", - "openapi.json URL or Path": "", - "optional": "", - "Optional": "", + "OpenAPI": "OpenAPI", + "OpenAPI Spec": "OpenAPI-specificatie", + "openapi.json URL or Path": "openapi.json-URL of pad", + "optional": "optioneel", + "Optional": "Optioneel", "or": "of", - "Ordered List": "", + "Ordered List": "Genummerde lijst", "Other": "Andere", - "out of": "", - "Output": "", + "Output": "Uitvoer", + "out of": "van de", "OUTPUT": "UITVOER", "Output format": "Uitvoerformaat", - "Output Format": "", + "Output Format": "Uitvoerformaat", "Overview": "Overzicht", "page": "pagina", - "Page": "", - "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", - "Paginate": "", - "Parameters": "", - "Parent message not found": "", - "Participate in community leaderboards and evaluations! Syncing aggregated usage stats helps drive research and improvements to Open WebUI. Your privacy is paramount: no message content is ever shared.": "", + "Page": "Pagina", + "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Paginamodus maakt per pagina een document. De enkele modus combineert alle pagina's in één document voor betere chunking over paginagrens heen.", + "Paginate": "Pagineren", + "Parameters": "Parameters", + "Parent message not found": "Bovenliggend bericht niet gevonden", + "Participate in community leaderboards and evaluations! Syncing aggregated usage stats helps drive research and improvements to Open WebUI. Your privacy is paramount: no message content is ever shared.": "Neem deel aan communityranglijsten en evaluaties! Het synchroniseren van geaggregeerde gebruiksstatistieken helpt onderzoek en verbeteringen aan Open WebUI te stimuleren. Je privacy staat voorop: er wordt nooit berichtinhoud gedeeld.", "Password": "Wachtwoord", - "Passwords do not match.": "", + "Passwords do not match.": "Wachtwoorden komen niet overeen.", "Paste Large Text as File": "Plak grote tekst als bestand", - "Path copied": "", - "Paused": "", + "Path copied": "Pad gekopieerd", + "Paused": "Gepauzeerd", "PDF document (.pdf)": "PDF document (.pdf)", "PDF Extract Images (OCR)": "PDF extraheer afbeeldingen (OCR)", - "PDF Loader Mode": "", + "PDF Loader Mode": "PDF-loadermodus", "pending": "wachtend", - "Pending": "", - "Pending User Overlay Content": "", - "Pending User Overlay Title": "", + "Pending": "In afwachting", + "Pending User Overlay Content": "Inhoud van overlay voor wachtende gebruiker", + "Pending User Overlay Title": "Titel van overlay voor wachtende gebruiker", "Permission denied when accessing media devices": "Toegang geweigerd bij het toegang krijgen tot media-apparaten", "Permission denied when accessing microphone": "Toegang geweigerd bij toegang tot de microfoon", "Permission denied when accessing microphone: {{error}}": "Toestemming geweigerd bij toegang tot microfoon: {{error}}", "Permissions": "Toestemmingen", "Perplexity API Key": "Perplexity API-sleutel", - "Perplexity Model": "", - "Perplexity Search API URL": "", - "Perplexity Search Context Usage": "", - "Persistent": "", + "Perplexity Model": "Perplexity-model", + "Perplexity Search API URL": "Perplexity Search API-URL", + "Perplexity Search Context Usage": "Gebruik van zoekcontext voor Perplexity", + "Persistent": "Persistent", "Personalization": "Personalisatie", "Pin": "Zet vast", - "Pin to Sidebar": "", + "Pin to Sidebar": "Vastzetten in zijbalk", "Pinned": "Vastgezet", - "Pinned Messages": "", - "Pinned Models": "", + "Pinned Messages": "Vastgemaakte berichten", + "Pinned Models": "Vastgemaakte modellen", "Pioneer insights": "Verken inzichten", - "Pipe": "", + "Pipe": "Pijp", "Pipeline deleted successfully": "Pijpleiding succesvol verwijderd", "Pipeline downloaded successfully": "Pijpleiding succesvol gedownload", - "Pipelines": "", - "Pipelines are a plugin system with arbitrary code execution —": "Pipelines is een plug‑insysteem met willekeurige code‑uitvoering —", + "Pipelines": "Pijplijnen", + "Pipelines are a plugin system with arbitrary code execution —": "Pipelines is een plug-insysteem met willekeurige code‑uitvoering —", "Pipelines Not Detected": "Pijpleiding niet gedetecteerd", "Pipelines Valves": "Pijpleidingen Kleppen", - "Plain text (.md)": "", + "Plain text (.md)": "Platte tekst (.md)", "Plain text (.txt)": "Platte tekst (.txt)", "Playground": "Speeltuin", - "Playwright Timeout (ms)": "", - "Playwright WebSocket URL": "", + "Playwright Timeout (ms)": "Playwright-time-out (ms)", + "Playwright WebSocket URL": "Playwright WebSocket-URL", "Please carefully review the following warnings:": "Beoordeel de volgende waarschuwingen nauwkeurig:", - "Please connect all required integrations before sending a message": "", + "Please connect all required integrations before sending a message": "Verbind eerst alle vereiste integraties voordat je een bericht verzendt", "Please do not close the settings page while loading the model.": "Sluit de instellingenpagina niet terwijl het model geladen wordt.", - "Please enter a message or attach a file.": "", + "Please enter a message or attach a file.": "Voer een bericht in of voeg een bestand toe.", "Please enter a prompt": "Voer een prompt in", - "Please enter a valid ID": "", - "Please enter a valid JSON spec": "", - "Please enter a valid path": "", - "Please enter a valid URL": "", - "Please enter a valid URL.": "", - "Please enter Client ID and Client Secret": "", + "Please enter a valid ID": "Voer een geldige ID in", + "Please enter a valid JSON spec": "Voer een geldige JSON-specificatie in", + "Please enter a valid path": "Voer een geldig pad in", + "Please enter a valid URL": "Voer een geldige URL in", + "Please enter a valid URL.": "Voer een geldige URL in.", + "Please enter Client ID and Client Secret": "Voer Client ID en Client Secret in", "Please fill in all fields.": "Voer alle velden in", - "Please register the OAuth client": "", - "Please save the connection to persist the OAuth client information and do not change the ID": "", + "Please register the OAuth client": "Registreer de OAuth-client", + "Please save the connection to persist the OAuth client information and do not change the ID": "Sla de verbinding op om de OAuth-clientinformatie te bewaren en wijzig de ID niet", "Please select a model first.": "Selecteer eerst een model", "Please select a model.": "Selecteer een model", "Please select a reason": "Voer een reden in", - "Please select a valid JSON file": "", - "Please select at least one user for Direct Message channel.": "", - "Please wait until all files are uploaded.": "", - "Policy ID": "", + "Please select a valid JSON file": "Selecteer een geldig JSON-bestand", + "Please select at least one user for Direct Message channel.": "Selecteer ten minste een gebruiker voor het Direct Message-kanaal.", + "Please wait until all files are uploaded.": "Wacht tot alle bestanden zijn geüpload.", + "Policy ID": "Beleid-ID", "Port": "Poort", - "Ports": "", + "Ports": "Poorten", "Positive attitude": "Positieve houding", - "Prefer not to say": "", + "Prefer not to say": "Liever niet zeggen", "Prefix ID": "Voorvoegsel-ID", "Prefix ID is used to avoid conflicts with other connections by adding a prefix to the model IDs - leave empty to disable": "Voorvoegsel-ID wordt gebruikt om conflicten met andere verbindingen te vermijden door een voorvoegsel aan het model-ID toe te voegen - laat leeg om uit te schakelen", - "Prevent File Creation": "", - "Preview": "", + "Prevent File Creation": "Bestandsaanmaak voorkomen", + "Preview": "Voorvertoning", "Previous 30 days": "Afgelopen 30 dagen", "Previous 7 days": "Afgelopen 7 dagen", - "Previous message": "", + "Previous message": "Vorige bericht", "Private": "Privé", - "Private conversation between selected users": "", - "Production version updated": "", + "Private conversation between selected users": "Privégesprek tussen geselecteerde gebruikers", + "Production version updated": "Productieversie bijgewerkt", "Profile": "Profiel", "Prompt": "Prompt", "Prompt Autocompletion": "Automatische promptaanvulling", "Prompt Content": "Promptinhoud", "Prompt created successfully": "Prompt succesvol aangemaakt", - "Prompt Name": "", - "Prompt Suggestions": "", + "Prompt Name": "Promptnaam", + "Prompt Suggestions": "Promptsuggesties", "Prompt updated successfully": "Prompt succesvol bijgewerkt", "Prompts": "Prompts", "Prompts Access": "Prompttoegang", "Prompts Public Sharing": "Publiek prompts delen", - "Prompts Sharing": "", - "Provider Type": "", + "Prompts Sharing": "Prompts delen", + "Provider Type": "Providertype", "Public": "Publiek", "Pull \"{{searchValue}}\" from Ollama.com": "Haal \"{{searchValue}}\" uit Ollama.com", "Pull a model from Ollama.com": "Haal een model van Ollama.com", - "Pull Model": "", - "Pyodide file browser": "", + "Pull Model": "Model ophalen", + "Pyodide file browser": "Pyodide-bestandsverkenner", "Query Generation Prompt": "Vraaggeneratieprompt", - "Querying": "", - "Quick Actions": "", + "Querying": "Bezig met opvragen", + "Quick Actions": "Snelle acties", "RAG Template": "RAG-sjabloon", - "Ran {{COUNT}} analyses": "", - "Ran {{COUNT}} analysis": "", - "Rate {{rating}} out of 10": "", + "Ran {{COUNT}} analyses": "{{COUNT}} analyses uitgevoerd", + "Ran {{COUNT}} analysis": "{{COUNT}} analyse uitgevoerd", + "Rate {{rating}} out of 10": "Beoordeel {{rating}} van de 10", "Rating": "Beoordeling", "Re-rank models by topic similarity": "Herrangschik modellen op basis van onderwerpsovereenkomst", "Read": "Voorlezen", "Read Aloud": "Voorlezen", - "Read more →": "", - "Read Only": "", - "Read-Only Access": "", - "Reason": "", + "Read more →": "Lees meer →", + "Read Only": "Alleen lezen", + "Read-Only Access": "Alleen-lezen-toegang", + "Reason": "Reden", "Reasoning Effort": "Redeneerinspanning", - "Reasoning Tags": "", - "Recently Used": "", - "Reconnected": "", - "Record": "", + "Reasoning Tags": "Redeneertags", + "Record": "Opnemen", + "Recently Used": "Onlangs gebruikt", + "Reconnected": "Opnieuw verbonden", "Record voice": "Neem stem op", "Redirecting you to Open WebUI Community": "Je wordt doorgestuurd naar OpenWebUI Community", "Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative.": "Vermindert de kans op het genereren van onzin. Een hogere waarde (bijv. 100) zal meer diverse antwoorden geven, terwijl een lagere waarde (bijv. 10) conservatiever zal zijn.", "Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Refereer naar jezelf als \"user\" (bv. \"User is Spaans aan het leren\")", - "Reference Chats": "", - "Refresh": "", - "Refused when it shouldn't have": "Geweigerd terwijl het niet had moeten", + "Reference Chats": "Referentiechats", + "Refresh": "Verversen", + "Refused when it shouldn't have": "Geweigerd terwijl dat niet had mogen gebeuren", "Regenerate": "Regenereren", - "Regenerate Menu": "", - "Regenerate Response": "", - "Register Again": "", - "Register Client": "", - "Registered": "", - "Registration failed": "", - "Registration successful": "", - "Reindex": "", - "Reindex Knowledge Base Vectors": "", + "Regenerate Menu": "Menu opnieuw genereren", + "Regenerate Response": "Antwoord opnieuw genereren", + "Register Again": "Opnieuw registreren", + "Register Client": "Client registreren", + "Registered": "Geregistreerd", + "Registration failed": "Registratie mislukt", + "Registration successful": "Registratie geslaagd", + "Reindex": "Opnieuw indexeren", + "Reindex Knowledge Base Vectors": "Vektoren van kennisbank opnieuw indexeren", "Release Notes": "Release-opmerkingen", - "Releases": "", + "Releases": "Uitgaven", "Relevance": "Relevantie", - "Relevance Threshold": "", - "Remember Dismissal": "", - "Reminder": "", + "Relevance Threshold": "Relevantiegrens", + "Remember Dismissal": "Afwijzing onthouden", + "Reminder": "Herinnering", "Remove": "Verwijderen", - "Remove {{MODELID}} from list.": "", - "Remove action": "", - "Remove file": "", - "Remove File": "", - "Remove from favorites": "", - "Remove image": "", + "Remove {{MODELID}} from list.": "Verwijder {{MODELID}} uit de lijst.", + "Remove action": "Actie verwijderen", + "Remove file": "Bestand verwijderen", + "Remove File": "Bestand verwijderen", + "Remove from favorites": "Verwijderen uit favorieten", + "Remove image": "Afbeelding verwijderen", "Remove Model": "Verwijder model", "Rename": "Hernoemen", - "Renamed to {{name}}": "", - "Render Markdown in Previews": "", + "Renamed to {{name}}": "Hernoemd naar {{name}}", + "Render Markdown in Previews": "Markdown renderen in voorvertoningen", "Reorder Models": "Herschik modellen", - "Repeats": "", - "Reply": "", + "Reply": "Antwoorden", "Reply in Thread": "Antwoord in draad", - "Reply to thread...": "", - "Replying to {{NAME}}": "", - "required": "", - "Reranking Batch Size": "", - "Reranking Engine": "", + "Reply to thread...": "Reageren op draad...", + "Replying to {{NAME}}": "Reageren op {{NAME}}", + "required": "vereist", + "Reranking Engine": "Herschikkingsengine", + "Repeats": "Herhalingen", + "Reranking Batch Size": "Batchgrootte voor herordenen", "Reranking Model": "Reranking Model", "Reset": "Herstellen", "Reset All Models": "Herstel alle modellen", @@ -1688,335 +1688,335 @@ "Reset Upload Directory": "Herstel Uploadmap", "Reset Vector Storage/Knowledge": "Herstel Vectoropslag/-kennis", "Reset view": "Herstel zicht", - "Response": "", - "Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Antwoordmeldingen kunnen niet worden geactiveerd omdat de rechten voor de website zijn geweigerd. Ga naar de instellingen van uw browser om de benodigde toegang te verlenen.", + "Response": "Antwoord", + "Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Antwoordmeldingen kunnen niet worden geactiveerd omdat de rechten voor de website zijn geweigerd. Ga naar de instellingen van je browser om de benodigde toegang te verlenen.", "Response splitting": "Antwoord splitsing", - "Response Watermark": "", - "Responses": "", - "Restart": "", + "Response Watermark": "Antwoordwatermerk", + "Responses": "Antwoorden", + "Restart": "Opnieuw starten", "Result": "Resultaat", "RESULT": "Resultaat", "Retrieval": "Ophalen", "Retrieval Query Generation": "Ophaalqueriegeneratie", - "Retrieved {{count}} sources": "", - "Retrieved {{count}} sources_one": "", - "Retrieved {{count}} sources_other": "", - "Retrieved 1 source": "", + "Retrieved {{count}} sources": "{{count}} bronnen opgehaald", + "Retrieved {{count}} sources_one": "{{count}} bron opgehaald", + "Retrieved {{count}} sources_other": "{{count}} bronnen opgehaald", + "Retrieved 1 source": "1 bron opgehaald", "Rich Text Input for Chat": "Rijke tekstinvoer voor chatten", "Role": "Rol", "RTL": "RNL", "Run": "Uitvoeren", - "Run All": "", - "Run now": "", - "Run Now": "", + "Run All": "Alles uitvoeren", "Running": "Aan het uitvoeren", "Running...": "Aan het uitvoeren...", - "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "", - "Sa_day_of_week": "", + "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Voert embeddingtaken gelijktijdig uit om de verwerking te versnellen. Schakel uit als rate limits een probleem worden.", + "Run now": "Nu uitvoeren", + "Run Now": "Nu uitvoeren", + "Sa_day_of_week": "za", "Save": "Opslaan", "Save & Create": "Opslaan & Creëren", "Save & Update": "Opslaan & Bijwerken", "Save As Copy": "Bewaar als kopie", - "Save Chat": "", + "Save Chat": "Chat opslaan", "Saved": "Opgeslagen", "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "Chat logs direct opslaan in de opslag van je browser wordt niet langer ondersteund. Neem even de tijd om je chat logs te downloaden en te verwijderen door op de knop hieronder te klikken. Maak je geen zorgen, je kunt je chat logs eenvoudig opnieuw importeren naar de backend via", - "Schedule": "", - "Scheduled time must be in the future": "", - "Scroll On Branch Change": "", + "Scroll On Branch Change": "Scrollen bij wijziging van branch", "Search": "Zoeken", "Search a model": "Zoek een model", - "Search all emojis": "", - "Search and manage user memories": "", - "Search and view user chat history": "", - "Search Automations": "", + "Search all emojis": "Alle emoji's zoeken", + "Search and manage user memories": "Gebruikersherinneringen zoeken en beheren", + "Search and view user chat history": "Gebruikerschatgeschiedenis zoeken en bekijken", + "Schedule": "Planning", + "Scheduled time must be in the future": "Ingeplande tijd moet in de toekomst liggen", + "Search Automations": "Zoek automatiseringen", "Search Base": "Zoeken naar basis", - "Search channels and channel messages": "", + "Search channels and channel messages": "Kanalen en kanaalberichten zoeken", "Search Chats": "Chats zoeken", "Search Collection": "Zoek naar verzamelingen", - "Search Files": "", + "Search Files": "Bestanden zoeken", "Search Filters": "Zoek naar filters", - "search for archived chats": "", - "search for folders": "", - "search for pinned chats": "", - "search for shared chats": "", + "search for archived chats": "zoek naar gearchiveerde chats", + "search for folders": "zoek naar mappen", + "search for pinned chats": "zoek naar vastgemaakte chats", + "search for shared chats": "zoek naar gedeelde chats", "search for tags": "Zoek naar tags", "Search Functions": "Zoek naar functie", - "Search Groups": "", - "Search In Models": "", + "Search Groups": "Groepen zoeken", + "Search In Models": "Zoeken in modellen", "Search Knowledge": "Zoek naar Kennis", - "Search Memories": "", + "Search Memories": "Herinneringen zoeken", "Search Models": "Modellen zoeken", - "Search Notes": "", + "Search Notes": "Notities zoeken", "Search options": "Opties zoeken", "Search Prompts": "Prompts zoeken", "Search Result Count": "Aantal zoekresultaten", - "Search Skills": "", + "Search Skills": "Vaardigheden zoeken", "Search the internet": "Zoek op het internet", - "Search the web and fetch URLs": "", + "Search the web and fetch URLs": "Doorzoek het web en haal URL's op", "Search Tools": "Zoek gereedschappen", - "Search, view, and manage user notes": "", + "Search, view, and manage user notes": "Gebruikersnotities zoeken, bekijken en beheren", "SearchApi API Key": "SearchApi API-sleutel", "SearchApi Engine": "SearchApi Engine", "Searched {{count}} sites": "Zocht op {{count}} sites", - "Searching": "", + "Searching": "Aan het zoeken", "Searching \"{{searchQuery}}\"": "\"{{searchQuery}}\" aan het zoeken.", "Searching Knowledge for \"{{searchQuery}}\"": "Zoek kennis bij \"{{searchQuery}}\"", - "Searching the web": "", + "Searching the web": "Bezig met zoeken op het web", "Searxng Query URL": "Searxng Query URL", - "Searxng search language (all, en, es, de, fr, etc.)": "", + "Searxng search language (all, en, es, de, fr, etc.)": "Searxng-zoektaal (all, en, es, de, fr, enz.)", "See readme.md for instructions": "Zie readme.md voor instructies", "See what's new": "Zie wat er nieuw is", "Seed": "Seed", - "Select": "", - "Select {{modelName}} model": "", + "Select": "Selecteren", + "Select {{modelName}} model": "Selecteer {{modelName}}-model", "Select a base model": "Selecteer een basismodel", - "Select a base model (e.g. llama3, gpt-4o)": "", - "Select a conversation to preview": "", + "Select a base model (e.g. llama3, gpt-4o)": "Selecteer een basismodel (bijv. llama3, gpt-4o)", + "Select a conversation to preview": "Selecteer een gesprek om te bekijken", "Select a engine": "Selecteer een engine", "Select a function": "Selecteer een functie", "Select a group": "Selecteer een groep", - "Select a language": "", - "Select a mode": "", + "Select a language": "Selecteer een taal", + "Select a mode": "Selecteer een modus", "Select a model": "Selecteer een model", - "Select a model (optional)": "", + "Select a model (optional)": "Selecteer een model (optioneel)", "Select a pipeline": "Selecteer een pijplijn", "Select a pipeline url": "Selecteer een pijplijn-URL", - "Select a reranking model engine": "", - "Select a role": "", - "Select a theme": "", + "Select a reranking model engine": "Selecteer een engine voor herordening van modellen", + "Select a role": "Selecteer een rol", + "Select a theme": "Selecteer een thema", "Select a tool": "Selecteer een tool", - "Select a voice": "", - "Select All": "", + "Select a voice": "Selecteer een stem", + "Select All": "Alles selecteren", "Select an auth method": "Selecteer een authenticatiemethode", - "Select an embedding model engine": "", - "Select an engine": "", + "Select an embedding model engine": "Selecteer een embeddingmodel-engine", + "Select an engine": "Selecteer een engine", "Select an Ollama instance": "Selecteer een Ollama-instantie", - "Select an option": "", - "Select an output format": "", - "Select dtype": "", + "Select an option": "Selecteer een optie", + "Select an output format": "Selecteer een uitvoerformaat", + "Select dtype": "Selecteer dtype", "Select Engine": "Selecteer Engine", - "Select how to split message text for TTS requests": "", + "Select how to split message text for TTS requests": "Selecteer hoe berichttekst wordt gesplitst voor TTS-verzoeken", "Select Knowledge": "Selecteer kennis", - "Select Method": "", - "Select model": "", + "Select Method": "Selecteer methode", + "Select model": "Selecteer model", "Select only one model to call": "Selecteer maar één model om aan te roepen", - "Select view": "", - "Selected model: {{modelName}}": "", + "Select view": "Selecteer weergave", + "Selected model: {{modelName}}": "Geselecteerd model: {{modelName}}", "Selected model(s) do not support image inputs": "Geselecteerde modellen ondersteunen geen beeldinvoer", - "Selected Models": "", - "semantic": "", + "Selected Models": "Geselecteerde modellen", + "semantic": "semantisch", "Send": "Verzenden", "Send a Message": "Stuur een bericht", "Send message": "Stuur bericht", - "Send now": "", + "Send now": "Nu verzenden", "Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.": "Stuurt `stream_options: { include_usage: true }` in het verzoek. \nOndersteunde providers zullen informatie over tokengebruik in het antwoord terugsturen als dit aan staat.", - "September": "September", + "September": "september", "SerpApi API Key": "SerpApi API-sleutel", "SerpApi Engine": "SerpApi-engine", "Serper API Key": "Serper API-sleutel", "Serply API Key": "Serply API-sleutel", "Serpstack API Key": "Serpstack API-sleutel", - "Server connection failed": "", + "Server connection failed": "Serververbinding mislukt", "Server connection verified": "Server verbinding geverifieerd", - "Session": "", + "Session": "Sessie", "Set as default": "Stel in als standaard", - "Set as Production": "", + "Set as Production": "Instellen als productie", "Set embedding model": "Stel embedding-model in", "Set embedding model (e.g. {{model}})": "Stel embedding-model in (bv. {{model}})", "Set reranking model (e.g. {{model}})": "Stel reranking-model in (bv. {{model}})", - "Set the default models that are automatically selected for all users when a new chat is created.": "", - "Set the models that are automatically pinned to the sidebar for all users.": "", + "Set the default models that are automatically selected for all users when a new chat is created.": "Stel de standaardmodellen in die automatisch voor alle gebruikers worden geselecteerd wanneer een nieuwe chat wordt gemaakt.", + "Set the models that are automatically pinned to the sidebar for all users.": "Stel de modellen in die automatisch voor alle gebruikers in de zijbalk worden vastgezet.", "Set the number of layers, which will be off-loaded to GPU. Increasing this value can significantly improve performance for models that are optimized for GPU acceleration but may also consume more power and GPU resources.": "Stel het aantal lagen in dat wordt overgeheveld naar de GPU. Het verhogen van deze waarde kan de prestaties aanzienlijk verbeteren voor modellen die geoptimaliseerd zijn voor GPU-versnelling, maar kan ook meer stroom en GPU-bronnen verbruiken.", "Set the number of worker threads used for computation. This option controls how many threads are used to process incoming requests concurrently. Increasing this value can improve performance under high concurrency workloads but may also consume more CPU resources.": "Stel het aantal threads in dat wordt gebruikt voor berekeningen. Deze optie bepaalt hoeveel threads worden gebruikt om gelijktijdig binnenkomende verzoeken te verwerken. Het verhogen van deze waarde kan de prestaties verbeteren onder hoge concurrency werklasten, maar kan ook meer CPU-bronnen verbruiken.", "Set Voice": "Stel stem in", "Set whisper model": "Stel Whisper-model in", - "Set your status": "", + "Set your status": "Stel je status in", "Sets a flat bias against tokens that have appeared at least once. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. At 0, it is disabled.": "Stelt een vlakke bias in tegen tokens die minstens één keer zijn voorgekomen. Een hogere waarde (bijv. 1,5) straft herhalingen sterker af, terwijl een lagere waarde (bijv. 0,9) toegeeflijker is. Bij 0 is het uitgeschakeld.", "Sets a scaling bias against tokens to penalize repetitions, based on how many times they have appeared. A higher value (e.g., 1.5) will penalize repetitions more strongly, while a lower value (e.g., 0.9) will be more lenient. At 0, it is disabled.": "Stelt een schaalvooroordeel in tegen tokens om herhalingen te bestraffen, gebaseerd op hoe vaak ze zijn voorgekomen. Een hogere waarde (bijv. 1,5) straft herhalingen sterker af, terwijl een lagere waarde (bijv. 0,9) toegeeflijker is. Bij 0 is het uitgeschakeld.", "Sets how far back for the model to look back to prevent repetition.": "Stelt in hoe ver het model terug moet kijken om herhaling te voorkomen.", "Sets the random number seed to use for generation. Setting this to a specific number will make the model generate the same text for the same prompt.": "Stelt de willekeurigheid in om te gebruiken voor het genereren. Als je dit op een specifiek getal instelt, genereert het model dezelfde tekst voor dezelfde prompt.", "Sets the size of the context window used to generate the next token.": "Stelt de grootte van het contextvenster in dat gebruikt wordt om het volgende token te genereren.", "Sets the stop sequences to use. When this pattern is encountered, the LLM will stop generating text and return. Multiple stop patterns may be set by specifying multiple separate stop parameters in a modelfile.": "Stelt de te gebruiken stopsequentie in. Als dit patroon wordt gevonden, stopt de LLM met het genereren van tekst en keert terug. Er kunnen meerdere stoppatronen worden ingesteld door meerdere afzonderlijke stopparameters op te geven in een modelbestand.", - "Setting": "", + "Setting": "Instelling", "Settings": "Instellingen", - "Settings Permissions": "", + "Settings Permissions": "Instellingenrechten", "Settings saved successfully!": "Instellingen succesvol opgeslagen!", "Share": "Delen", "Share Chat": "Deel chat", - "Share link copied to clipboard.": "", + "Share link copied to clipboard.": "Deellink gekopieerd naar klembord.", "Share to Open WebUI Community": "Deel naar OpenWebUI-community", - "Share your background and interests": "", - "Shared Chats": "", - "Shared with you": "", + "Share your background and interests": "Deel je achtergrond en interesses", + "Shared Chats": "Gedeelde chats", + "Shared with you": "Gedeeld met jou", "Sharing Permissions": "Deeltoestemmingen", "Show": "Toon", "Show \"What's New\" modal on login": "Toon \"Wat is nieuw\" bij inloggen", "Show Admin Details in Account Pending Overlay": "Admin-details weergeven in overlay in afwachting van account", - "Show All": "", - "Show all ({{COUNT}} characters)": "", - "Show Files": "", - "Show Formatting Toolbar": "", - "Show image preview": "", + "Show All": "Alles tonen", + "Show all ({{COUNT}} characters)": "Alles tonen ({{COUNT}} tekens)", + "Show Files": "Bestanden tonen", + "Show Formatting Toolbar": "Opmaakwerkbalk tonen", + "Show image preview": "Afbeeldingsvoorvertoning tonen", "Show Model": "Toon model", - "Show Shortcuts": "", + "Show Shortcuts": "Sneltoetsen tonen", "Show your support!": "Toon je steun", "Showcased creativity": "Toonde creativiteit", - "Showing all messages (user + assistant) per user.": "", + "Showing all messages (user + assistant) per user.": "Toont alle berichten (gebruiker + assistent) per gebruiker.", "Sign in": "Inloggen", "Sign in to {{WEBUI_NAME}}": "Log in bij {{WEBUI_NAME}}", "Sign in to {{WEBUI_NAME}} with LDAP": "Log in bij {{WEBUI_NAME}} met LDAP", "Sign Out": "Uitloggen", "Sign up": "Registreren", "Sign up to {{WEBUI_NAME}}": "Meld je aan bij {{WEBUI_NAME}}", - "Significantly improves accuracy by using an LLM to enhance tables, forms, inline math, and layout detection. Will increase latency. Defaults to False.": "", + "Significantly improves accuracy by using an LLM to enhance tables, forms, inline math, and layout detection. Will increase latency. Defaults to False.": "Verbetert de nauwkeurigheid aanzienlijk door een LLM te gebruiken voor het verbeteren van tabellen, formulieren, inline wiskunde en lay-outdetectie. Dit verhoogt de latentie. Standaard is False.", "Signing in to {{WEBUI_NAME}}": "Aan het inloggen bij {{WEBUI_NAME}}", - "Single": "", - "Sink List": "", + "Single": "Enkelvoudig", + "Sink List": "Sink-lijst", "sk-1234": "sk-1234", - "Skill created successfully": "", - "Skill deleted successfully": "", - "Skill Description": "", - "Skill ID": "", - "Skill imported successfully": "", - "Skill Instructions": "", - "Skill Name": "", - "Skill updated successfully": "", - "Skills": "", - "Skills Access": "", - "Skills Public Sharing": "", - "Skills Sharing": "", - "Skip Cache": "", - "Skip the cache and re-run the inference. Defaults to False.": "", - "Something went wrong :/": "", - "Sonar": "", - "Sonar Deep Research": "", - "Sonar Pro": "", - "Sonar Reasoning": "", - "Sonar Reasoning Pro": "", - "Sort": "", - "Sort by": "", - "Sougou Search API sID": "", - "Sougou Search API SK": "", + "Skill created successfully": "Vaardigheid succesvol aangemaakt", + "Skill deleted successfully": "Vaardigheid succesvol verwijderd", + "Skill Description": "Beschrijving van de vaardigheid", + "Skill ID": "Vaardigheid-ID", + "Skill imported successfully": "Vaardigheid succesvol geimporteerd", + "Skill Instructions": "Vaardigheidsinstructies", + "Skill Name": "Vaardigheidsnaam", + "Skill updated successfully": "Vaardigheid succesvol bijgewerkt", + "Skills": "Vaardigheden", + "Skills Access": "Toegang tot vaardigheden", + "Skills Public Sharing": "Openbaar delen van vaardigheden", + "Skills Sharing": "Vaardigheden delen", + "Skip Cache": "Cache overslaan", + "Skip the cache and re-run the inference. Defaults to False.": "Sla de cache over en voer de inferentie opnieuw uit. Standaard is False.", + "Something went wrong :/": "Er is iets misgegaan :/", + "Sonar": "Sonar", + "Sonar Deep Research": "Sonar Deep Research", + "Sonar Pro": "Sonar Pro", + "Sonar Reasoning": "Sonar Reasoning", + "Sonar Reasoning Pro": "Sonar Reasoning Pro", + "Sort": "Sorteren", + "Sort by": "Sorteren op", + "Sougou Search API sID": "Sougou Search API sID", + "Sougou Search API SK": "Sougou Search API SK", "Source": "Bron", "Speech Playback Speed": "Afspeelsnelheid spraak", "Speech recognition error: {{error}}": "Spraakherkenning fout: {{error}}", - "Speech-to-Text": "", + "Speech-to-Text": "Spraak-naar-tekst", "Speech-to-Text Engine": "Spraak-naar-tekst Engine", - "Speech-to-Text Language": "", - "Split documents by markdown headers before applying character/token splitting.": "", - "Start a new conversation": "", + "Speech-to-Text Language": "Spraak-naar-teksttaal", + "Split documents by markdown headers before applying character/token splitting.": "Splits documenten op basis van markdown-koppen voordat teken-/token-splitsing wordt toegepast.", + "Start a new conversation": "Start een nieuw gesprek", "Start of the channel": "Begin van het kanaal", - "Start Tag": "", - "Starting in {{count}} minutes_one": "", - "Starting in {{count}} minutes_other": "", - "Starting in 1 minute": "", - "Starting kernel...": "", - "Starting now": "", - "State": "", - "Status": "", - "Status cleared successfully": "", - "Status updated successfully": "", - "Status Updates": "", + "Start Tag": "Starttag", + "Starting kernel...": "Kernel wordt gestart...", + "Status": "Status", + "Status cleared successfully": "Status succesvol gewist", + "Status updated successfully": "Status succesvol bijgewerkt", + "Status Updates": "Statusupdates", + "State": "Status", + "Starting in {{count}} minutes_one": "Begint over {{count}} minuut", + "Starting in {{count}} minutes_other": "Begint over {{count}} minuten", + "Starting in 1 minute": "Begint over 1 minuut", + "Starting now": "Begint nu", "STDOUT/STDERR": "STDOUT/STDERR", - "Steps": "", + "Steps": "Stappen", "Stop": "Stop", - "Stop Download": "", - "Stop Generating": "", + "Stop Download": "Download stoppen", + "Stop Generating": "Genereren stoppen", "Stop Sequence": "Stopsequentie", - "Storage": "", + "Storage": "Opslag", "Stream Chat Response": "Stream chat-antwoord", - "Stream Delta Chunk Size": "", - "Streamable HTTP": "", - "Strikethrough": "", - "Strip Existing OCR": "", - "Strip existing OCR text from the PDF and re-run OCR. Ignored if Force OCR is enabled. Defaults to False.": "", + "Stream Delta Chunk Size": "Stream delta-chunkgrootte", + "Streamable HTTP": "Streambare HTTP", + "Strikethrough": "Doorhalen", + "Strip Existing OCR": "Bestaande OCR verwijderen", + "Strip existing OCR text from the PDF and re-run OCR. Ignored if Force OCR is enabled. Defaults to False.": "Verwijder bestaande OCR-tekst uit de PDF en voer OCR opnieuw uit. Wordt genegeerd als Force OCR is ingeschakeld. Standaard is False.", "STT Model": "STT Model", "STT Settings": "STT Instellingen", - "Stylized PDF Export": "", - "Su_day_of_week": "", - "Submit question": "", - "Submit suggestion": "", - "Subtitle": "", + "Stylized PDF Export": "Gestileerde PDF-export", + "Submit question": "Vraag indienen", + "Submit suggestion": "Suggestie indienen", + "Subtitle": "Ondertitel", + "Su_day_of_week": "zo", "Success": "Succes", - "Successfully imported {{userCount}} users.": "", + "Successfully imported {{userCount}} users.": "{{userCount}} gebruikers succesvol geimporteerd.", "Successfully updated.": "Succesvol bijgewerkt.", - "Suggest a change": "", + "Suggest a change": "Een wijziging voorstellen", "Suggested": "Suggestie", "Support": "Ondersteuning", "Support this plugin:": "ondersteun deze plugin", - "Supported MIME Types": "", - "Sync": "", - "Sync Complete!": "", + "Supported MIME Types": "Ondersteunde MIME-typen", + "Sync": "Synchroniseren", + "Sync Complete!": "Synchronisatie voltooid!", "Sync directory": "Synchroniseer map", - "Sync Failed": "", - "Sync Usage Stats": "", - "Syncing stats...": "", - "Syncing...": "", - "Syncs only chats with updates after your last sync timestamp. Disable to re-sync all chats.": "", + "Sync Failed": "Synchronisatie mislukt", + "Sync Usage Stats": "Gebruiksstatistieken synchroniseren", + "Syncing stats...": "Statistieken synchroniseren...", + "Syncing...": "Synchroniseren...", + "Syncs only chats with updates after your last sync timestamp. Disable to re-sync all chats.": "Synchroniseert alleen chats met wijzigingen na je laatste synchronisatietijdstip. Schakel dit uit om alle chats opnieuw te synchroniseren.", "System": "Systeem", "System Instructions": "Systeem instructies", "System Prompt": "Systeem prompt", - "Tag": "", + "Tag": "Tag", "Tags": "Tags", "Tags Generation": "Taggeneratie", "Tags Generation Prompt": "Prompt voor taggeneratie", "Tail free sampling is used to reduce the impact of less probable tokens from the output. A higher value (e.g., 2.0) will reduce the impact more, while a value of 1.0 disables this setting.": "Tail free sampling wordt gebruikt om de impact van minder waarschijnlijke tokens uit de uitvoer te verminderen. Een hogere waarde (bijvoorbeeld 2,0) zal de impact meer verminderen, terwijl een waarde van 1,0 deze instelling uitschakelt.", - "Talk to Model": "", + "Talk to Model": "Praat met model", "Tap to interrupt": "Tik om te onderbreken", - "Task List": "", - "Task Management": "", - "Task Model": "", + "Task List": "Takenlijst", + "Task Model": "Taakmodel", + "Task Management": "Taakbeheer", "Tasks": "Taken", - "tasks completed": "", + "tasks completed": "taken voltooid", "Tavily API Key": "Tavily API-sleutel", - "Tavily Extract Depth": "", + "Tavily Extract Depth": "Tavily-extractiediepte", "Tell us more:": "Vertel ons meer:", "Temperature": "Temperatuur", "Temporary Chat": "Tijdelijke chat", - "Temporary Chat by Default": "", - "Terminal": "", - "Terminal servers saved": "", + "Temporary Chat by Default": "Tijdelijke chat standaard", + "Terminal": "Terminal", + "Terminal servers saved": "Terminalservers opgeslagen", "Text Splitter": "Tekst splitser", - "Text-to-Speech": "", + "Text-to-Speech": "Tekst-naar-spraak", "Text-to-Speech Engine": "Tekst-naar-Spraak Engine", - "Th_day_of_week": "", + "Th_day_of_week": "do", "Thanks for your feedback!": "Bedankt voor je feedback!", "The Application Account DN you bind with for search": "Het applicatieaccount DN waarmee je zoekt", "The base to search for users": "De basis om gebruikers te zoeken", "The batch size determines how many text requests are processed together at once. A higher batch size can increase the performance and speed of the model, but it also requires more memory.": "De batchgrootte bepaalt hoeveel tekstverzoeken tegelijk worden verwerkt. Een hogere batchgrootte kan de prestaties en snelheid van het model verhogen, maar vereist ook meer geheugen.", "The developers behind this plugin are passionate volunteers from the community. If you find this plugin helpful, please consider contributing to its development.": "De ontwikkelaars achter deze plugin zijn gepassioneerde vrijwilligers uit de gemeenschap. Als je deze plugin nuttig vindt, overweeg dan om bij te dragen aan de ontwikkeling ervan.", "The evaluation leaderboard is based on the Elo rating system and is updated in real-time.": "Het beoordelingsklassement is gebaseerd op het Elo-classificatiesysteem en wordt in realtime bijgewerkt.", - "The format to return a response in. Format can be json or a JSON schema.": "", - "The height in pixels to compress images to. Leave empty for no compression.": "", - "The language of the input audio. Supplying the input language in ISO-639-1 (e.g. en) format will improve accuracy and latency. Leave blank to automatically detect the language.": "", + "The format to return a response in. Format can be json or a JSON schema.": "Het formaat waarin een antwoord moet worden teruggegeven. Het formaat kan json of een JSON-schema zijn.", + "The height in pixels to compress images to. Leave empty for no compression.": "De hoogte in pixels waarnaar afbeeldingen moeten worden gecomprimeerd. Laat leeg voor geen compressie.", + "The language of the input audio. Supplying the input language in ISO-639-1 (e.g. en) format will improve accuracy and latency. Leave blank to automatically detect the language.": "De taal van de invoeraudio. Het opgeven van de invoertaal in ISO-639-1-indeling (bijv. en) verbetert de nauwkeurigheid en latentie. Laat leeg om de taal automatisch te detecteren.", "The LDAP attribute that maps to the mail that users use to sign in.": "Het LDAP-attribuut dat verwijst naar de e-mail waarmee gebruikers zich aanmelden.", "The LDAP attribute that maps to the username that users use to sign in.": "Het LDAP-attribuut dat verwijst naar de gebruikersnaam die gebruikers gebruiken om in te loggen.", "The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.": "Het leaderboard is momenteel in bèta en we kunnen de ratingberekeningen aanpassen naarmate we het algoritme verfijnen.", "The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.": "De maximale bestandsgrootte in MB. Als het bestand groter is dan deze limiet, wordt het bestand niet geüpload.", "The maximum number of files that can be used at once in chat. If the number of files exceeds this limit, the files will not be uploaded.": "Het maximum aantal bestanden dat in één keer kan worden gebruikt in de chat. Als het aantal bestanden deze limiet overschrijdt, worden de bestanden niet geüpload.", - "The output format for the text. Can be 'json', 'markdown', or 'html'. Defaults to 'markdown'.": "", - "The passwords you entered don't quite match. Please double-check and try again.": "", + "The output format for the text. Can be 'json', 'markdown', or 'html'. Defaults to 'markdown'.": "Het uitvoerformaat voor de tekst. Kan 'json', 'markdown' of 'html' zijn. Standaard is 'markdown'.", + "The passwords you entered don't quite match. Please double-check and try again.": "De ingevoerde wachtwoorden komen niet helemaal overeen. Controleer ze en probeer opnieuw.", "The score should be a value between 0.0 (0%) and 1.0 (100%).": "De score moet een waarde zijn tussen 0.0 (0%) en 1.0 (100%).", - "The stream delta chunk size for the model. Increasing the chunk size will make the model respond with larger pieces of text at once.": "", + "The stream delta chunk size for the model. Increasing the chunk size will make the model respond with larger pieces of text at once.": "De stream-delta-chunkgrootte voor het model. Door de chunkgrootte te vergroten, reageert het model met grotere stukken tekst tegelijk.", "The temperature of the model. Increasing the temperature will make the model answer more creatively.": "De temperatuur van het model. De temperatuur groter maken zal het model creatiever laten antwoorden.", - "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "", - "The width in pixels to compress images to. Leave empty for no compression.": "", + "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "Het gewicht van BM25-hybride zoeken. 0 meer semantisch, 1 meer lexicaal. Standaard 0,5", + "The width in pixels to compress images to. Leave empty for no compression.": "De breedte in pixels waarnaar afbeeldingen moeten worden gecomprimeerd. Laat leeg voor geen compressie.", "Theme": "Thema", - "There was an error syncing your stats. Please try again.": "", - "Thinking...": "Aan het denken...", - "This action cannot be undone. Do you wish to continue?": "Deze actie kan niet ongedaan worden gemaakt. Wilt u doorgaan?", + "There was an error syncing your stats. Please try again.": "Er is een fout opgetreden bij het synchroniseren van je statistieken. Probeer het opnieuw.", + "Thinking...": "Aan het nadenken...", + "This action cannot be undone. Do you wish to continue?": "Deze actie kan niet ongedaan worden gemaakt. Wil je doorgaan?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Dit kanaal is aangemaakt op {{createdAt}}. Dit is het begin van het kanaal {{channelName}}.", - "This chat won't appear in history and your messages will not be saved.": "", + "This chat won't appear in history and your messages will not be saved.": "Deze chat verschijnt niet in de geschiedenis en je berichten worden niet opgeslagen.", "This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "Dit zorgt ervoor dat je waardevolle gesprekken veilig worden opgeslagen in je backend database. Dank je wel!", - "This feature is currently experimental and may not work as expected.": "", - "This feature is experimental and may be modified or discontinued without notice.": "", - "This folder is empty": "", - "This is a default user permission and will remain enabled.": "", + "This feature is currently experimental and may not work as expected.": "Deze functie is momenteel experimenteel en werkt mogelijk niet zoals verwacht.", + "This feature is experimental and may be modified or discontinued without notice.": "Deze functie is experimenteel en kan zonder kennisgeving worden gewijzigd of stopgezet.", + "This folder is empty": "Deze map is leeg", + "This is a default user permission and will remain enabled.": "Dit is een standaardgebruikersrecht en blijft ingeschakeld.", "This is an experimental feature, it may not function as expected and is subject to change at any time.": "Dit is een experimentele functie, het werkt mogelijk niet zoals verwacht en kan op elk moment worden gewijzigd.", - "This model is not publicly available. Please select another model.": "", - "This option controls how long the model will stay loaded into memory following the request (default: 5m)": "", + "This model is not publicly available. Please select another model.": "Dit model is niet publiek beschikbaar. Selecteer een ander model.", + "This option controls how long the model will stay loaded into memory following the request (default: 5m)": "Deze optie bepaalt hoe lang het model na het verzoek in het geheugen geladen blijft (standaard: 5m)", "This option controls how many tokens are preserved when refreshing the context. For example, if set to 2, the last 2 tokens of the conversation context will be retained. Preserving context can help maintain the continuity of a conversation, but it may reduce the ability to respond to new topics.": "Deze optie bepaalt hoeveel tokens bewaard blijven bij het verversen van de context. Als deze bijvoorbeeld op 2 staat, worden de laatste 2 tekens van de context van het gesprek bewaard. Het behouden van de context kan helpen om de continuïteit van een gesprek te behouden, maar het kan de mogelijkheid om te reageren op nieuwe onderwerpen verminderen.", - "This option enables or disables the use of the reasoning feature in Ollama, which allows the model to think before generating a response. When enabled, the model can take a moment to process the conversation context and generate a more thoughtful response.": "", + "This option enables or disables the use of the reasoning feature in Ollama, which allows the model to think before generating a response. When enabled, the model can take a moment to process the conversation context and generate a more thoughtful response.": "Deze optie schakelt het gebruik van de redeneermogelijkheid in Ollama in of uit, waardoor het model eerst kan nadenken voordat het een antwoord genereert. Wanneer ingeschakeld, kan het model even de tijd nemen om de gesprekscontext te verwerken en een doordachter antwoord te genereren.", "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Deze optie stelt het maximum aantal tokens in dat het model kan genereren in zijn antwoord. Door deze limiet te verhogen, kan het model langere antwoorden geven, maar het kan ook de kans vergroten dat er onbehulpzame of irrelevante inhoud wordt gegenereerd.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Deze optie verwijdert alle bestaande bestanden in de collectie en vervangt ze door nieuw geüploade bestanden.", "This response was generated by \"{{model}}\"": "Dit antwoord is gegenereerd door \"{{model}}\"", @@ -2024,50 +2024,50 @@ "This will delete {{NAME}} and all its contents.": "Dit zal {{NAME}} verwijderen en al zijn inhoud.", "This will delete all models including custom models": "Dit zal alle modellen, ook aangepaste modellen, verwijderen", "This will delete all models including custom models and cannot be undone.": "Dit zal alle modellen, ook aangepaste modellen, verwijderen en kan niet ongedaan worden gemaakt", - "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", - "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dit zal de kennisdatabase resetten en alle bestanden synchroniseren. Wilt u doorgaan?", + "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dit zal de kennisdatabase resetten en alle bestanden synchroniseren. Wil je doorgaan?", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "Dit zal de kalender \"{{name}}\" en alle gebeurtenissen permanent verwijderen. Deze actie kan niet ongedaan worden gemaakt.", "Thorough explanation": "Grondige uitleg", - "Thought": "", - "Thought for {{DURATION}}": "Dacht {{DURATION}}", - "Thought for {{DURATION}} seconds": "Dacht {{DURATION}} seconden", - "Thought for less than a second": "", + "Thought": "Gedachte", + "Thought for {{DURATION}}": "Dacht {{DURATION}} na", + "Thought for {{DURATION}} seconds": "Dacht {{DURATION}} seconden na", + "Thought for less than a second": "Dacht minder dan een seconde na", "Thread": "Draad", - "Thumbs up/down ratings from users on model responses": "", + "Thumbs up/down ratings from users on model responses": "Duim omhoog/omlaag-beoordelingen van gebruikers op modelantwoorden", "Tika": "Tika", "Tika Server URL required.": "Tika Server-URL vereist", "Tiktoken": "Tiktoken", - "Time": "", - "Time & Calculation": "", - "Timeout": "", + "Time & Calculation": "Tijd en berekening", + "Timeout": "Time-out", + "Time": "Tijd", "Title": "Titel", - "Title Auto-Generation": "Titel Auto-Generatie", + "Title Auto-Generation": "Automatische titelgeneratie", "Title cannot be an empty string.": "Titel kan niet leeg zijn.", "Title Generation": "Titelgeneratie", - "Title Generation Prompt": "Titel Generatie Prompt", - "Title is required": "", + "Title Generation Prompt": "Prompt voor titelgeneratie", + "Title is required": "Titel is vereist", "TLS": "TLS", "To access the available model names for downloading,": "Om de beschikbare modelnamen voor downloaden te openen,", "To access the GGUF models available for downloading,": "Om toegang te krijgen tot de GGUF-modellen die beschikbaar zijn voor downloaden,", "To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Om toegang te krijgen tot de WebUI, neem contact op met de administrator. Beheerders kunnen de gebruikersstatussen beheren vanuit het Beheerderspaneel.", "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Om hier een kennisbron bij te voegen, voeg ze eerst aan de \"Kennis\" werkplaats toe.", "To learn more about available endpoints, visit our documentation.": "Om meer over beschikbare endpoints te leren, bezoek onze documentatie.", - "To select skills here, add them to the \"Skills\" workspace first.": "", + "To select skills here, add them to the \"Skills\" workspace first.": "Om hier vaardigheden te selecteren, voeg ze eerst toe aan de \"Vaardigheden\"-werkruimte.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Om hier gereedschapssets te selecteren, voeg ze eerst aan de \"Gereedschappen\" Werkplaats toe.", "Toast notifications for new updates": "Toon notificaties voor nieuwe updates", "Today": "Vandaag", - "Today at": "", - "Today at {{LOCALIZED_TIME}}": "", - "Toggle {{COUNT}} sources": "", - "Toggle 1 source": "", - "Toggle details": "", - "Toggle Dictation": "", - "Toggle Sidebar": "", - "Toggle status history": "", - "Toggle whether current connection is active.": "", + "Today at {{LOCALIZED_TIME}}": "Vandaag om {{LOCALIZED_TIME}}", + "Toggle {{COUNT}} sources": "Schakel {{COUNT}} bronnen om", + "Toggle 1 source": "Schakel 1 bron om", + "Toggle details": "Details omzetten", + "Toggle Dictation": "Dicteren omzetten", + "Toggle Sidebar": "Zijbalk omzetten", + "Toggle status history": "Statusgeschiedenis omzetten", + "Toggle whether current connection is active.": "Schakel in of de huidige verbinding actief is.", + "Today at": "Vandaag om", "Token": "Token", - "Token counts are estimates and may not reflect actual API usage": "", - "tokens": "", - "Tokens": "", + "Token counts are estimates and may not reflect actual API usage": "Tokenaantallen zijn schattingen en komen mogelijk niet overeen met het werkelijke API-gebruik", + "tokens": "tokens", + "Tokens": "Tokens", "Too verbose": "Te langdradig", "Tool created successfully": "Gereedschap succesvol aangemaakt", "Tool deleted successfully": "Gereedschap succesvol verwijderd", @@ -2075,7 +2075,7 @@ "Tool ID": "Gereedschaps-ID", "Tool imported successfully": "Gereedschap succesvol geïmporteerd", "Tool Name": "Gereedschapsnaam", - "Tool Servers": "", + "Tool Servers": "Toolservers", "Tool updated successfully": "Gereedschap succesvol bijgewerkt", "Tools": "Gereedschappen", "Tools Access": "Gereedschaptoegang", @@ -2083,204 +2083,204 @@ "Tools Function Calling Prompt": "Gereedschapsfunctie aanroepprompt", "Tools have a function calling system that allows arbitrary code execution.": "Gereedschappen hebben een systeem voor het aanroepen van functies waarmee willekeurige code kan worden uitgevoerd", "Tools Public Sharing": "Gereedschappen publiek delen", - "Tools Sharing": "", - "Top": "", + "Tools Sharing": "Tools delen", + "Top": "Top", "Top K": "Top K", "Top K Reranker": "Top K herranker", "Transformers": "Transformers", "Trouble accessing Ollama?": "Problemen met toegang tot Ollama?", "Trust Proxy Environment": "Vertrouwelijk proxyomgeving", - "Try adjusting your search or filter to find what you are looking for.": "", - "Try Again": "", + "Try adjusting your search or filter to find what you are looking for.": "Probeer je zoekopdracht of filter aan te passen om te vinden wat je zoekt.", + "Try Again": "Probeer opnieuw", "TTS Model": "TTS Model", "TTS Settings": "TTS instellingen", "TTS Voice": "TTS Stem", - "Tu_day_of_week": "", + "Tu_day_of_week": "di", "Type": "Type", - "Type here...": "", + "Type here...": "Typ hier...", "Type Hugging Face Resolve (Download) URL": "Type Hugging Face Resolve (Download) URL", "Uh-oh! There was an issue with the response.": "Oh-oh! Er was een probleem met het antwoord.", "UI": "UI", - "UI Scale": "", + "UI Scale": "UI-schaal", "Unarchive All": "Onarchiveer alles", "Unarchive All Archived Chats": "Onarchiveer alle gearchiveerde chats", "Unarchive Chat": "Onarchiveer chat", - "Underline": "", - "Unknown": "", - "Unknown User": "", - "Unloads {{FROM_NOW}}": "", + "Underline": "Onderstrepen", + "Unknown": "Onbekend", + "Unknown User": "Onbekende gebruiker", + "Unloads {{FROM_NOW}}": "Laadt over {{FROM_NOW}} uit", "Unlock mysteries": "Ontsleutel mysteries", "Unpin": "Losmaken", - "Unpin from Sidebar": "", + "Unpin from Sidebar": "Losmaken van zijbalk", "Unravel secrets": "Ontrafel geheimen", - "Unshare Chat": "", - "Unsupported file type.": "", + "Unshare Chat": "Chat delen opheffen", + "Unsupported file type.": "Niet-ondersteund bestandstype.", "Untagged": "Ongemarkeerd", - "Untitled": "", + "Untitled": "Zonder titel", "Update": "Bijwerken", "Update and Copy Link": "Bijwerken en kopieer link", "Update for the latest features and improvements.": "Bijwerken voor de nieuwste functies en verbeteringen", "Update password": "Wijzig wachtwoord", - "Update your status": "", + "Update your status": "Werk je status bij", "Updated": "Bijgewerkt", "Updated at": "Bijgewerkt om", "Updated At": "Bijgewerkt om", "Upgrade to a licensed plan for enhanced capabilities, including custom theming and branding, and dedicated support.": "Upgrade naar een licentie voor meer mogelijkheden, waaronder aangepaste thematisering en branding, en speciale ondersteuning.", "Upload": "Uploaden", "Upload a GGUF model": "Upload een GGUF-model", - "Upload Audio": "", + "Upload Audio": "Audio uploaden", "Upload directory": "Upload map", "Upload files": "Bestanden uploaden", "Upload Files": "Bestanden uploaden", - "Upload Model": "", + "Upload Model": "Model uploaden", "Upload Pipeline": "Upload Pijpleiding", - "Upload profile image": "", + "Upload profile image": "Profielafbeelding uploaden", "Upload Progress": "Upload Voortgang", - "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", - "Uploaded files or images": "", - "Uploading file...": "", - "Uploading...": "", + "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Uploadvoortgang: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "Geüploade bestanden of afbeeldingen", + "Uploading file...": "Bestand aan het uploaden...", + "Uploading...": "Aan het uploaden...", "URL": "URL", - "URL is required": "", + "URL is required": "URL is vereist", "URL Mode": "URL-modus", - "Usage": "", - "Use": "", + "Usage": "Gebruik", + "Use": "Gebruiken", "Use '#' in the prompt input to load and include your knowledge.": "Gebruik '#' in de promptinvoer om je kennis te laden en op te nemen.", - "Use /v1/chat/completions endpoint instead of /v1/audio/transcriptions for potentially better accuracy.": "", - "Use Chat Completions API": "", - "Use groups to organize your users and assign permissions.": "", - "Use LLM": "", - "Use no proxy to fetch page contents.": "", - "Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "", + "Use /v1/chat/completions endpoint instead of /v1/audio/transcriptions for potentially better accuracy.": "Gebruik het /v1/chat/completions-endpoint in plaats van /v1/audio/transcriptions voor mogelijk betere nauwkeurigheid.", + "Use Chat Completions API": "Gebruik Chat Completions API", + "Use groups to organize your users and assign permissions.": "Gebruik groepen om je gebruikers te organiseren en machtigingen toe te kennen.", + "Use LLM": "LLM gebruiken", + "Use no proxy to fetch page contents.": "Gebruik geen proxy om paginainhoud op te halen.", + "Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "Gebruik de proxy die is opgegeven door de omgevingsvariabelen http_proxy en https_proxy om paginainhoud op te halen.", "user": "gebruiker", "User": "Gebruiker", - "User Activity": "", - "User Groups": "", + "User Activity": "Gebruikersactiviteit", + "User Groups": "Gebruikersgroepen", "User location successfully retrieved.": "Gebruikerslocatie succesvol opgehaald", - "User menu": "", - "User ratings (thumbs up/down)": "", - "User Status": "", + "User menu": "Gebruikersmenu", + "User ratings (thumbs up/down)": "Gebruikersbeoordelingen (duim omhoog/omlaag)", + "User Status": "Gebruikersstatus", "User Webhooks": "Gebruiker-webhooks", "Username": "Gebruikersnaam", - "users": "", + "users": "gebruikers", "Users": "Gebruikers", - "Uses DefaultAzureCredential to authenticate": "", - "Uses OAuth 2.1 Dynamic Client Registration": "", - "Using Entire Document": "", - "Using Focused Retrieval": "", + "Uses DefaultAzureCredential to authenticate": "Gebruikt DefaultAzureCredential voor authenticatie", + "Uses OAuth 2.1 Dynamic Client Registration": "Gebruikt dynamische clientregistratie van OAuth 2.1", + "Using Entire Document": "Volledig document gebruiken", + "Using Focused Retrieval": "Gerichte retrieval gebruiken", "Using the default arena model with all models. Click the plus button to add custom models.": "Het standaard arena-model gebruiken met alle modellen. Klik op de plusknop om aangepaste modellen toe te voegen.", "Valid time units:": "Geldige tijdseenheden:", - "Validate certificate": "", + "Validate certificate": "Certificaat valideren", "Valves": "Kleppen", "Valves updated": "Kleppen bijgewerkt", "Valves updated successfully": "Kleppen succesvol bijgewerkt", "variable": "variabele", "Verify Connection": "Controleer verbinding", - "Verify SSL Certificate": "", + "Verify SSL Certificate": "SSL-certificaat verifiëren", "Version": "Versie", "Version {{selectedVersion}} of {{totalVersions}}": "Versie {{selectedVersion}} van {{totalVersions}}", - "Version deleted": "", + "Version deleted": "Versie verwijderd", "View Replies": "Bekijke resultaten", - "View Result from **{{NAME}}**": "", - "View source: {{name}}": "", - "View source: {{title}}": "", + "View Result from **{{NAME}}**": "Bekijk resultaat van **{{NAME}}**", + "View source: {{name}}": "Bekijk bron: {{name}}", + "View source: {{title}}": "Bekijk bron: {{title}}", "Visibility": "Zichtbaarheid", - "Visible": "", - "Visible to all users": "", - "Vision": "", + "Visible": "Zichtbaar", + "Visible to all users": "Zichtbaar voor alle gebruikers", + "Vision": "Visie", "Voice": "Stem", "Voice Input": "Steminvoer", - "Voice mode": "", - "Voice Mode Custom Prompt": "", - "Voice Mode Prompt": "", - "Waiting for upload...": "", + "Voice mode": "Spraakmodus", + "Voice Mode Custom Prompt": "Aangepaste prompt voor spraakmodus", + "Voice Mode Prompt": "Prompt voor spraakmodus", + "Waiting for upload...": "Wachten op upload...", "Warning": "Waarschuwing", "Warning:": "Waarschuwing", - "Warning: Enabling this will allow users to run scheduled prompts automatically.": "", + "Warning: Enabling this will allow users to run scheduled prompts automatically.": "Waarschuwing: Als je dit inschakelt, kunnen gebruikers geplande prompts automatisch uitvoeren.", "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Waarschuwing: Door dit in te schakelen kunnen gebruikers willekeurige code uploaden naar de server.", "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Waarschuwing: Jupyter kan willekeurige code uitvoeren, wat ernstige veiligheidsrisico's met zich meebrengt - ga uiterst voorzichtig te werk. ", - "We_day_of_week": "", + "We_day_of_week": "wo", "Web": "Web", "Web API": "Web-API", - "Web Loader Engine": "", + "Web Loader Engine": "Webloader-engine", "Web Search": "Zoeken op het web", "Web Search Engine": "Zoekmachine op het web", "Web Search in Chat": "Zoekopdracht in chat", "Web Search Query Generation": "Zoekopdracht generatie", - "Webhook Name": "", + "Webhook Name": "Webhooknaam", "Webhook URL": "Webhook URL", - "Webhooks": "", - "Webpage URLs": "", + "Webhooks": "Webhooks", + "Webpage URLs": "Webpagina-URL's", "WebUI Settings": "WebUI Instellingen", "WebUI URL": "WebUI-URL", - "WebUI will make requests to \"{{url}}\"": "", + "WebUI will make requests to \"{{url}}\"": "WebUI zal verzoeken doen aan \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI zal verzoeken doen aan \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI zal verzoeken doen aan \"{{url}}/chat/completions\"", - "Week": "", - "Weekly": "", + "Week": "Week", + "Weekly": "Wekelijks", "What are you trying to achieve?": "Wat probeer je te bereiken?", "What are you working on?": "Waar werk je aan?", - "What is NOT shared:": "", - "What is shared:": "", + "What is NOT shared:": "Wat NIET wordt gedeeld:", + "What is shared:": "Wat wordt gedeeld:", "What's New in": "Wat is nieuw in", - "What's on your mind?": "", - "When": "", + "What's on your mind?": "Waar denk je aan?", + "When": "Wanneer", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "Als dit is ingeschakeld, reageert het model op elk chatbericht in real-time, waarbij een reactie wordt gegenereerd zodra de gebruiker een bericht stuurt. Deze modus is handig voor live chat-toepassingen, maar kan de prestaties op langzamere hardware beïnvloeden.", "wherever you are": "waar je ook bent", - "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", + "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Of de uitvoer moet worden gepagineerd. Elke pagina wordt gescheiden door een horizontale lijn en een paginanummer. Standaard is False.", "Whisper (Local)": "Whisper (Lokaal)", - "Who can share to this group": "", + "Who can share to this group": "Wie kan delen met deze groep", "Why?": "Waarom?", "Widescreen Mode": "Breedschermmodus", - "Width": "", - "Wikipedia": "", + "Width": "Breedte", + "Wikipedia": "Wikipedia", "Won": "Gewonnen", - "Working Directory": "", + "Working Directory": "Werkmap", "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.": "Werkt samen met top-k. Een hogere waarde (bijv. 0,95) leidt tot meer diverse tekst, terwijl een lagere waarde (bijv. 0,5) meer gerichte en conservatieve tekst genereert.", "Workspace": "Werkruimte", "Workspace Permissions": "Werkruimtemachtigingen", "Write": "Schrijf", - "Write a summary in 50 words that summarizes {{topic}}.": "Schrijf een samenvatting in 50 woorden die [onderwerp of trefwoord] samenvat.", + "Write a summary in 50 words that summarizes {{topic}}.": "Schrijf een samenvatting in 50 woorden die {{topic}} samenvat.", "Write something...": "Schrijf iets...", "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "Schrijf hier de inhoud van de systeemprompt van je model\nbijv.: Je bent Mario uit Super Mario Bros en treedt op als assistent.", - "Yacy Instance URL": "", - "Yacy Password": "", - "Yacy Username": "", - "Yahoo": "", - "Yandex": "", - "Yandex Web Search API Key": "", - "Yandex Web Search config": "", - "Yandex Web Search URL": "", + "Yacy Instance URL": "Yacy-instantie-URL", + "Yacy Password": "Yacy-wachtwoord", + "Yacy Username": "Yacy-gebruikersnaam", + "Yahoo": "Yahoo", + "Yandex": "Yandex", + "Yandex Web Search API Key": "Yandex Web Search API-sleutel", + "Yandex Web Search config": "Yandex Web Search-configuratie", + "Yandex Web Search URL": "Yandex Web Search-URL", "Yesterday": "Gisteren", - "Yesterday at {{LOCALIZED_TIME}}": "", + "Yesterday at {{LOCALIZED_TIME}}": "Gisteren om {{LOCALIZED_TIME}}", "You": "Jij", "You are currently using a trial license. Please contact support to upgrade your license.": "Je gebruikt momenteel een proeflicentie. Neem contact op met de ondersteuning om je licentie te upgraden.", "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Je kunt slechts met maximaal {{maxCount}} bestand(en) tegelijk chatten", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Je kunt je interacties met LLM's personaliseren door herinneringen toe te voegen via de 'Beheer'-knop hieronder, waardoor ze nuttiger en voor jou op maat gemaakt worden.", "You cannot upload an empty file.": "Je kunt een leeg bestand niet uploaden.", - "You do not have permission to edit this model": "", - "You do not have permission to edit this prompt.": "", - "You do not have permission to edit this skill.": "", - "You do not have permission to edit this tool": "", - "You do not have permission to make this public": "", - "You do not have permission to send messages in this channel.": "", - "You do not have permission to send messages in this thread.": "", - "You do not have permission to upload files to this knowledge base.": "", + "You do not have permission to edit this model": "Je hebt geen toestemming om dit model te bewerken", + "You do not have permission to edit this prompt.": "Je hebt geen toestemming om deze prompt te bewerken.", + "You do not have permission to edit this skill.": "Je hebt geen toestemming om deze vaardigheid te bewerken.", + "You do not have permission to edit this tool": "Je hebt geen toestemming om deze tool te bewerken", + "You do not have permission to make this public": "Je hebt geen toestemming om dit openbaar te maken", + "You do not have permission to send messages in this channel.": "Je hebt geen toestemming om berichten in dit kanaal te verzenden.", + "You do not have permission to send messages in this thread.": "Je hebt geen toestemming om berichten in deze draad te verzenden.", + "You do not have permission to upload files to this knowledge base.": "Je hebt geen toestemming om bestanden naar deze kennisbank te uploaden.", "You do not have permission to upload files.": "Je hebt geen toestemming om bestanden up te loaden", - "You do not have permission to upload web content.": "", + "You do not have permission to upload web content.": "Je hebt geen toestemming om webinhoud te uploaden.", "You have no archived conversations.": "Je hebt geen gearchiveerde gesprekken.", - "You have no shared conversations.": "", + "You have no shared conversations.": "Je hebt geen gedeelde gesprekken.", "You have shared this chat": "Je hebt dit gesprek gedeeld", - "You.com API Key": "", + "You.com API Key": "You.com API-sleutel", "You're a helpful assistant.": "Je bent een behulpzame assistent.", "You're now logged in.": "Je bent nu ingelogd.", - "Your Account": "", + "Your Account": "Je account", "Your account status is currently pending activation.": "Je accountstatus wacht nu op activatie", - "Your browser does not support the audio tag.": "", - "Your browser does not support the video tag.": "", + "Your browser does not support the audio tag.": "Je browser ondersteunt de audio-tag niet.", + "Your browser does not support the video tag.": "Je browser ondersteunt de video-tag niet.", "Your entire contribution will go directly to the plugin developer; Open WebUI does not take any percentage. However, the chosen funding platform might have its own fees.": "Je volledige bijdrage gaat direct naar de ontwikkelaar van de plugin; Open WebUI neemt hier geen deel van. Het gekozen financieringsplatform kan echter wel zijn eigen kosten hebben.", - "Your message text or inputs": "", - "Your usage stats have been successfully synced.": "", + "Your message text or inputs": "Je berichttekst of invoer", + "Your usage stats have been successfully synced.": "Je gebruiksstatistieken zijn succesvol gesynchroniseerd.", "YouTube": "Youtube", "Youtube Language": "Youtube-taal", "Youtube Proxy URL": "Youtube-proxy-URL" From 7da6b82471f0867450f622eb12e01637655c8e7f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:35:59 +0900 Subject: [PATCH 372/404] refac --- backend/open_webui/routers/ollama.py | 13 ++++++++++++- backend/open_webui/routers/openai.py | 19 +++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index b957310b58..8311fee5d4 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -86,6 +86,17 @@ log = logging.getLogger(__name__) # ########################################## +# Headers that become stale after aiohttp auto-decompresses the upstream +# response body. Forwarding them verbatim causes desktop / programmatic +# clients to attempt decompression of an already-decoded payload, resulting +# in ZlibError. See https://github.com/aio-libs/aiohttp/issues/4462. +_STRIP_PROXY_HEADERS = frozenset({'Content-Encoding', 'Content-Length', 'Transfer-Encoding'}) + + +def _clean_proxy_headers(raw_headers) -> dict: + """Return a copy of *raw_headers* with stale encoding headers removed.""" + return {k: v for k, v in raw_headers.items() if k not in _STRIP_PROXY_HEADERS} + async def send_get_request(url, key=None, user: UserModel = None): timeout = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST) @@ -163,7 +174,7 @@ async def send_request( r.raise_for_status() if stream: - response_headers = dict(r.headers) + response_headers = _clean_proxy_headers(r.headers) if content_type: response_headers['Content-Type'] = content_type diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index 8a7c3aca72..6f8c0f81bf 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -76,6 +76,17 @@ log = logging.getLogger(__name__) # ########################################## +# Headers that become stale after aiohttp auto-decompresses the upstream +# response body. Forwarding them verbatim causes desktop / programmatic +# clients to attempt decompression of an already-decoded payload, resulting +# in ZlibError. See https://github.com/aio-libs/aiohttp/issues/4462. +_STRIP_PROXY_HEADERS = frozenset({'Content-Encoding', 'Content-Length', 'Transfer-Encoding'}) + + +def _clean_proxy_headers(raw_headers) -> dict: + """Return a copy of *raw_headers* with stale encoding headers removed.""" + return {k: v for k, v in raw_headers.items() if k not in _STRIP_PROXY_HEADERS} + async def send_get_request( request: Request = None, @@ -1219,7 +1230,7 @@ async def generate_chat_completion( return StreamingResponse( stream_wrapper(r, content_handler=stream_chunks_handler), status_code=r.status, - headers=dict(r.headers), + headers=_clean_proxy_headers(r.headers), ) else: try: @@ -1304,7 +1315,7 @@ async def embeddings(request: Request, form_data: dict, user): return StreamingResponse( stream_wrapper(r), status_code=r.status, - headers=dict(r.headers), + headers=_clean_proxy_headers(r.headers), ) else: try: @@ -1425,7 +1436,7 @@ async def responses( return StreamingResponse( stream_wrapper(r), status_code=r.status, - headers=dict(r.headers), + headers=_clean_proxy_headers(r.headers), ) else: try: @@ -1542,7 +1553,7 @@ async def proxy(path: str, request: Request, user=Depends(get_verified_user)): return StreamingResponse( stream_wrapper(r), status_code=r.status, - headers=dict(r.headers), + headers=_clean_proxy_headers(r.headers), ) else: try: From a76652193385fe248425956d3075119f4e5bfbbf Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:39:12 +0900 Subject: [PATCH 373/404] refac --- backend/open_webui/tools/builtin.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index afa3cb63a9..25d6a2cecb 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2568,8 +2568,11 @@ async def create_automation( if not user: return json.dumps({'error': 'User not found'}) - # Always use the calling model for the automation - model_id = (__metadata__ or {}).get('model_id') + # Fall back to model dict ID since __metadata__ may predate model_id assignment + metadata = __metadata__ or {} + model_id = metadata.get('model_id') or ( + metadata.get('model', {}).get('id') if isinstance(metadata.get('model'), dict) else None + ) if not model_id: return json.dumps({'error': 'Could not detect current model'}) From a76a779c01e2e9106eacf141424b28fa870cb21e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:40:02 +0900 Subject: [PATCH 374/404] refac --- backend/start_windows.bat | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/start_windows.bat b/backend/start_windows.bat index c8587c3c6d..c5f96e0e6f 100644 --- a/backend/start_windows.bat +++ b/backend/start_windows.bat @@ -24,7 +24,7 @@ IF NOT "%WEBUI_SECRET_KEY_FILE%" == "" ( IF "%PORT%"=="" SET PORT=8080 IF "%HOST%"=="" SET HOST=0.0.0.0 -IF "%FORWARDED_ALLOW_IPS%"=="" SET "FORWARDED_ALLOW_IPS=*" +IF "%FORWARDED_ALLOW_IPS%"=="" SET "FORWARDED_ALLOW_IPS='*'" SET "WEBUI_SECRET_KEY=%WEBUI_SECRET_KEY%" SET "WEBUI_JWT_SECRET_KEY=%WEBUI_JWT_SECRET_KEY%" @@ -47,5 +47,5 @@ IF "%WEBUI_SECRET_KEY% %WEBUI_JWT_SECRET_KEY%" == " " ( :: Execute uvicorn SET "WEBUI_SECRET_KEY=%WEBUI_SECRET_KEY%" IF "%UVICORN_WORKERS%"=="" SET UVICORN_WORKERS=1 -uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips "%FORWARDED_ALLOW_IPS%" --workers %UVICORN_WORKERS% --ws auto +uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips %FORWARDED_ALLOW_IPS% --workers %UVICORN_WORKERS% --ws auto :: For ssl user uvicorn open_webui.main:app --host "%HOST%" --port "%PORT%" --forwarded-allow-ips '*' --ssl-keyfile "key.pem" --ssl-certfile "cert.pem" --ws auto From f2cb63140c1109b9ea73ece97073dcb3f37ab8f3 Mon Sep 17 00:00:00 2001 From: Jacob Leksan <63938553+jmleksan@users.noreply.github.com> Date: Fri, 24 Apr 2026 02:45:10 -0400 Subject: [PATCH 375/404] perf: redirect default model profile image to canonical static URL (#24015) - Return 302 to /static/favicon.png instead of streaming the same PNG per model id so browsers can cache one asset for default avatars. - Validate stored /static/ paths with decode, normpath, and /static prefix checks; invalid paths fall back to favicon. Made-with: Cursor --- backend/open_webui/routers/models.py | 53 +++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index 3ef0838fcc..079245d550 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -4,6 +4,8 @@ import base64 import json import asyncio import logging +import posixpath +from urllib.parse import unquote from open_webui.models.groups import Groups from open_webui.models.models import ( @@ -29,12 +31,12 @@ from fastapi import ( status, Response, ) -from fastapi.responses import FileResponse, StreamingResponse +from fastapi.responses import RedirectResponse, StreamingResponse from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.access_control import has_permission, filter_allowed_access_grants -from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL, STATIC_DIR +from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL from open_webui.internal.db import get_async_session from sqlalchemy.ext.asyncio import AsyncSession @@ -43,6 +45,34 @@ log = logging.getLogger(__name__) router = APIRouter() +def _safe_static_redirect_path(url: str) -> Optional[str]: + """ + If url is a same-origin static asset path, return a normalized path safe for + RedirectResponse Location. Otherwise None (caller should fall back to default). + Rejects traversal (..), encoded dots, query/fragment, and non-/static targets. + """ + if not url or not isinstance(url, str): + return None + path = url.split('?', 1)[0].split('#', 1)[0].strip() + for _ in range(2): + decoded = unquote(path) + if decoded == path: + break + path = decoded + if '\x00' in path or '\\' in path: + return None + if not path.startswith('/'): + return None + normalized = posixpath.normpath(path) + if normalized in ('.', '/'): + return None + if not (normalized == '/static' or normalized.startswith('/static/')): + return None + if normalized == '/static': + return '/static/' + return normalized + + def is_valid_model_id(model_id: str) -> bool: return model_id and len(model_id) <= 256 @@ -465,10 +495,25 @@ async def get_model_profile_image( ) except Exception as e: pass + else: + safe_static = _safe_static_redirect_path(model.meta.profile_image_url) + if safe_static: + return RedirectResponse( + url=safe_static, + status_code=status.HTTP_302_FOUND, + ) - return FileResponse(f'{STATIC_DIR}/favicon.png') + # Canonical URL so browsers cache one asset for all default model avatars + # (distinct /profile/image?id=... URLs would otherwise re-download the same bytes). + return RedirectResponse( + url='/static/favicon.png', + status_code=status.HTTP_302_FOUND, + ) else: - return FileResponse(f'{STATIC_DIR}/favicon.png') + return RedirectResponse( + url='/static/favicon.png', + status_code=status.HTTP_302_FOUND, + ) ############################ From 26711c1bcc82bb03769545ca8d44e81a100b452e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:46:08 +0900 Subject: [PATCH 376/404] refac --- backend/open_webui/main.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index b56659e721..2299ef84c4 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1836,7 +1836,7 @@ async def chat_completion( except HTTPException: raise except Exception as e: - log.debug(f'Error processing chat metadata: {e}') + log.warning(f'Error processing chat metadata: {e}') raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail=str(e), @@ -1908,6 +1908,15 @@ async def chat_completion( except Exception: pass + else: + # No chat_id/message_id → legacy/direct API path with no + # WebSocket error channel. We must surface the error as + # a proper HTTP response; without this the function would + # return None which FastAPI serializes as null. #23924 + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=error_detail, + ) finally: # MCP cleanup — MUST run in the SAME asyncio task as # connect() because the MCP SDK's streamablehttp_client From 5cc55e227815dbb9c466243f16d8358cfd845d82 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 15:51:54 +0900 Subject: [PATCH 377/404] refac --- backend/open_webui/utils/middleware.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index fa6c65f36d..813ced0466 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -4658,6 +4658,7 @@ async def streaming_chat_response_handler(response, ctx): **form_data, 'model': model_id, 'stream': True, + 'metadata': metadata, } if ENABLE_RESPONSES_API_STATEFUL and last_response_id: @@ -4881,6 +4882,7 @@ async def streaming_chat_response_handler(response, ctx): **form_data, 'model': model_id, 'stream': True, + 'metadata': metadata, 'messages': [ *form_data['messages'], *convert_output_to_messages(output, raw=True), From 678c44c7cdade74c14092fd4de549b7a3d737921 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:17:46 +0900 Subject: [PATCH 378/404] refac --- backend/open_webui/internal/db.py | 196 ++++++++++++------ backend/open_webui/migrations/env.py | 6 +- backend/open_webui/models/oauth_sessions.py | 15 ++ backend/open_webui/routers/auths.py | 45 +++- backend/open_webui/routers/tools.py | 1 + backend/open_webui/routers/users.py | 4 + src/lib/apis/auths/index.ts | 30 +++ src/lib/apis/configs/index.ts | 1 + src/lib/apis/tools/index.ts | 1 + src/lib/apis/users/index.ts | 1 + .../chat/MessageInput/IntegrationsMenu.svelte | 38 ++++ static/pyodide/pyodide-lock.json | 6 +- 12 files changed, 268 insertions(+), 76 deletions(-) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index 25aa94591b..3a4a22c55d 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -3,6 +3,7 @@ import json import logging import ssl as _stdlib_ssl from contextlib import asynccontextmanager, contextmanager +from dataclasses import dataclass from typing import Any, Optional from urllib.parse import parse_qs, urlencode, urlparse, urlunparse @@ -37,90 +38,154 @@ from typing_extensions import Self log = logging.getLogger(__name__) -def extract_ssl_mode_from_url(url: str) -> tuple[str, str | None]: - """Strip SSL query-string parameters from a PostgreSQL URL. +@dataclass +class SSLParams: + """SSL parameters extracted from a PostgreSQL ``DATABASE_URL``. - asyncpg and psycopg2 use different query-string keys for SSL - (``ssl`` vs ``sslmode``). This helper removes **both** from the - URL so that each driver can receive the correct parameter through - its own mechanism (query-string re-injection for psycopg2, - ``connect_args`` for asyncpg). - - Returns - ------- - (url_without_ssl, ssl_mode) - *url_without_ssl* is the original URL with ``ssl`` / ``sslmode`` - query parameters removed. *ssl_mode* is the extracted mode - string (e.g. ``'require'``), or ``None`` if neither parameter - was present. - - Non-PostgreSQL URLs are returned unchanged with ``ssl_mode=None``. + Holds the connection-mode flag and optional certificate file paths + so that each driver (asyncpg, psycopg2/libpq) can receive them in + the format it expects. """ - if not url or not any(url.startswith(prefix) for prefix in ('postgresql://', 'postgresql+', 'postgres://')): - return url, None + + mode: str | None = None + rootcert: str | None = None + cert: str | None = None + key: str | None = None + crl: str | None = None + + def __bool__(self) -> bool: + return self.mode is not None + + @property + def has_any(self) -> bool: + """True when *any* SSL-related field is set (mode or cert files).""" + return any((self.mode, self.rootcert, self.cert, self.key, self.crl)) + + +# ── URL extraction / reattachment ──────────────────────────────────── + + +def _pop_first(params: dict[str, list[str]], key: str) -> str | None: + """Pop a single-valued query param, returning ``None`` if absent.""" + values = params.pop(key, None) + return values[0] if values else None + + +def extract_ssl_params_from_url(url: str) -> tuple[str, SSLParams]: + """Strip all SSL query-string parameters from a PostgreSQL URL. + + asyncpg does not accept libpq-style certificate-file keys + (``sslrootcert``, ``sslcert``, ``sslkey``, ``sslcrl``), so every + SSL-related key is removed and returned as a structured + :class:`SSLParams` object. + + Returns ``(url_without_ssl, ssl_params)``. Non-PostgreSQL URLs are + returned unchanged with an empty ``SSLParams``. + """ + if not url or not any( + url.startswith(p) for p in ('postgresql://', 'postgresql+', 'postgres://') + ): + return url, SSLParams() parsed = urlparse(url) - query_params = parse_qs(parsed.query, keep_blank_values=True) + qp = parse_qs(parsed.query, keep_blank_values=True) - # Prefer sslmode (libpq canonical) over the asyncpg-only ssl key. - ssl_mode: str | None = None - for key in ('sslmode', 'ssl'): - values = query_params.pop(key, None) - if values and ssl_mode is None: - ssl_mode = values[0] + # Prefer sslmode (libpq canonical) over the asyncpg-only ``ssl`` key. + # Both must be popped unconditionally so neither leaks into the cleaned URL. + sslmode_val = _pop_first(qp, 'sslmode') + ssl_val = _pop_first(qp, 'ssl') + ssl_mode = sslmode_val or ssl_val - if ssl_mode is None: - # Nothing to strip — return the URL untouched. - return url, None + params = SSLParams( + mode=ssl_mode, + rootcert=_pop_first(qp, 'sslrootcert'), + cert=_pop_first(qp, 'sslcert'), + key=_pop_first(qp, 'sslkey'), + crl=_pop_first(qp, 'sslcrl'), + ) - # Rebuild the query string without the SSL keys. - remaining_query = urlencode(query_params, doseq=True) - url_without_ssl = urlunparse(parsed._replace(query=remaining_query)) - return url_without_ssl, ssl_mode + if not params.has_any: + return url, params + + cleaned_query = urlencode(qp, doseq=True) + return urlunparse(parsed._replace(query=cleaned_query)), params -def build_asyncpg_ssl_args(ssl_mode: str | None) -> dict: - """Convert a libpq-style SSL mode value to asyncpg ``connect_args``. +def reattach_ssl_params_to_url(url_without_ssl: str, ssl_params: SSLParams) -> str: + """Re-append SSL query-string parameters to a cleaned PostgreSQL URL. + + Used for psycopg2/libpq consumers that expect ``sslmode`` and the + certificate-file keys in the connection string. + """ + if not ssl_params: + return url_without_ssl + + mapping = ( + ('sslmode', ssl_params.mode), + ('sslrootcert', ssl_params.rootcert), + ('sslcert', ssl_params.cert), + ('sslkey', ssl_params.key), + ('sslcrl', ssl_params.crl), + ) + parts = [f'{k}={v}' for k, v in mapping if v] + if not parts: + return url_without_ssl + + sep = '&' if '?' in url_without_ssl else '?' + return f'{url_without_ssl}{sep}{"&".join(parts)}' + + +# ── asyncpg SSLContext builder ─────────────────────────────────────── + + +def _make_ssl_context(ssl_params: SSLParams, *, verify: bool) -> _stdlib_ssl.SSLContext: + """Create an :class:`ssl.SSLContext` from *ssl_params*. + + When *verify* is ``False``, hostname checking and certificate + verification are disabled (matching libpq ``require`` semantics). + """ + ctx = _stdlib_ssl.create_default_context(cafile=ssl_params.rootcert) + if not verify: + ctx.check_hostname = False + ctx.verify_mode = _stdlib_ssl.CERT_NONE + if ssl_params.cert and ssl_params.key: + ctx.load_cert_chain(certfile=ssl_params.cert, keyfile=ssl_params.key) + if verify and ssl_params.crl: + ctx.load_verify_locations(cafile=ssl_params.crl) + ctx.verify_flags |= _stdlib_ssl.VERIFY_CRL_CHECK_LEAF + return ctx + + +def build_asyncpg_ssl_args(ssl_params: SSLParams) -> dict: + """Convert :class:`SSLParams` to asyncpg-compatible ``connect_args``. Returns a dict suitable for unpacking into - ``create_async_engine(..., connect_args=...)``. + ``create_async_engine(...)``. """ - if ssl_mode is None: + if not ssl_params: return {} - mode = ssl_mode.lower() + mode = (ssl_params.mode or 'require').lower() + if mode == 'disable': return {'connect_args': {'ssl': False}} if mode in ('allow', 'prefer'): - # asyncpg has no direct equivalent — omit to let it try without. return {} if mode == 'require': - # SSL required but no certificate verification (matches libpq). - ctx = _stdlib_ssl.create_default_context() - ctx.check_hostname = False - ctx.verify_mode = _stdlib_ssl.CERT_NONE - return {'connect_args': {'ssl': ctx}} + return {'connect_args': {'ssl': _make_ssl_context(ssl_params, verify=False)}} if mode in ('verify-ca', 'verify-full'): - # Full verification — use the system trust store. - ctx = _stdlib_ssl.create_default_context() + ctx = _make_ssl_context(ssl_params, verify=True) if mode == 'verify-ca': ctx.check_hostname = False return {'connect_args': {'ssl': ctx}} # Unknown value — pass through as-is and let asyncpg decide. - return {'connect_args': {'ssl': ssl_mode}} + return {'connect_args': {'ssl': ssl_params.mode}} -def reattach_ssl_mode_to_url(url_without_ssl: str, ssl_mode: str | None) -> str: - """Re-append ``sslmode=`` to a cleaned PostgreSQL URL. - - Used for psycopg2 / libpq consumers that expect the canonical - ``sslmode`` query-string key. - """ - if ssl_mode is None: - return url_without_ssl - separator = '&' if '?' in url_without_ssl else '?' - return f'{url_without_ssl}{separator}sslmode={ssl_mode}' +# Backwards-compatible aliases for external callers. +extract_ssl_mode_from_url = extract_ssl_params_from_url +reattach_ssl_mode_to_url = reattach_ssl_params_to_url class JSONField(types.TypeDecorator): @@ -150,9 +215,10 @@ class JSONField(types.TypeDecorator): def handle_peewee_migration(DATABASE_URL): db = None try: - # Normalize SSL params so psycopg2 always sees `sslmode=` (never `ssl=`). - url_without_ssl, ssl_mode = extract_ssl_mode_from_url(DATABASE_URL) - normalized_url = reattach_ssl_mode_to_url(url_without_ssl, ssl_mode) + # Normalize SSL params so psycopg2 always sees `sslmode=` (never `ssl=`) + # and cert-file params are preserved in the connection string. + url_without_ssl, ssl_params = extract_ssl_params_from_url(DATABASE_URL) + normalized_url = reattach_ssl_params_to_url(url_without_ssl, ssl_params) # Replace the postgresql:// with postgres:// to handle the peewee migration db = register_connection(normalized_url.replace('postgresql://', 'postgres://')) @@ -181,11 +247,11 @@ if ENABLE_DB_MIGRATIONS: # Normalize SSL params from the URL once; each engine branch re-injects # the driver-appropriate form. -DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE = extract_ssl_mode_from_url(DATABASE_URL) +DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_PARAMS = extract_ssl_params_from_url(DATABASE_URL) -# For psycopg2 (sync engine), re-append sslmode=. +# For psycopg2 (sync engine), re-append sslmode + cert-file params. SQLALCHEMY_DATABASE_URL = ( - reattach_ssl_mode_to_url(DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_MODE) if DATABASE_SSL_MODE else DATABASE_URL + reattach_ssl_params_to_url(DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_PARAMS) if DATABASE_SSL_PARAMS else DATABASE_URL ) @@ -331,7 +397,7 @@ get_db = contextmanager(get_session) # Use the SSL-stripped URL for asyncpg — SSL is injected via connect_args. ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url( - DATABASE_URL_WITHOUT_SSL if DATABASE_SSL_MODE else SQLALCHEMY_DATABASE_URL + DATABASE_URL_WITHOUT_SSL if DATABASE_SSL_PARAMS else SQLALCHEMY_DATABASE_URL ) if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: @@ -352,7 +418,7 @@ if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: else: # Inject asyncpg-compatible SSL connect_args when the user specified # sslmode/ssl in DATABASE_URL. - asyncpg_ssl_args = build_asyncpg_ssl_args(DATABASE_SSL_MODE) + asyncpg_ssl_args = build_asyncpg_ssl_args(DATABASE_SSL_PARAMS) if isinstance(DATABASE_POOL_SIZE, int): if DATABASE_POOL_SIZE > 0: diff --git a/backend/open_webui/migrations/env.py b/backend/open_webui/migrations/env.py index f5e57920ea..ea4839ebc1 100644 --- a/backend/open_webui/migrations/env.py +++ b/backend/open_webui/migrations/env.py @@ -5,7 +5,7 @@ from alembic import context from open_webui.models.auths import Auth from open_webui.models.calendar import Calendar, CalendarEvent, CalendarEventAttendee # noqa: F401 from open_webui.env import DATABASE_URL, DATABASE_PASSWORD, LOG_FORMAT -from open_webui.internal.db import extract_ssl_mode_from_url, reattach_ssl_mode_to_url +from open_webui.internal.db import extract_ssl_params_from_url, reattach_ssl_params_to_url from sqlalchemy import engine_from_config, pool, create_engine # this is the Alembic Config object, which provides @@ -38,8 +38,8 @@ target_metadata = Auth.metadata DB_URL = DATABASE_URL # Normalize SSL query params for psycopg2 (Alembic uses psycopg2, not asyncpg). -url_without_ssl, ssl_mode = extract_ssl_mode_from_url(DB_URL) -DB_URL = reattach_ssl_mode_to_url(url_without_ssl, ssl_mode) if ssl_mode else DB_URL +url_without_ssl, ssl_params = extract_ssl_params_from_url(DB_URL) +DB_URL = reattach_ssl_params_to_url(url_without_ssl, ssl_params) if ssl_params else DB_URL if DB_URL: config.set_main_option('sqlalchemy.url', DB_URL.replace('%', '%%')) diff --git a/backend/open_webui/models/oauth_sessions.py b/backend/open_webui/models/oauth_sessions.py index 050a50d486..fce18ae586 100644 --- a/backend/open_webui/models/oauth_sessions.py +++ b/backend/open_webui/models/oauth_sessions.py @@ -320,6 +320,21 @@ class OAuthSessionTable: log.error(f'Error deleting OAuth sessions by user ID: {e}') return False + async def delete_sessions_by_user_id_and_provider( + self, user_id: str, provider: str, db: Optional[AsyncSession] = None + ) -> bool: + """Delete all OAuth sessions for a specific user and provider""" + try: + async with get_async_db_context(db) as db: + result = await db.execute( + delete(OAuthSession).filter_by(user_id=user_id, provider=provider) + ) + await db.commit() + return result.rowcount > 0 + except Exception as e: + log.error(f'Error deleting OAuth sessions for user {user_id} and provider {provider}: {e}') + return False + async def delete_sessions_by_provider(self, provider: str, db: Optional[AsyncSession] = None) -> bool: """Delete all OAuth sessions for a provider""" try: diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 2a6f0f6dcd..7cb6ca3681 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -172,10 +172,17 @@ async def get_session_user( user=Depends(get_current_user), db: AsyncSession = Depends(get_async_session), ): + token = None auth_header = request.headers.get('Authorization') - auth_token = get_http_authorization_cred(auth_header) - token = auth_token.credentials - data = decode_token(token) + if auth_header: + auth_token = get_http_authorization_cred(auth_header) + if auth_token is not None: + token = auth_token.credentials + if token is None: + token = request.cookies.get('token') + if token is None and getattr(request.state, 'token', None): + token = request.state.token.credentials + data = decode_token(token) if token else None expires_at = None @@ -773,8 +780,9 @@ async def signout(request: Request, response: Response, db: AsyncSession = Depen auth_header = request.headers.get('Authorization') if auth_header: auth_cred = get_http_authorization_cred(auth_header) - token = auth_cred.credentials - else: + if auth_cred is not None: + token = auth_cred.credentials + if token is None: token = request.cookies.get('token') if token: @@ -853,6 +861,33 @@ async def signout(request: Request, response: Response, db: AsyncSession = Depen return JSONResponse(status_code=200, content={'status': True}, headers=response.headers) +############################ +# OAuth Session Management +############################ + + +@router.delete('/oauth/sessions/{provider:path}', response_model=bool) +async def delete_oauth_session_by_provider( + provider: str, + user=Depends(get_verified_user), + db: AsyncSession = Depends(get_async_session), +): + """ + Disconnect the current user's OAuth session for a specific provider. + The provider string matches the 'provider' field in the oauth_session table + (e.g. 'mcp:server-id' for MCP connections). + """ + result = await OAuthSessions.delete_sessions_by_user_id_and_provider( + user.id, provider, db=db + ) + if not result: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail='No OAuth session found for this provider', + ) + return True + + ############################ # AddUser ############################ diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index 04d845c3de..af5e795511 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -917,3 +917,4 @@ async def update_tools_user_valves_by_id( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND, ) + diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 9dec855e45..04be89c92f 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -550,6 +550,8 @@ async def update_user_by_id( detail=ERROR_MESSAGES.ACTION_PROHIBITED, ) + except HTTPException: + raise except Exception as e: log.error(f'Error checking primary admin status: {e}') raise HTTPException( @@ -631,6 +633,8 @@ async def delete_user_by_id(user_id: str, user=Depends(get_admin_user), db: Asyn status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACTION_PROHIBITED, ) + except HTTPException: + raise except Exception as e: log.error(f'Error checking primary admin status: {e}') raise HTTPException( diff --git a/src/lib/apis/auths/index.ts b/src/lib/apis/auths/index.ts index c501a36ed7..b8494ceedf 100644 --- a/src/lib/apis/auths/index.ts +++ b/src/lib/apis/auths/index.ts @@ -712,3 +712,33 @@ export const deleteAPIKey = async (token: string) => { } return res; }; + +export const deleteOAuthSession = async (token: string, provider: string) => { + let error = null; + + const res = await fetch( + `${WEBUI_API_BASE_URL}/auths/oauth/sessions/${encodeURIComponent(provider)}`, + { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + } + } + ) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .catch((err) => { + console.error(err); + error = err.detail; + return null; + }); + + if (error) { + throw error; + } + + return res; +}; diff --git a/src/lib/apis/configs/index.ts b/src/lib/apis/configs/index.ts index 6b7bf6f47b..b0dd6541ee 100644 --- a/src/lib/apis/configs/index.ts +++ b/src/lib/apis/configs/index.ts @@ -647,3 +647,4 @@ export const setBanners = async (token: string, banners: Banner[]) => { return res; }; + diff --git a/src/lib/apis/tools/index.ts b/src/lib/apis/tools/index.ts index 5d26e50fee..1d812b3f0f 100644 --- a/src/lib/apis/tools/index.ts +++ b/src/lib/apis/tools/index.ts @@ -483,3 +483,4 @@ export const updateUserValvesById = async (token: string, id: string, valves: ob return res; }; + diff --git a/src/lib/apis/users/index.ts b/src/lib/apis/users/index.ts index 91b63338de..13044c09d5 100644 --- a/src/lib/apis/users/index.ts +++ b/src/lib/apis/users/index.ts @@ -550,3 +550,4 @@ export const getUserGroupsById = async (token: string, userId: string) => { return res; }; + diff --git a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte index 3659122152..5d703e3113 100644 --- a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte +++ b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte @@ -13,8 +13,11 @@ } from '$lib/stores'; import { getOAuthClientAuthorizationUrl } from '$lib/apis/configs'; + import { deleteOAuthSession } from '$lib/apis/auths'; import { getTools } from '$lib/apis/tools'; + import { toast } from 'svelte-sonner'; + import Knobs from '$lib/components/icons/Knobs.svelte'; import Dropdown from '$lib/components/common/Dropdown.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte'; @@ -27,6 +30,7 @@ import Terminal from '$lib/components/icons/Terminal.svelte'; import ChevronRight from '$lib/components/icons/ChevronRight.svelte'; import ChevronLeft from '$lib/components/icons/ChevronLeft.svelte'; + import LinkSlash from '$lib/components/icons/LinkSlash.svelte'; const i18n = getContext('i18n'); @@ -375,6 +379,40 @@
+ {#if (tools[toolId]?.authenticated ?? true) && toolId.startsWith('server:mcp:')} +
+ + + +
+ {/if} + {#if tools[toolId]?.has_user_valves && ($user?.role === 'admin' || ($user?.permissions?.chat?.valves ?? true))}
diff --git a/static/pyodide/pyodide-lock.json b/static/pyodide/pyodide-lock.json index 138f33a8ff..440679ecbf 100644 --- a/static/pyodide/pyodide-lock.json +++ b/static/pyodide/pyodide-lock.json @@ -4987,10 +4987,10 @@ }, "pathspec": { "name": "pathspec", - "version": "1.0.4", - "file_name": "pathspec-1.0.4-py3-none-any.whl", + "version": "1.1.0", + "file_name": "pathspec-1.1.0-py3-none-any.whl", "install_dir": "site", - "sha256": "fb6ae2fd4e7c921a165808a552060e722767cfa526f99ca5156ed2ce45a5c723", + "sha256": "574b128f7456bd899045ccd142dd446af7e6cfd0072d63ad73fbc55fbb4aaa42", "package_type": "package", "imports": [ "pathspec" From d740b545a4b58a52dd3f7154fa637929e037ed54 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:21:37 +0900 Subject: [PATCH 379/404] refac --- src/lib/components/chat/MessageInput/IntegrationsMenu.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte index 5d703e3113..a62b3a2438 100644 --- a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte +++ b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte @@ -399,9 +399,8 @@ // Refresh tools to update authenticated state _tools.set(await getTools(localStorage.token)); - - // Remove from selected if it was selected selectedToolIds = selectedToolIds.filter((id) => id !== toolId); + await init(); } catch (err) { toast.error(err ?? $i18n.t('Failed to disconnect')); } From db05fdaf8366d327dbe33550aa917dea1f4c0e16 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:23:28 +0900 Subject: [PATCH 380/404] refac --- backend/open_webui/env.py | 6 ++++++ backend/open_webui/utils/asgi_middleware.py | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 26a8d376c5..e734a2f865 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -525,6 +525,12 @@ WEBUI_AUTH_TRUSTED_NAME_HEADER = os.environ.get('WEBUI_AUTH_TRUSTED_NAME_HEADER' WEBUI_AUTH_TRUSTED_GROUPS_HEADER = os.environ.get('WEBUI_AUTH_TRUSTED_GROUPS_HEADER', None) WEBUI_AUTH_TRUSTED_ROLE_HEADER = os.environ.get('WEBUI_AUTH_TRUSTED_ROLE_HEADER', None) +# Custom header name for API key authentication. Defaults to 'x-api-key'. +# Useful when Open WebUI sits behind a reverse proxy / API gateway that +# already uses the Authorization header for its own authentication — set +# this to a unique header (e.g. 'X-OpenWebUI-Key') so the middleware +# checks the custom header instead and avoids the 401 short-circuit. +CUSTOM_API_KEY_HEADER = os.environ.get('CUSTOM_API_KEY_HEADER', 'x-api-key') ENABLE_PASSWORD_VALIDATION = os.environ.get('ENABLE_PASSWORD_VALIDATION', 'False').lower() == 'true' PASSWORD_VALIDATION_REGEX_PATTERN = os.environ.get( diff --git a/backend/open_webui/utils/asgi_middleware.py b/backend/open_webui/utils/asgi_middleware.py index 05389d8f94..e3872dd231 100644 --- a/backend/open_webui/utils/asgi_middleware.py +++ b/backend/open_webui/utils/asgi_middleware.py @@ -41,6 +41,7 @@ from starlette.datastructures import MutableHeaders from starlette.requests import Request from starlette.types import ASGIApp, Message, Receive, Scope, Send +from open_webui.env import CUSTOM_API_KEY_HEADER from open_webui.internal.db import ScopedSession from open_webui.utils.auth import get_http_authorization_cred @@ -119,9 +120,16 @@ class CommitSessionMiddleware: class AuthTokenMiddleware: - """Extract the bearer/cookie/x-api-key credential and stash it on + """Extract the bearer/cookie/API-key credential and stash it on `request.state.token`. + The header used for API-key transport is controlled by the + ``CUSTOM_API_KEY_HEADER`` environment variable (default ``x-api-key``). + This is useful when Open WebUI sits behind a reverse proxy that + consumes the ``Authorization`` header for its own authentication — + set the env var to a unique header (e.g. ``X-OpenWebUI-Key``) so + the middleware checks that instead and avoids the 401 short-circuit. + Routes that depend on `get_verified_user` etc. read this state. Also exposes `request.state.enable_api_keys` (snapshotted at request entry from runtime config) and stamps an `X-Process-Time` response @@ -146,7 +154,7 @@ class AuthTokenMiddleware: if cookie_token: token = HTTPAuthorizationCredentials(scheme='Bearer', credentials=cookie_token) if token is None: - api_key = request.headers.get('x-api-key') + api_key = request.headers.get(CUSTOM_API_KEY_HEADER) if api_key: token = HTTPAuthorizationCredentials(scheme='Bearer', credentials=api_key) From 5774ab4984c0b32ebd30d2e64b764c9582ab17c2 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:26:34 +0900 Subject: [PATCH 381/404] refac --- backend/open_webui/utils/oauth.py | 74 +++++++++++++++++++------------ 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 47302e7535..4a7d79d87c 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -304,57 +304,67 @@ async def get_authorization_server_discovery_urls(server_url: str) -> list[str]: ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as response: if response.status == 401: + resource_metadata_urls = [] match = re.search( r'resource_metadata=(?:"([^"]+)"|([^\s,]+))', response.headers.get('WWW-Authenticate', ''), ) if match: - resource_metadata_url = match.group(1) or match.group(2) - log.debug(f'Found resource_metadata URL: {resource_metadata_url}') + resource_metadata_urls = [match.group(1) or match.group(2)] + log.debug(f'Found resource_metadata URL: {resource_metadata_urls[0]}') + else: + # Fall back to well-known resource metadata URIs (RFC 9728 §4.2) + parsed, base_url = get_parsed_and_base_url(server_url) + if parsed.path and parsed.path != '/': + path = parsed.path.rstrip('/') + resource_metadata_urls.append( + urllib.parse.urljoin(base_url, f'/.well-known/oauth-protected-resource{path}') + ) + resource_metadata_urls.append( + urllib.parse.urljoin(base_url, '/.well-known/oauth-protected-resource') + ) + log.debug(f'No resource_metadata in header, trying well-known URIs: {resource_metadata_urls}') - # Step 2: Fetch Protected Resource metadata - async with session.get( - resource_metadata_url, ssl=AIOHTTP_CLIENT_SESSION_SSL - ) as resource_response: - if resource_response.status == 200: - resource_metadata = await resource_response.json() + # Fetch Protected Resource metadata from candidate URLs + for resource_metadata_url in resource_metadata_urls: + try: + async with session.get( + resource_metadata_url, ssl=AIOHTTP_CLIENT_SESSION_SSL + ) as resource_response: + if resource_response.status == 200: + resource_metadata = await resource_response.json() - # Step 3: Extract authorization_servers - servers = resource_metadata.get('authorization_servers', []) - if servers: - authorization_servers = servers - log.debug(f'Discovered authorization servers: {servers}') + servers = resource_metadata.get('authorization_servers', []) + if servers: + authorization_servers = servers + log.debug(f'Discovered authorization servers: {servers}') + break + except Exception as e: + log.debug(f'Failed to fetch resource metadata from {resource_metadata_url}: {e}') + continue except Exception as e: log.debug(f'MCP Protected Resource discovery failed: {e}') discovery_urls = [] for auth_server in authorization_servers: auth_server = auth_server.rstrip('/') - discovery_urls.extend( - [ - f'{auth_server}/.well-known/oauth-authorization-server', - f'{auth_server}/.well-known/openid-configuration', - ] - ) + discovery_urls.extend(_build_well_known_urls(auth_server)) return discovery_urls -async def get_discovery_urls(server_url) -> list[str]: - urls = await get_authorization_server_discovery_urls(server_url) +def _build_well_known_urls(server_url: str) -> list[str]: + """Build RFC 8414 / OIDC Discovery well-known URLs for a server URL.""" parsed, base_url = get_parsed_and_base_url(server_url) + urls = [] if parsed.path and parsed.path != '/': - # Generate discovery URLs based on https://modelcontextprotocol.io/specification/draft/basic/authorization#authorization-server-metadata-discovery - tenant = parsed.path.rstrip('/') + path = parsed.path.rstrip('/') urls.extend( [ - urllib.parse.urljoin( - base_url, - f'/.well-known/oauth-authorization-server{tenant}', - ), - urllib.parse.urljoin(base_url, f'/.well-known/openid-configuration{tenant}'), - urllib.parse.urljoin(base_url, f'{tenant}/.well-known/openid-configuration'), + urllib.parse.urljoin(base_url, f'/.well-known/oauth-authorization-server{path}'), + urllib.parse.urljoin(base_url, f'/.well-known/openid-configuration{path}'), + urllib.parse.urljoin(base_url, f'{path}/.well-known/openid-configuration'), ] ) @@ -368,6 +378,12 @@ async def get_discovery_urls(server_url) -> list[str]: return urls +async def get_discovery_urls(server_url) -> list[str]: + urls = await get_authorization_server_discovery_urls(server_url) + urls.extend(_build_well_known_urls(server_url)) + return urls + + # TODO: Some OAuth providers require Initial Access Tokens (IATs) for dynamic client registration. # This is not currently supported. async def get_oauth_client_info_with_dynamic_client_registration( From d6b73ea2f2951a48e8a422e27fc6d3e53371cc17 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:31:02 +0900 Subject: [PATCH 382/404] refac --- backend/open_webui/utils/response.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/open_webui/utils/response.py b/backend/open_webui/utils/response.py index 641c79fca9..676a07525e 100644 --- a/backend/open_webui/utils/response.py +++ b/backend/open_webui/utils/response.py @@ -135,6 +135,9 @@ def convert_response_ollama_to_openai(ollama_response: dict) -> dict: async def convert_streaming_response_ollama_to_openai(ollama_streaming_response): has_tool_calls = False + # All chunks in a single completion must share the same id (OpenAI spec). + completion_id = f'chatcmpl-{str(uuid4())}' + first = True async for data in ollama_streaming_response.body_iterator: data = json.loads(data) @@ -155,6 +158,12 @@ async def convert_streaming_response_ollama_to_openai(ollama_streaming_response) usage = convert_ollama_usage_to_openai(data) data = openai_chat_chunk_message_template(model, message_content, reasoning_content, openai_tool_calls, usage) + data['id'] = completion_id + + # First chunk must carry delta.role (OpenAI spec). + if first: + data['choices'][0]['delta']['role'] = 'assistant' + first = False if done and has_tool_calls: data['choices'][0]['finish_reason'] = 'tool_calls' From 465d6fe5143fbebaef025e5595e71ac4e13c40b4 Mon Sep 17 00:00:00 2001 From: Jacob Leksan <63938553+jmleksan@users.noreply.github.com> Date: Fri, 24 Apr 2026 03:33:46 -0400 Subject: [PATCH 383/404] feat: enhance RichTextInput configuration to prevent duplicate extensions when rich text is enabled (#24009) --- src/lib/components/common/RichTextInput.svelte | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index 8c4006d280..99fa025055 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -737,6 +737,17 @@ StarterKit.configure({ link: link, code: false, // Disabled in favor of FixedCode (see workaround above) + // When rich text is on, ListKit + CodeBlockLowlight provide these. + // Disable StarterKit's equivalents to avoid duplicate extension names. + ...(richText + ? { + codeBlock: false, + bulletList: false, + orderedList: false, + listItem: false, + listKeymap: false + } + : {}), // When rich text is off, disable Strike from StarterKit so we can // re-add it below without its Mod-Shift-s shortcut (which conflicts // with the Toggle Sidebar shortcut). When rich text is on, the user From 62693938a3ae993716cad3fd409ec985e329bc86 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:36:07 +0900 Subject: [PATCH 384/404] refac --- backend/open_webui/utils/mcp/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/open_webui/utils/mcp/client.py b/backend/open_webui/utils/mcp/client.py index 759bcc0a31..205b5a0b5a 100644 --- a/backend/open_webui/utils/mcp/client.py +++ b/backend/open_webui/utils/mcp/client.py @@ -44,7 +44,7 @@ def create_httpx_client(headers=None, timeout=None, auth=None): return _build_httpx_client(headers=headers, timeout=timeout, auth=auth, verify=True) -async def create_insecure_httpx_client(headers=None, timeout=None, auth=None): +def create_insecure_httpx_client(headers=None, timeout=None, auth=None): return _build_httpx_client(headers=headers, timeout=timeout, auth=auth, verify=False) From d8b55afb00ee308bdfd482e39728e1401d2f2911 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:37:02 +0900 Subject: [PATCH 385/404] refac --- backend/open_webui/utils/middleware.py | 44 +++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 813ced0466..3fd4d011df 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2180,6 +2180,43 @@ def process_messages_with_output(messages: list[dict]) -> list[dict]: return processed +SKILL_MENTION_RE = re.compile(r'<\$([^|>]+)\|?[^>]*>') + + +def _get_text_parts(message: dict) -> list[str]: + """Return all text segments from a message's content.""" + content = message.get('content') + if isinstance(content, str): + return [content] + if isinstance(content, list): + return [p.get('text', '') for p in content if isinstance(p, dict) and p.get('type') == 'text'] + return [] + + +def extract_skill_ids_from_messages(messages: list[dict]) -> set[str]: + """Extract skill IDs from <$skillId|label> mention tags in messages.""" + ids: set[str] = set() + for message in messages: + for text in _get_text_parts(message): + ids.update(m.group(1) for m in SKILL_MENTION_RE.finditer(text)) + return ids + + +def strip_skill_mentions(messages: list[dict]) -> None: + """Strip <$skillId|label> mention tags from message content in-place.""" + strip_re = re.compile(r'<\$[^>]+>') + for message in messages: + content = message.get('content') + if isinstance(content, str) and strip_re.search(content): + message['content'] = strip_re.sub('', content).strip() + elif isinstance(content, list): + for part in content: + if isinstance(part, dict) and part.get('type') == 'text': + text = part.get('text', '') + if strip_re.search(text): + part['text'] = strip_re.sub('', text).strip() + + async def process_chat_payload(request, form_data, user, metadata, model): # Pipeline Inlet -> Filter Inlet -> Chat Memory -> Chat Web Search -> Chat Image Generation # -> Chat Code Interpreter (Form Data Update) -> (Default) Chat Tools Function Calling @@ -2465,8 +2502,10 @@ async def process_chat_payload(request, form_data, user, metadata, model): # tool resolution (tool_ids, MCP servers, builtin tools). payload_tools = form_data.get('tools', None) - # Skills + # Skills — extract IDs from message content (<$skillId|label> tags) so + # persisted chats work without relying on the frontend to send skill_ids. user_skill_ids = set(form_data.pop('skill_ids', None) or []) + user_skill_ids |= extract_skill_ids_from_messages(form_data.get('messages', [])) model_skill_ids = set(model.get('info', {}).get('meta', {}).get('skillIds', [])) all_skill_ids = user_skill_ids | model_skill_ids @@ -2502,6 +2541,9 @@ async def process_chat_payload(request, form_data, user, metadata, model): append=True, ) + # Strip <$skillId|label> mention tags so the model doesn't see raw markup. + strip_skill_mentions(form_data.get('messages', [])) + prompt = get_last_user_message(form_data['messages']) # TODO: re-enable URL extraction from prompt # urls = [] From 3e14524154c7eb1a53d015d67eab4cb199cbe511 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:39:44 +0900 Subject: [PATCH 386/404] refac --- src/routes/+layout.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 0dc8170eef..01d9c10b65 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -489,7 +489,7 @@ const displayTitle = title || $i18n.t('New Chat'); if (done) { - if ($settings?.notificationSoundAlways ?? false) { + if (($settings?.notificationSound ?? true) && ($settings?.notificationSoundAlways ?? false)) { playingNotificationSound.set(true); const audio = new Audio(`/audio/notification.mp3`); From 752238247c251cd0bd974b25beee69112939b101 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 16:47:30 +0900 Subject: [PATCH 387/404] refac --- backend/requirements.txt | 1 + pyproject.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/requirements.txt b/backend/requirements.txt index 3437ab7652..539835dd22 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -19,6 +19,7 @@ aiocache==0.12.3 aiofiles==25.1.0 starlette-compress==1.7.0 Brotli==1.2.0 +brotlicffi==1.2.0.1 httpx[socks,http2,zstd,cli,brotli]==0.28.1 starsessions[redis]==2.2.1 python-mimeparse==2.0.0 diff --git a/pyproject.toml b/pyproject.toml index 3d458de753..2a802637a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ dependencies = [ "aiofiles==25.1.0", "starlette-compress==1.7.0", "Brotli==1.2.0", + "brotlicffi==1.2.0.1", "httpx[socks,http2,zstd,cli,brotli]==0.28.1", "starsessions[redis]==2.2.1", "python-mimeparse==2.0.0", From 9771898c5886850be0696d4d09a1f85afa55de5c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 17:04:47 +0900 Subject: [PATCH 388/404] refac --- backend/open_webui/main.py | 23 ++++++++++++++++++----- backend/open_webui/utils/mcp/client.py | 16 ++++++++-------- backend/requirements-min.txt | 1 + 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 2299ef84c4..9bc6b5177d 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1923,8 +1923,6 @@ async def chat_completion( # uses anyio task groups whose cancel scopes enforce # same-task exit. Do NOT wrap in asyncio.shield() or # asyncio.wait_for() — both create a new task. - # MCPClient.disconnect() self-shields via - # anyio.CancelScope(shield=True). try: if mcp_clients := metadata.get('mcp_clients'): for client in reversed(list(mcp_clients.values())): @@ -1932,14 +1930,29 @@ async def chat_completion( await client.disconnect() except Exception as e: log.debug(f'Error disconnecting MCP client: {e}') + except asyncio.CancelledError: + # Let the client close asynchronously by GC + pass except Exception as e: log.debug(f'Error cleaning up MCP clients: {e}') + except asyncio.CancelledError: + pass try: if metadata.get('chat_id'): - event_emitter = await get_event_emitter(metadata, update_db=False) - if event_emitter: - await event_emitter({'type': 'chat:active', 'data': {'active': False}}) + async def emit_inactive_event(): + try: + event_emitter = await get_event_emitter(metadata, update_db=False) + if event_emitter: + await event_emitter({'type': 'chat:active', 'data': {'active': False}}) + except Exception: + pass + + try: + # Shield the event emission so it finishes even if the main task is cancelled + await asyncio.shield(emit_inactive_event()) + except asyncio.CancelledError: + pass except Exception: pass diff --git a/backend/open_webui/utils/mcp/client.py b/backend/open_webui/utils/mcp/client.py index 205b5a0b5a..7a5aa61b80 100644 --- a/backend/open_webui/utils/mcp/client.py +++ b/backend/open_webui/utils/mcp/client.py @@ -156,14 +156,14 @@ class MCPClient: try: # IMPORTANT: Do NOT use asyncio.shield() or asyncio.wait_for() - # here — both create a new asyncio task. The MCP SDK's - # streamablehttp_client uses anyio task groups / cancel scopes - # that MUST be exited in the same task they were entered in. - # Using anyio.CancelScope(shield=True) protects from - # CancelledError while staying in the current task. - with anyio.CancelScope(shield=True): - with anyio.fail_after(5.0): - await exit_stack.aclose() + # because they create a new asyncio task, which violates the MCP SDK's + # requirement that its TaskGroup be exited in the exact same task. + # ALSO do NOT use anyio.CancelScope(shield=True) or anyio.fail_after(), + # because they push a new cancel scope onto the task, violating LIFO + # order when aclose() attempts to exit the inner TaskGroup. + # We simply call aclose() directly. If the task is cancelled, the + # sockets will eventually be cleaned up by garbage collection. + await exit_stack.aclose() except TimeoutError: log.warning('MCPClient.disconnect() timed out after 5 s') except RuntimeError as exc: diff --git a/backend/requirements-min.txt b/backend/requirements-min.txt index b7dfd69ffd..950a458c8f 100644 --- a/backend/requirements-min.txt +++ b/backend/requirements-min.txt @@ -22,6 +22,7 @@ aiocache aiofiles starlette-compress==1.7.0 Brotli==1.2.0 +brotlicffi==1.2.0.1 httpx[socks,http2,zstd,cli,brotli]==0.28.1 starsessions[redis]==2.2.1 From 34a55d45247628ca954a3506fc24e5160d3e2c7b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 17:06:36 +0900 Subject: [PATCH 389/404] refac --- src/lib/components/chat/ContentRenderer/FloatingButtons.svelte | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte index 8f0a8f7ec6..d8057acc96 100644 --- a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte +++ b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte @@ -120,8 +120,6 @@ [res, controller] = await chatCompletion(localStorage.token, { model: model, model_item: $models.find((m) => m.id === model), - session_id: $socket?.id, - chat_id: $chatId, messages: [ ...messages, { From 60f67c7c17e65d0989a4bc3f1eb283feeddb76ad Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 17:07:23 +0900 Subject: [PATCH 390/404] refac --- backend/open_webui/retrieval/loaders/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/retrieval/loaders/main.py b/backend/open_webui/retrieval/loaders/main.py index 27c81f7f81..7a115ca6d7 100644 --- a/backend/open_webui/retrieval/loaders/main.py +++ b/backend/open_webui/retrieval/loaders/main.py @@ -25,7 +25,7 @@ from open_webui.retrieval.loaders.datalab_marker import DatalabMarkerLoader from open_webui.retrieval.loaders.mineru import MinerULoader from open_webui.retrieval.loaders.paddleocr_vl import PaddleOCRVLLoader -from open_webui.env import GLOBAL_LOG_LEVEL, REQUESTS_VERIFY +from open_webui.env import GLOBAL_LOG_LEVEL, REQUESTS_VERIFY, AIOHTTP_CLIENT_SESSION_SSL logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) log = logging.getLogger(__name__) @@ -205,6 +205,7 @@ class DoclingLoader: **self.params, }, headers=headers, + verify=AIOHTTP_CLIENT_SESSION_SSL, ) if r.ok: result = r.json() From 2419899ac663f2fb2e2a44c16ad94581a2a087b8 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 17:34:12 +0900 Subject: [PATCH 391/404] refac --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index d5c40f15e9..88ffd09752 100644 --- a/Dockerfile +++ b/Dockerfile @@ -135,6 +135,9 @@ RUN apt-get update && \ # install python dependencies COPY --chown=$UID:$GID ./backend/requirements.txt ./requirements.txt +# Set UV_LINK_MODE to copy to prevent 0-byte file corruption in QEMU arm64 cross-builds +ENV UV_LINK_MODE=copy + RUN set -e; \ pip3 install --no-cache-dir uv; \ if [ "$USE_CUDA" = "true" ]; then \ From a7a92d2d9b33234e7e5a92429151dbf195dd72d1 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 17:49:22 +0900 Subject: [PATCH 392/404] refac --- backend/open_webui/models/models.py | 2 ++ src/lib/apis/models/index.ts | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/models/models.py b/backend/open_webui/models/models.py index 9bd3f888c1..71296b295e 100755 --- a/backend/open_webui/models/models.py +++ b/backend/open_webui/models/models.py @@ -143,6 +143,8 @@ class ModelAccessListResponse(BaseModel): class ModelForm(BaseModel): + model_config = ConfigDict(extra='ignore') + id: str base_model_id: Optional[str] = None name: str diff --git a/src/lib/apis/models/index.ts b/src/lib/apis/models/index.ts index 05f273c306..e7abaa309e 100644 --- a/src/lib/apis/models/index.ts +++ b/src/lib/apis/models/index.ts @@ -152,6 +152,9 @@ export const getBaseModels = async (token: string = '') => { export const createNewModel = async (token: string, model: object) => { let error = null; + const { id, base_model_id, name, meta, params, access_grants, is_active } = model as any; + const payload = { id, base_model_id, name, meta, params, access_grants, is_active }; + const res = await fetch(`${WEBUI_API_BASE_URL}/models/create`, { method: 'POST', headers: { @@ -159,7 +162,7 @@ export const createNewModel = async (token: string, model: object) => { 'Content-Type': 'application/json', authorization: `Bearer ${token}` }, - body: JSON.stringify(model) + body: JSON.stringify(payload) }) .then(async (res) => { if (!res.ok) throw await res.json(); @@ -251,6 +254,9 @@ export const toggleModelById = async (token: string, id: string) => { export const updateModelById = async (token: string, id: string, model: object) => { let error = null; + const { base_model_id, name, meta, params, access_grants, is_active } = model as any; + const payload = { id, base_model_id, name, meta, params, access_grants, is_active }; + const res = await fetch(`${WEBUI_API_BASE_URL}/models/model/update`, { method: 'POST', headers: { @@ -258,7 +264,7 @@ export const updateModelById = async (token: string, id: string, model: object) 'Content-Type': 'application/json', authorization: `Bearer ${token}` }, - body: JSON.stringify({ ...model, id }) + body: JSON.stringify(payload) }) .then(async (res) => { if (!res.ok) throw await res.json(); From 1cea8ec7d462d1542e04e15dac48ecbc3cb66d2a Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 17:59:45 +0900 Subject: [PATCH 393/404] refac --- backend/open_webui/retrieval/utils.py | 7 +++++++ backend/open_webui/tools/builtin.py | 10 +++++++--- backend/open_webui/utils/middleware.py | 6 +++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index b1aec78656..14a64fed60 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -566,6 +566,13 @@ async def query_collection( log.exception(f'Error when querying the collection: {e}') return None, e + # Sanitize: filter out None/empty queries to prevent embedding crashes + # (e.g. when get_last_user_message returns None) + queries = [q for q in queries if q] + if not queries: + log.warning('query_collection: all queries were None or empty, returning empty results') + return {'distances': [[]], 'documents': [[]], 'metadatas': [[]]} + # Generate all query embeddings (in one call) query_embeddings = await embedding_function(queries, prefix=RAG_EMBEDDING_QUERY_PREFIX) log.debug(f'query_collection: processing {len(queries)} queries across {len(collection_names)} collections') diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 25d6a2cecb..33d6bfa91e 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -238,9 +238,13 @@ async def fetch_url( content, _ = await asyncio.to_thread(get_content_from_url, __request__, url) # Truncate if configured (WEB_FETCH_MAX_CONTENT_LENGTH) - max_length = getattr(__request__.app.state.config, 'WEB_FETCH_MAX_CONTENT_LENGTH', None) - if max_length and max_length > 0 and len(content) > max_length: - content = content[:max_length] + '\n\n[Content truncated...]' + # Guard: content may be None if the web loader silently failed + if content is not None: + max_length = getattr(__request__.app.state.config, 'WEB_FETCH_MAX_CONTENT_LENGTH', None) + if max_length and max_length > 0 and len(content) > max_length: + content = content[:max_length] + '\n\n[Content truncated...]' + else: + content = '' return content except Exception as e: diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 3fd4d011df..ab2ca104f4 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1546,11 +1546,11 @@ async def chat_web_search_handler(request: Request, form_data: dict, extra_param except Exception as e: log.exception(e) - queries = [user_message] + queries = [user_message or ''] # Check if generated queries are empty if len(queries) == 1 and queries[0].strip() == '': - queries = [user_message] + queries = [user_message or ''] # Check if queries are not found if len(queries) == 0: @@ -1991,7 +1991,7 @@ async def chat_completion_files_handler( ) if len(queries) == 0: - queries = [get_last_user_message(body['messages'])] + queries = [get_last_user_message(body['messages']) or ''] try: # Directly await async get_sources_from_items (no thread needed - fully async now) From 7102a63c82c7d916acaaaaff2eee653de3c1bd69 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:06:19 +0900 Subject: [PATCH 394/404] refac --- backend/open_webui/tools/builtin.py | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 33d6bfa91e..18b888bbd7 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2895,6 +2895,9 @@ def _ns_to_dt(ns: int, tz) -> str: def _event_to_dict(event, tz) -> dict: """Convert a calendar event model to a human-friendly dict with local timestamps.""" + alert_minutes = None + if event.meta and 'alert_minutes' in event.meta: + alert_minutes = event.meta['alert_minutes'] return { 'id': event.id, 'calendar_id': event.calendar_id, @@ -2904,6 +2907,7 @@ def _event_to_dict(event, tz) -> dict: 'end': _ns_to_dt(event.end_at, tz) if event.end_at else None, 'all_day': event.all_day, 'location': event.location or '', + 'reminder_minutes': alert_minutes if alert_minutes is not None else 10, 'color': event.color, 'is_cancelled': event.is_cancelled, } @@ -3010,6 +3014,7 @@ async def create_calendar_event( calendar_id: Optional[str] = None, all_day: bool = False, location: Optional[str] = None, + reminder_minutes: Optional[int] = None, __request__: Request = None, __user__: dict = None, ) -> str: @@ -3024,6 +3029,7 @@ async def create_calendar_event( :param calendar_id: Target calendar ID (optional, uses default calendar if omitted) :param all_day: Whether this is an all-day event (default: false) :param location: Event location (optional) + :param reminder_minutes: Minutes before the event to send a reminder notification (optional, default: 10). Use 0 for "at time of event", -1 for no reminder. Accepts any positive integer for custom timing (e.g. 120 for 2 hours before). :return: JSON with the created event details including id """ if __request__ is None: @@ -3086,6 +3092,18 @@ async def create_calendar_event( # Default to 1 hour duration end_ns = start_ns + 3_600_000_000_000 + # Build meta with reminder setting + meta = {} + if reminder_minutes is not None: + if isinstance(reminder_minutes, str): + try: + reminder_minutes = int(reminder_minutes) + except ValueError: + reminder_minutes = 10 + meta['alert_minutes'] = reminder_minutes + else: + meta['alert_minutes'] = 10 + form = CalendarEventForm( calendar_id=calendar_id, title=title, @@ -3094,6 +3112,7 @@ async def create_calendar_event( end_at=end_ns, all_day=all_day, location=location, + meta=meta, ) event = await CalendarEvents.insert_new_event(user_id, form) @@ -3121,6 +3140,7 @@ async def update_calendar_event( all_day: Optional[bool] = None, location: Optional[str] = None, is_cancelled: Optional[bool] = None, + reminder_minutes: Optional[int] = None, __request__: Request = None, __user__: dict = None, ) -> str: @@ -3136,6 +3156,7 @@ async def update_calendar_event( :param all_day: Whether this is an all-day event (optional) :param location: New event location (optional) :param is_cancelled: Set to true to cancel the event (optional) + :param reminder_minutes: Minutes before the event to send a reminder notification (optional). Use 0 for "at time of event", -1 for no reminder. Accepts any positive integer for custom timing (e.g. 120 for 2 hours before). :return: JSON with the updated event details """ if __request__ is None: @@ -3190,6 +3211,17 @@ async def update_calendar_event( except (ValueError, TypeError) as e: return json.dumps({'error': f'Invalid end datetime: {e}'}) + # Build meta update with reminder setting if provided + meta = None + if reminder_minutes is not None: + if isinstance(reminder_minutes, str): + try: + reminder_minutes = int(reminder_minutes) + except ValueError: + reminder_minutes = None + if reminder_minutes is not None: + meta = {'alert_minutes': reminder_minutes} + form = CalendarEventUpdateForm( title=title, description=description, @@ -3198,6 +3230,7 @@ async def update_calendar_event( all_day=all_day, location=location, is_cancelled=is_cancelled, + meta=meta, ) updated = await CalendarEvents.update_event_by_id(event_id, form) From 3d1e355df722c34158e7a59190d1b054d391b262 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:20:10 +0900 Subject: [PATCH 395/404] refac --- backend/open_webui/internal/db.py | 191 +++------- backend/open_webui/migrations/env.py | 2 +- backend/open_webui/models/models.py | 50 +++ backend/open_webui/routers/models.py | 82 ++--- backend/open_webui/utils/filter.py | 2 +- backend/open_webui/utils/models.py | 4 +- backend/open_webui/utils/plugin.py | 7 +- backend/requirements-min.txt | 2 +- backend/requirements.txt | 2 +- pyproject.toml | 2 +- .../ContentRenderer/FloatingButtons.svelte | 341 ++++-------------- .../chat/Messages/ContentRenderer.svelte | 42 ++- .../chat/Messages/ResponseMessage.svelte | 7 +- src/lib/components/workspace/Models.svelte | 2 + 14 files changed, 258 insertions(+), 478 deletions(-) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index 3a4a22c55d..4592aa6cb8 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -1,9 +1,7 @@ import os import json import logging -import ssl as _stdlib_ssl from contextlib import asynccontextmanager, contextmanager -from dataclasses import dataclass from typing import Any, Optional from urllib.parse import parse_qs, urlencode, urlparse, urlunparse @@ -38,31 +36,17 @@ from typing_extensions import Self log = logging.getLogger(__name__) -@dataclass -class SSLParams: - """SSL parameters extracted from a PostgreSQL ``DATABASE_URL``. - - Holds the connection-mode flag and optional certificate file paths - so that each driver (asyncpg, psycopg2/libpq) can receive them in - the format it expects. - """ - - mode: str | None = None - rootcert: str | None = None - cert: str | None = None - key: str | None = None - crl: str | None = None - - def __bool__(self) -> bool: - return self.mode is not None - - @property - def has_any(self) -> bool: - """True when *any* SSL-related field is set (mode or cert files).""" - return any((self.mode, self.rootcert, self.cert, self.key, self.crl)) - - -# ── URL extraction / reattachment ──────────────────────────────────── +# ── SSL URL normalization (used by sync engine & Alembic migrations) ─ +# +# psycopg2 (sync) needs ``sslmode=`` in the connection string (it does +# not recognise the bare ``ssl=`` key that some ORMs emit). The helpers +# below strip all SSL-related query params, normalise them, and +# reattach them in the canonical libpq form. +# +# The **async** engine now uses psycopg (v3), which speaks libpq +# natively, so it needs no translation at all — the DATABASE_URL is +# passed through as-is. +# ───────────────────────────────────────────────────────────────────── def _pop_first(params: dict[str, list[str]], key: str) -> str | None: @@ -71,63 +55,57 @@ def _pop_first(params: dict[str, list[str]], key: str) -> str | None: return values[0] if values else None -def extract_ssl_params_from_url(url: str) -> tuple[str, SSLParams]: - """Strip all SSL query-string parameters from a PostgreSQL URL. - - asyncpg does not accept libpq-style certificate-file keys - (``sslrootcert``, ``sslcert``, ``sslkey``, ``sslcrl``), so every - SSL-related key is removed and returned as a structured - :class:`SSLParams` object. - - Returns ``(url_without_ssl, ssl_params)``. Non-PostgreSQL URLs are - returned unchanged with an empty ``SSLParams``. - """ - if not url or not any( +def _is_postgres_url(url: str) -> bool: + """Return True if *url* looks like a PostgreSQL connection string.""" + return bool(url) and any( url.startswith(p) for p in ('postgresql://', 'postgresql+', 'postgres://') - ): - return url, SSLParams() + ) + + +def extract_ssl_params_from_url(url: str) -> tuple[str, dict[str, str]]: + """Strip SSL query-string parameters from a PostgreSQL URL. + + Returns ``(url_without_ssl, ssl_dict)`` where *ssl_dict* maps + canonical libpq key names (``sslmode``, ``sslrootcert``, …) to + their values. Non-PostgreSQL URLs are returned unchanged with an + empty dict. + """ + if not _is_postgres_url(url): + return url, {} parsed = urlparse(url) qp = parse_qs(parsed.query, keep_blank_values=True) - # Prefer sslmode (libpq canonical) over the asyncpg-only ``ssl`` key. - # Both must be popped unconditionally so neither leaks into the cleaned URL. + # Prefer sslmode (libpq canonical) over the bare ``ssl`` key. sslmode_val = _pop_first(qp, 'sslmode') ssl_val = _pop_first(qp, 'ssl') ssl_mode = sslmode_val or ssl_val - params = SSLParams( - mode=ssl_mode, - rootcert=_pop_first(qp, 'sslrootcert'), - cert=_pop_first(qp, 'sslcert'), - key=_pop_first(qp, 'sslkey'), - crl=_pop_first(qp, 'sslcrl'), - ) + ssl_dict: dict[str, str] = {} + if ssl_mode: + ssl_dict['sslmode'] = ssl_mode + for key in ('sslrootcert', 'sslcert', 'sslkey', 'sslcrl'): + val = _pop_first(qp, key) + if val: + ssl_dict[key] = val - if not params.has_any: - return url, params + if not ssl_dict: + return url, ssl_dict cleaned_query = urlencode(qp, doseq=True) - return urlunparse(parsed._replace(query=cleaned_query)), params + return urlunparse(parsed._replace(query=cleaned_query)), ssl_dict -def reattach_ssl_params_to_url(url_without_ssl: str, ssl_params: SSLParams) -> str: +def reattach_ssl_params_to_url(url_without_ssl: str, ssl_dict: dict[str, str]) -> str: """Re-append SSL query-string parameters to a cleaned PostgreSQL URL. Used for psycopg2/libpq consumers that expect ``sslmode`` and the certificate-file keys in the connection string. """ - if not ssl_params: + if not ssl_dict: return url_without_ssl - mapping = ( - ('sslmode', ssl_params.mode), - ('sslrootcert', ssl_params.rootcert), - ('sslcert', ssl_params.cert), - ('sslkey', ssl_params.key), - ('sslcrl', ssl_params.crl), - ) - parts = [f'{k}={v}' for k, v in mapping if v] + parts = [f'{k}={v}' for k, v in ssl_dict.items() if v] if not parts: return url_without_ssl @@ -135,54 +113,6 @@ def reattach_ssl_params_to_url(url_without_ssl: str, ssl_params: SSLParams) -> s return f'{url_without_ssl}{sep}{"&".join(parts)}' -# ── asyncpg SSLContext builder ─────────────────────────────────────── - - -def _make_ssl_context(ssl_params: SSLParams, *, verify: bool) -> _stdlib_ssl.SSLContext: - """Create an :class:`ssl.SSLContext` from *ssl_params*. - - When *verify* is ``False``, hostname checking and certificate - verification are disabled (matching libpq ``require`` semantics). - """ - ctx = _stdlib_ssl.create_default_context(cafile=ssl_params.rootcert) - if not verify: - ctx.check_hostname = False - ctx.verify_mode = _stdlib_ssl.CERT_NONE - if ssl_params.cert and ssl_params.key: - ctx.load_cert_chain(certfile=ssl_params.cert, keyfile=ssl_params.key) - if verify and ssl_params.crl: - ctx.load_verify_locations(cafile=ssl_params.crl) - ctx.verify_flags |= _stdlib_ssl.VERIFY_CRL_CHECK_LEAF - return ctx - - -def build_asyncpg_ssl_args(ssl_params: SSLParams) -> dict: - """Convert :class:`SSLParams` to asyncpg-compatible ``connect_args``. - - Returns a dict suitable for unpacking into - ``create_async_engine(...)``. - """ - if not ssl_params: - return {} - - mode = (ssl_params.mode or 'require').lower() - - if mode == 'disable': - return {'connect_args': {'ssl': False}} - if mode in ('allow', 'prefer'): - return {} - if mode == 'require': - return {'connect_args': {'ssl': _make_ssl_context(ssl_params, verify=False)}} - if mode in ('verify-ca', 'verify-full'): - ctx = _make_ssl_context(ssl_params, verify=True) - if mode == 'verify-ca': - ctx.check_hostname = False - return {'connect_args': {'ssl': ctx}} - - # Unknown value — pass through as-is and let asyncpg decide. - return {'connect_args': {'ssl': ssl_params.mode}} - - # Backwards-compatible aliases for external callers. extract_ssl_mode_from_url = extract_ssl_params_from_url reattach_ssl_mode_to_url = reattach_ssl_params_to_url @@ -245,32 +175,38 @@ if ENABLE_DB_MIGRATIONS: handle_peewee_migration(DATABASE_URL) -# Normalize SSL params from the URL once; each engine branch re-injects -# the driver-appropriate form. -DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_PARAMS = extract_ssl_params_from_url(DATABASE_URL) +# Normalize SSL params from the URL once; the sync engine needs them +# reattached in canonical libpq form for psycopg2. +_url_without_ssl, _ssl_dict = extract_ssl_params_from_url(DATABASE_URL) # For psycopg2 (sync engine), re-append sslmode + cert-file params. SQLALCHEMY_DATABASE_URL = ( - reattach_ssl_params_to_url(DATABASE_URL_WITHOUT_SSL, DATABASE_SSL_PARAMS) if DATABASE_SSL_PARAMS else DATABASE_URL + reattach_ssl_params_to_url(_url_without_ssl, _ssl_dict) if _ssl_dict else DATABASE_URL ) def _make_async_url(url: str) -> str: - """Convert a sync database URL to its async driver equivalent.""" + """Convert a sync database URL to its async driver equivalent. + + The async engine uses psycopg (v3) which speaks libpq natively, + so all standard connection-string parameters (``sslmode``, + ``options``, ``target_session_attrs``, etc.) are passed through + without any translation. + """ if url.startswith('sqlite+sqlcipher://'): - # SQLCipher has no async driver — not supported for async raise ValueError( 'sqlite+sqlcipher:// URLs are not supported with async engine. ' 'Use standard sqlite:// or postgresql:// instead.' ) if url.startswith('sqlite:///') or url.startswith('sqlite://'): return url.replace('sqlite://', 'sqlite+aiosqlite://', 1) + # psycopg v3 — auto-selects async mode with create_async_engine if url.startswith('postgresql+psycopg2://'): - return url.replace('postgresql+psycopg2://', 'postgresql+asyncpg://', 1) + return url.replace('postgresql+psycopg2://', 'postgresql+psycopg://', 1) if url.startswith('postgresql://'): - return url.replace('postgresql://', 'postgresql+asyncpg://', 1) + return url.replace('postgresql://', 'postgresql+psycopg://', 1) if url.startswith('postgres://'): - return url.replace('postgres://', 'postgresql+asyncpg://', 1) + return url.replace('postgres://', 'postgresql+psycopg://', 1) # For other dialects, return as-is and let SQLAlchemy handle it return url @@ -395,10 +331,10 @@ get_db = contextmanager(get_session) # ASYNC ENGINE (used for ALL runtime database operations) # ============================================================ -# Use the SSL-stripped URL for asyncpg — SSL is injected via connect_args. -ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url( - DATABASE_URL_WITHOUT_SSL if DATABASE_SSL_PARAMS else SQLALCHEMY_DATABASE_URL -) +# psycopg (v3) speaks libpq natively — the full DATABASE_URL is passed +# through as-is. SSL params, ``options``, ``target_session_attrs``, etc. +# all work without any stripping or translation. +ASYNC_SQLALCHEMY_DATABASE_URL = _make_async_url(SQLALCHEMY_DATABASE_URL) if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: # Generous default — async coroutines + no session sharing = high connection demand. @@ -416,10 +352,6 @@ if 'sqlite' in ASYNC_SQLALCHEMY_DATABASE_URL: def _set_sqlite_pragmas(dbapi_connection, connection_record): _apply_sqlite_pragmas(dbapi_connection) else: - # Inject asyncpg-compatible SSL connect_args when the user specified - # sslmode/ssl in DATABASE_URL. - asyncpg_ssl_args = build_asyncpg_ssl_args(DATABASE_SSL_PARAMS) - if isinstance(DATABASE_POOL_SIZE, int): if DATABASE_POOL_SIZE > 0: async_engine = create_async_engine( @@ -429,20 +361,17 @@ else: pool_timeout=DATABASE_POOL_TIMEOUT, pool_recycle=DATABASE_POOL_RECYCLE, pool_pre_ping=True, - **asyncpg_ssl_args, ) else: async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, poolclass=NullPool, - **asyncpg_ssl_args, ) else: async_engine = create_async_engine( ASYNC_SQLALCHEMY_DATABASE_URL, pool_pre_ping=True, - **asyncpg_ssl_args, ) diff --git a/backend/open_webui/migrations/env.py b/backend/open_webui/migrations/env.py index ea4839ebc1..961a92becf 100644 --- a/backend/open_webui/migrations/env.py +++ b/backend/open_webui/migrations/env.py @@ -37,7 +37,7 @@ target_metadata = Auth.metadata DB_URL = DATABASE_URL -# Normalize SSL query params for psycopg2 (Alembic uses psycopg2, not asyncpg). +# Normalize SSL query params for psycopg2 (Alembic uses psycopg2 for sync migrations). url_without_ssl, ssl_params = extract_ssl_params_from_url(DB_URL) DB_URL = reattach_ssl_params_to_url(url_without_ssl, ssl_params) if ssl_params else DB_URL diff --git a/backend/open_webui/models/models.py b/backend/open_webui/models/models.py index 71296b295e..db9459e028 100755 --- a/backend/open_webui/models/models.py +++ b/backend/open_webui/models/models.py @@ -391,6 +391,56 @@ class ModelsTable: return ModelListResponse(items=models, total=total) + async def get_model_meta_by_id( + self, id: str, db: Optional[AsyncSession] = None + ) -> Optional[tuple[dict, int]]: + """Return (meta, updated_at) for a model, skipping access grant resolution.""" + try: + async with get_async_db_context(db) as db: + result = await db.execute( + select(Model.meta, Model.updated_at).filter_by(id=id) + ) + return result.first() + except Exception: + return None + + async def get_all_tags( + self, + user_id: str, + is_admin: bool = False, + db: Optional[AsyncSession] = None, + ) -> set[str]: + """Extract unique tag names from model meta, querying only the meta column.""" + async with get_async_db_context(db) as db: + stmt = select(Model.meta).filter(Model.base_model_id != None) + + if not is_admin: + user_groups = await Groups.get_groups_by_member_id(user_id, db=db) + user_group_ids = [group.id for group in user_groups] + + filter_dict = {'user_id': user_id} + if user_group_ids: + filter_dict['group_ids'] = user_group_ids + + stmt = self._has_permission(db, stmt, filter_dict, permission='read') + + result = await db.execute(stmt) + rows = result.scalars().all() + + tags_set: set[str] = set() + for meta in rows: + if not meta: + continue + for tag in meta.get('tags', []): + try: + name = tag.get('name') if isinstance(tag, dict) else str(tag) + if name: + tags_set.add(name) + except Exception: + continue + + return tags_set + async def get_model_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[ModelModel]: try: async with get_async_db_context(db) as db: diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index 079245d550..510a0d3d29 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -138,18 +138,25 @@ async def get_models( db=db, ) - return ModelAccessListResponse( - items=[ + # Strip profile_image_url from meta — images are served via /model/profile/image. + items = [] + for model in result.items: + data = model.model_dump() + if data.get('meta'): + data['meta'].pop('profile_image_url', None) + items.append( ModelAccessResponse( - **model.model_dump(), + **data, write_access=( (user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL) or user.id == model.user_id or model.id in writable_model_ids ), ) - for model in result.items - ], + ) + + return ModelAccessListResponse( + items=items, total=result.total, ) @@ -171,25 +178,12 @@ async def get_base_models(user=Depends(get_admin_user), db: AsyncSession = Depen @router.get('/tags', response_model=list[str]) async def get_model_tags(user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session)): - if user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL: - models = await Models.get_models(db=db) - else: - models = await Models.get_models_by_user_id(user.id, db=db) - - tags_set = set() - for model in models: - if model.meta: - meta = model.meta.model_dump() - for tag in meta.get('tags', []): - try: - name = tag.get('name') if isinstance(tag, dict) else str(tag) - if name: - tags_set.add(name) - except Exception: - continue - - tags = sorted(tags_set) - return tags + tags = await Models.get_all_tags( + user_id=user.id, + is_admin=(user.role == 'admin' and BYPASS_ADMIN_ACCESS_CONTROL), + db=db, + ) + return sorted(tags) ############################ @@ -466,54 +460,48 @@ async def get_model_profile_image( user=Depends(get_verified_user), db: AsyncSession = Depends(get_async_session), ): - model = await Models.get_model_by_id(id, db=db) + model_meta = await Models.get_model_meta_by_id(id, db=db) - if model: - etag = f'"{model.updated_at}"' if model.updated_at else None + if model_meta: + meta, updated_at = model_meta + profile_image_url = (meta or {}).get('profile_image_url') - if model.meta.profile_image_url: - if model.meta.profile_image_url.startswith('http'): + if profile_image_url: + if profile_image_url.startswith('http'): return Response( status_code=status.HTTP_302_FOUND, - headers={'Location': model.meta.profile_image_url}, + headers={'Location': profile_image_url}, ) - elif model.meta.profile_image_url.startswith('data:image'): + elif profile_image_url.startswith('data:image'): try: - header, base64_data = model.meta.profile_image_url.split(',', 1) + header, base64_data = profile_image_url.split(',', 1) image_data = base64.b64decode(base64_data) image_buffer = io.BytesIO(image_data) media_type = header.split(';')[0].lstrip('data:') headers = {'Content-Disposition': 'inline'} - if etag: - headers['ETag'] = etag + if updated_at: + headers['ETag'] = f'"{updated_at}"' return StreamingResponse( image_buffer, media_type=media_type, headers=headers, ) - except Exception as e: + except Exception: pass else: - safe_static = _safe_static_redirect_path(model.meta.profile_image_url) + safe_static = _safe_static_redirect_path(profile_image_url) if safe_static: return RedirectResponse( url=safe_static, status_code=status.HTTP_302_FOUND, ) - # Canonical URL so browsers cache one asset for all default model avatars - # (distinct /profile/image?id=... URLs would otherwise re-download the same bytes). - return RedirectResponse( - url='/static/favicon.png', - status_code=status.HTTP_302_FOUND, - ) - else: - return RedirectResponse( - url='/static/favicon.png', - status_code=status.HTTP_302_FOUND, - ) + return RedirectResponse( + url='/static/favicon.png', + status_code=status.HTTP_302_FOUND, + ) ############################ diff --git a/backend/open_webui/utils/filter.py b/backend/open_webui/utils/filter.py index 50b1583088..07edf9afa7 100644 --- a/backend/open_webui/utils/filter.py +++ b/backend/open_webui/utils/filter.py @@ -14,7 +14,7 @@ async def get_function_module(request, function_id, load_from_db=True): """ Get the function module by its ID. """ - function_module, _, _ = await get_function_module_from_cache(request, function_id, load_from_db) + function_module, _, _ = await get_function_module_from_cache(request, function_id, load_from_db=load_from_db) return function_module diff --git a/backend/open_webui/utils/models.py b/backend/open_webui/utils/models.py index 6b12515ba1..cc8c5fad3a 100644 --- a/backend/open_webui/utils/models.py +++ b/backend/open_webui/utils/models.py @@ -287,9 +287,9 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None) # imported/custom model configs may reference tools or filters the user # hasn't installed, and trying to load those would cause persistent # "Failed to load function module" log spam on every model refresh. - for function_id in functions_by_id: + for function_id, function in functions_by_id.items(): try: - await get_function_module_from_cache(request, function_id) + await get_function_module_from_cache(request, function_id, function=function) except Exception as e: log.debug(f'Failed to load function module for {function_id}: {e}') diff --git a/backend/open_webui/utils/plugin.py b/backend/open_webui/utils/plugin.py index 84671bbd3b..5b945749ec 100644 --- a/backend/open_webui/utils/plugin.py +++ b/backend/open_webui/utils/plugin.py @@ -14,7 +14,7 @@ from open_webui.env import ( OFFLINE_MODE, ENABLE_PIP_INSTALL_FRONTMATTER_REQUIREMENTS, ) -from open_webui.models.functions import Functions +from open_webui.models.functions import FunctionModel, Functions from open_webui.models.tools import Tools log = logging.getLogger(__name__) @@ -335,13 +335,14 @@ async def get_tool_module_from_cache(request, tool_id, load_from_db=True): return tool_module, frontmatter -async def get_function_module_from_cache(request, function_id, load_from_db=True): +async def get_function_module_from_cache(request, function_id, function: FunctionModel | None = None, load_from_db=True): if load_from_db: # Always load from the database by default # This is useful for hooks like "inlet" or "outlet" where the content might change # and we want to ensure the latest content is used. - function = await Functions.get_function_by_id(function_id) + if function is None: + function = await Functions.get_function_by_id(function_id) if not function: raise Exception(f'Function not found: {function_id}') content = function.content diff --git a/backend/requirements-min.txt b/backend/requirements-min.txt index 950a458c8f..05c28deba6 100644 --- a/backend/requirements-min.txt +++ b/backend/requirements-min.txt @@ -28,7 +28,7 @@ starsessions[redis]==2.2.1 sqlalchemy==2.0.48 aiosqlite==0.21.0 -asyncpg==0.30.0 +psycopg[binary]==3.2.9 alembic==1.18.4 peewee==3.19.0 peewee-migrate==1.14.3 diff --git a/backend/requirements.txt b/backend/requirements.txt index 539835dd22..77b87324cf 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -26,7 +26,7 @@ python-mimeparse==2.0.0 sqlalchemy[asyncio]==2.0.48 aiosqlite==0.21.0 -asyncpg==0.30.0 +psycopg[binary]==3.2.9 alembic==1.18.4 peewee==3.19.0 peewee-migrate==1.14.3 diff --git a/pyproject.toml b/pyproject.toml index 2a802637a1..af6084dd08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,7 +34,7 @@ dependencies = [ "sqlalchemy[asyncio]==2.0.48", "aiosqlite==0.21.0", - "asyncpg==0.30.0", + "psycopg[binary]==3.2.9", "alembic==1.18.4", "peewee==3.19.0", "peewee-migrate==1.14.3", diff --git a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte index d8057acc96..09543fc3e7 100644 --- a/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte +++ b/src/lib/components/chat/ContentRenderer/FloatingButtons.svelte @@ -1,27 +1,14 @@ {:else}
-
-
- -
-
+ { + if (e.key === 'Enter') { + actionHandler(selectedAction?.id); + } + }} + /> -
-
+ -
- {/if} -
+ + + +
{/if} diff --git a/src/lib/components/chat/Messages/ContentRenderer.svelte b/src/lib/components/chat/Messages/ContentRenderer.svelte index 37246c6de2..ec1454a32d 100644 --- a/src/lib/components/chat/Messages/ContentRenderer.svelte +++ b/src/lib/components/chat/Messages/ContentRenderer.svelte @@ -37,7 +37,7 @@ export let onSave = (e) => {}; export let onSourceClick = (e) => {}; export let onTaskClick = (e) => {}; - export let onAddMessages = (e) => {}; + export let onSetInputText = (text) => {}; let contentContainerElement; let floatingButtonsElement; @@ -140,20 +140,36 @@ } }; - onMount(() => { - if (floatingButtons) { - contentContainerElement?.addEventListener('mouseup', updateButtonPosition); + // Reactive listener attachment: re-attaches when floatingButtons + // transitions from false → true (e.g. when message.done flips). + let listenersAttached = false; + + function attachListeners() { + if (!listenersAttached && contentContainerElement) { + contentContainerElement.addEventListener('mouseup', updateButtonPosition); document.addEventListener('mouseup', updateButtonPosition); document.addEventListener('keydown', keydownHandler); + listenersAttached = true; } - }); + } - onDestroy(() => { - if (floatingButtons) { + function detachListeners() { + if (listenersAttached) { contentContainerElement?.removeEventListener('mouseup', updateButtonPosition); document.removeEventListener('mouseup', updateButtonPosition); document.removeEventListener('keydown', keydownHandler); + listenersAttached = false; } + } + + $: if (floatingButtons && contentContainerElement) { + attachListeners(); + } else { + detachListeners(); + } + + onDestroy(() => { + detachListeners(); }); @@ -201,17 +217,9 @@ 0 - ? selectedModels.at(0) - : (model?.id ?? null)} - messages={createMessagesList(history, messageId)} - onAdd={({ modelId, parentId, messages }) => { - console.log(modelId, parentId, messages); - onAddMessages({ modelId, parentId, messages }); + onSetInputText={(text) => { + onSetInputText(text); closeFloatingButtons(); }} /> diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 2d339c6f36..e333215af9 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -788,9 +788,6 @@ { - addMessages({ modelId, parentId, messages }); + onSetInputText={(text) => { + setInputText(text); }} onSave={({ raw, oldContent, newContent }) => { history.messages[message.id].content = history.messages[ diff --git a/src/lib/components/workspace/Models.svelte b/src/lib/components/workspace/Models.svelte index b74711ddb2..8c177f48b4 100644 --- a/src/lib/components/workspace/Models.svelte +++ b/src/lib/components/workspace/Models.svelte @@ -601,6 +601,8 @@ src={`${WEBUI_API_BASE_URL}/models/model/profile/image?id=${model.id}&lang=${$i18n.language}`} alt="modelfile profile" class=" rounded-2xl size-12 object-cover" + loading="lazy" + decoding="async" on:error={(e) => { e.target.src = '/favicon.png'; }} From 70b28b629e66ca98b07ba61b7514fa8c6e5b5529 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:29:39 +0900 Subject: [PATCH 396/404] refac --- src/lib/components/admin/Settings/Documents.svelte | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index a2349e78e5..6416b2d05a 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -1369,7 +1369,14 @@ )} /> +
+ + {#if RAGConfig.RAG_TEMPLATE && ((RAGConfig.RAG_TEMPLATE.match(/\[context\]/g) || []).length + (RAGConfig.RAG_TEMPLATE.match(/\{\{CONTEXT\}\}/g) || []).length) > 1} +
+ {$i18n.t('This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.')} +
+ {/if}
{/if} From b1bd3084f0ea0e7a6a53eaf1b6bb2389ba961ae7 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 24 Apr 2026 11:30:51 +0200 Subject: [PATCH 397/404] changelog (#24072) --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8049dcca1b..b37ca58ad5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.9.2] - 2026-04-24 + +### Added + +- 🧠 **PaddleOCR-vl document extraction.** Administrators can now use PaddleOCR-vl as a content extraction engine for document processing, with configurable API URL and token settings in document retrieval configuration. [Commit](https://github.com/open-webui/open-webui/commit/04c7e9535d330906891eefa5eda516f661c1cf79..331b7520db719d2f1c76c4b06603a9a59a9b7c25) +- 🧵 **Streaming markdown performance stability.** Streaming responses now stay more memory-efficient by preventing repeated cleanup callback registration during markdown updates. [#24048](https://github.com/open-webui/open-webui/pull/24048) +- 📚 **Source overflow indicator.** The Sources button now shows a +N badge when more than three sources are available, so hidden sources are clearly indicated in chat responses. [#23918](https://github.com/open-webui/open-webui/pull/23918) +- ⚡ **Model avatar cache reuse.** Default model profile images now reuse a shared static path to reduce repeated downloads and improve loading efficiency when multiple models use the fallback icon. [#24015](https://github.com/open-webui/open-webui/pull/24015) +- 🚀 **Faster splash image loading.** Splash screen images are now prioritized earlier during page load, improving first-load LCP behavior and reducing delayed image discovery. [#24011](https://github.com/open-webui/open-webui/pull/24011) +- 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security. +- 🌐 **Translation updates.** Translations for Finnish, Korean, Portuguese (Brazil), and Dutch were enhanced and expanded. + +### Fixed + +- 🛠️ **Throttle request handling.** Request handling no longer fails when user activity status updates are throttled with a non-zero interval. [#23979](https://github.com/open-webui/open-webui/pull/23979) +- ✍️ **Rich text extension conflicts.** Rich text editing no longer triggers duplicate extension conflicts for lists and code blocks, improving editor stability. [#24009](https://github.com/open-webui/open-webui/pull/24009) + +### Changed + +- + ## [0.9.1] - 2026-04-21 ### Fixed From e0d6074cd2402ef983d18ad16ded88401ca44705 Mon Sep 17 00:00:00 2001 From: RomualdYT Date: Fri, 24 Apr 2026 11:32:08 +0200 Subject: [PATCH 398/404] refactor(firecrawl): use v2 API directly (#23934) Co-authored-by: Tim Baek --- backend/open_webui/retrieval/web/firecrawl.py | 227 ++++++++++++++++-- backend/open_webui/retrieval/web/utils.py | 42 +--- backend/requirements.txt | 3 - pyproject.toml | 1 - uv.lock | 20 +- 5 files changed, 215 insertions(+), 78 deletions(-) diff --git a/backend/open_webui/retrieval/web/firecrawl.py b/backend/open_webui/retrieval/web/firecrawl.py index 8cd18e1ef2..4bbd4f212b 100644 --- a/backend/open_webui/retrieval/web/firecrawl.py +++ b/backend/open_webui/retrieval/web/firecrawl.py @@ -1,52 +1,229 @@ +from __future__ import annotations + import logging -from typing import Optional, List +import time +from typing import TYPE_CHECKING, Any import requests -from open_webui.retrieval.web.main import SearchResult, get_filtered_results +from langchain_core.documents import Document + +if TYPE_CHECKING: + from open_webui.retrieval.web.main import SearchResult log = logging.getLogger(__name__) +DEFAULT_FIRECRAWL_API_BASE_URL = 'https://api.firecrawl.dev' +FIRECRAWL_RETRY_STATUS_CODES = {429, 500, 502, 503, 504} +FIRECRAWL_MAX_RETRIES = 2 + + +def build_firecrawl_url(base_url: str | None, path: str) -> str: + base_url = (base_url or DEFAULT_FIRECRAWL_API_BASE_URL).rstrip('/') + path = path.lstrip('/') + + if base_url.endswith('/v2'): + return f'{base_url}/{path}' + + return f'{base_url}/v2/{path}' + + +def build_firecrawl_headers(api_key: str | None) -> dict[str, str]: + return { + 'Content-Type': 'application/json', + 'Authorization': f'Bearer {api_key or ""}', + } + + +def get_firecrawl_timeout_seconds(timeout: Any) -> float | None: + if timeout in (None, ''): + return None + + try: + timeout = float(timeout) + except (TypeError, ValueError): + return None + + return timeout if timeout > 0 else None + + +def get_firecrawl_scrape_timeout_ms(timeout: Any) -> int | None: + timeout_seconds = get_firecrawl_timeout_seconds(timeout) + if timeout_seconds is None: + return None + + # Firecrawl v2 expects scrape timeouts in milliseconds. + return min(300000, max(1000, int(timeout_seconds * 1000))) + + +def get_firecrawl_client_timeout_seconds(timeout: Any, fallback: float = 60) -> float: + # Keep the local HTTP timeout slightly above Firecrawl's scrape timeout. + return (get_firecrawl_timeout_seconds(timeout) or fallback) + 10 + + +def get_firecrawl_retry_delay(headers: Any, attempt: int) -> float: + retry_after = headers.get('Retry-After') if headers else None + if retry_after: + try: + return min(10.0, max(0.0, float(retry_after))) + except (TypeError, ValueError): + pass + + return min(8.0, float(2**attempt)) + + +def request_firecrawl_json( + method: str, + url: str, + *, + headers: dict[str, str], + json: dict[str, Any] | None = None, + timeout: float | None = None, + verify: bool = True, +) -> dict[str, Any]: + last_error = None + + for attempt in range(FIRECRAWL_MAX_RETRIES + 1): + try: + response = requests.request( + method, + url, + headers=headers, + json=json, + timeout=timeout, + verify=verify, + ) + + if response.status_code in FIRECRAWL_RETRY_STATUS_CODES and attempt < FIRECRAWL_MAX_RETRIES: + delay = get_firecrawl_retry_delay(response.headers, attempt) + log.warning( + 'Firecrawl %s %s returned HTTP %s; retrying in %.1fs', + method, + url, + response.status_code, + delay, + ) + time.sleep(delay) + continue + + response.raise_for_status() + return response.json() + except (requests.ConnectionError, requests.Timeout) as e: + last_error = e + if attempt >= FIRECRAWL_MAX_RETRIES: + break + + delay = get_firecrawl_retry_delay(None, attempt) + log.warning('Firecrawl %s %s failed; retrying in %.1fs: %s', method, url, delay, e) + time.sleep(delay) + + if last_error: + raise last_error + + raise RuntimeError(f'Firecrawl {method} {url} failed without a response') + + +def get_firecrawl_result_url(result: dict[str, Any]) -> str: + metadata = result.get('metadata') or {} + return ( + result.get('url') + or result.get('link') + or metadata.get('url') + or metadata.get('sourceURL') + or metadata.get('source_url') + or '' + ) + + +def scrape_firecrawl_url( + firecrawl_url: str, + firecrawl_api_key: str, + url: str, + *, + verify_ssl: bool = True, + timeout: Any = None, + params: dict[str, Any] | None = None, +) -> Document | None: + payload = { + 'url': url, + 'formats': ['markdown'], + 'skipTlsVerification': not verify_ssl, + 'removeBase64Images': True, + **(params or {}), + } + scrape_timeout_ms = get_firecrawl_scrape_timeout_ms(timeout) + if scrape_timeout_ms is not None: + payload['timeout'] = scrape_timeout_ms + + response = request_firecrawl_json( + 'POST', + build_firecrawl_url(firecrawl_url, 'scrape'), + headers=build_firecrawl_headers(firecrawl_api_key), + json=payload, + timeout=get_firecrawl_client_timeout_seconds(timeout), + verify=verify_ssl, + ) + data = response.get('data') or {} + content = data.get('markdown') or '' + if not isinstance(content, str) or not content.strip(): + return None + + metadata = data.get('metadata') or {} + document_metadata = {'source': get_firecrawl_result_url(data) or url} + if metadata.get('title'): + document_metadata['title'] = metadata['title'] + if metadata.get('description'): + document_metadata['description'] = metadata['description'] + + return Document(page_content=content, metadata=document_metadata) + def search_firecrawl( firecrawl_url: str, firecrawl_api_key: str, query: str, count: int, - filter_list: Optional[List[str]] = None, -) -> List[SearchResult]: + filter_list: list[str] | None = None, +) -> list[SearchResult]: try: - url = firecrawl_url.rstrip('/') - response = requests.post( - f'{url}/v1/search', - headers={ - 'Content-Type': 'application/json', - 'Authorization': f'Bearer {firecrawl_api_key}', - }, + response = request_firecrawl_json( + 'POST', + build_firecrawl_url(firecrawl_url, 'search'), + headers=build_firecrawl_headers(firecrawl_api_key), json={ 'query': query, 'limit': count, 'timeout': count * 3000, + 'ignoreInvalidURLs': True, }, timeout=count * 3 + 10, ) - response.raise_for_status() - data = response.json().get('data', []) - - results = [ - SearchResult( - link=r.get('url', ''), - title=r.get('title', ''), - snippet=r.get('description', ''), - ) - for r in (data if isinstance(data, list) else []) - ] + data = response.get('data') or {} + results = data.get('web') or [] if filter_list: + from open_webui.retrieval.web.main import get_filtered_results + results = get_filtered_results(results, filter_list) - results = results[:count] - log.info(f'FireCrawl search results: {results}') - return results + from open_webui.retrieval.web.main import SearchResult + + search_results = [] + for result in results[:count]: + url = get_firecrawl_result_url(result) + if not url: + continue + + metadata = result.get('metadata') or {} + search_results.append( + SearchResult( + link=url, + title=result.get('title') or metadata.get('title'), + snippet=result.get('description') or result.get('snippet') or metadata.get('description'), + ) + ) + + log.info(f'FireCrawl search results: {search_results}') + return search_results except Exception as e: log.error(f'Error in FireCrawl search: {e}') return [] diff --git a/backend/open_webui/retrieval/web/utils.py b/backend/open_webui/retrieval/web/utils.py index 9cb0c1abd7..6ee0e3781a 100644 --- a/backend/open_webui/retrieval/web/utils.py +++ b/backend/open_webui/retrieval/web/utils.py @@ -30,6 +30,7 @@ from langchain_core.documents import Document from open_webui.retrieval.loaders.tavily import TavilyLoader from open_webui.retrieval.loaders.external_web import ExternalWebLoader +from open_webui.retrieval.web.firecrawl import scrape_firecrawl_url from open_webui.constants import ERROR_MESSAGES from open_webui.config import ( ENABLE_RAG_LOCAL_WEB_FETCH, @@ -218,39 +219,20 @@ class SafeFireCrawlLoader(BaseLoader, RateLimitMixin, URLProcessingMixin): def lazy_load(self) -> Iterator[Document]: try: - headers = { - 'Content-Type': 'application/json', - 'Authorization': f'Bearer {self.api_key}', - } - for url in self.web_paths: - payload = { - 'url': url, - 'formats': ['markdown'], - **self.params, - } - if self.timeout: - payload['timeout'] = self.timeout * 1000 - - response = requests.post( - f'{self.api_url}/v1/scrape', - headers=headers, - json=payload, - timeout=self.timeout or 60, - verify=self.verify_ssl, - ) - response.raise_for_status() - data = response.json().get('data', {}) - metadata = data.get('metadata', {}) - source = metadata.get('url') or metadata.get('sourceURL') or url - - yield Document( - page_content=data.get('markdown', ''), - metadata={'source': source}, + doc = scrape_firecrawl_url( + self.api_url, + self.api_key, + url, + verify_ssl=self.verify_ssl, + timeout=self.timeout, + params=self.params, ) + if doc is not None: + yield doc except Exception as e: if self.continue_on_failure: - log.exception(f'Error extracting content from URLs: {e}') + log.warning(f'Error extracting content from URLs with Firecrawl: {e}') else: raise e @@ -261,7 +243,7 @@ class SafeFireCrawlLoader(BaseLoader, RateLimitMixin, URLProcessingMixin): yield doc except Exception as e: if self.continue_on_failure: - log.exception(f'Error extracting content from URLs: {e}') + log.warning(f'Error extracting content from URLs with Firecrawl: {e}') else: raise e diff --git a/backend/requirements.txt b/backend/requirements.txt index 77b87324cf..a7d2b1cb53 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -145,9 +145,6 @@ pytest-docker~=3.2.5 ## LDAP ldap3==2.9.1 -## Firecrawl -firecrawl-py==4.18.0 - ## Trace opentelemetry-api==1.40.0 opentelemetry-sdk==1.40.0 diff --git a/pyproject.toml b/pyproject.toml index af6084dd08..8d8fc8a755 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,7 +167,6 @@ all = [ "oracledb==3.4.2", "colbert-ai==0.2.22", - "firecrawl-py==4.18.0", "azure-search-documents==11.6.0", "unstructured==0.18.31", ] diff --git a/uv.lock b/uv.lock index 7bde0eeb01..8f610937f5 100644 --- a/uv.lock +++ b/uv.lock @@ -1133,22 +1133,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, ] -[[package]] -name = "firecrawl-py" -version = "1.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nest-asyncio" }, - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/db/e4f8ef9f0475b91b7c16a15e02fe19069d443cc5516cdefa2f9a0924a9a3/firecrawl_py-1.12.0.tar.gz", hash = "sha256:bbf883f6c774f05a5426121b85978a5f7b5ab11e614aff609f0673b097c3e553", size = 19655, upload-time = "2025-02-13T15:40:15.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/d8/301d829099082c606ed16ed2a9acd263c47a365d471b9636435bf5d858b3/firecrawl_py-1.12.0-py3-none-any.whl", hash = "sha256:2b9c549315027da32421aca2a7ca597cb05cdbb968cfe0a89f389c7bb20afa4a", size = 31854, upload-time = "2025-02-13T15:40:14.492Z" }, -] - [[package]] name = "flask" version = "3.1.0" @@ -2692,7 +2676,6 @@ dependencies = [ { name = "fake-useragent" }, { name = "fastapi" }, { name = "faster-whisper" }, - { name = "firecrawl-py" }, { name = "fpdf2" }, { name = "ftfy" }, { name = "gcp-storage-emulator" }, @@ -2803,7 +2786,6 @@ requires-dist = [ { name = "fake-useragent", specifier = "==2.1.0" }, { name = "fastapi", specifier = "==0.115.7" }, { name = "faster-whisper", specifier = "==1.1.1" }, - { name = "firecrawl-py", specifier = "==1.12.0" }, { name = "fpdf2", specifier = "==2.8.2" }, { name = "ftfy", specifier = "==6.2.3" }, { name = "gcp-storage-emulator", specifier = ">=2024.8.3" }, @@ -5321,4 +5303,4 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f2/61/ac78a1263bc83a5cf29e7458b77a568eda5a8f81980691bbc6eb6a0d45cc/zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35", size = 5191313, upload-time = "2024-07-15T00:16:09.758Z" }, { url = "https://files.pythonhosted.org/packages/e7/54/967c478314e16af5baf849b6ee9d6ea724ae5b100eb506011f045d3d4e16/zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d", size = 430877, upload-time = "2024-07-15T00:16:11.758Z" }, { url = "https://files.pythonhosted.org/packages/75/37/872d74bd7739639c4553bf94c84af7d54d8211b626b352bc57f0fd8d1e3f/zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b", size = 495595, upload-time = "2024-07-15T00:16:13.731Z" }, -] \ No newline at end of file +] From 3aeb691d985bc614cdfb927ddbd01f0c72c31777 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:33:27 +0900 Subject: [PATCH 399/404] chore: bump --- package-lock.json | 30 +++++++++++++++--------------- package.json | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3175ba8a0..35554ac1d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.9.1", + "version": "0.9.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.9.1", + "version": "0.9.2", "dependencies": { "@azure/msal-browser": "^4.5.0", "@codemirror/lang-javascript": "^6.2.2", @@ -2284,9 +2284,9 @@ "license": "Apache-2.0" }, "node_modules/@mermaid-js/parser": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.0.1.tgz", - "integrity": "sha512-opmV19kN1JsK0T6HhhokHpcVkqKpF+x2pPDKKM2ThHtZAB5F4PROopk0amuVYK5qMrIA4erzpNm8gmPNJgMDxQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.0.tgz", + "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==", "license": "MIT", "dependencies": { "langium": "^4.0.0" @@ -3582,9 +3582,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.57.1", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.57.1.tgz", - "integrity": "sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw==", + "version": "2.58.0", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.58.0.tgz", + "integrity": "sha512-kT9GCN8yJTkCK1W+Gi/bvGooWAM7y7WXP+yd+rf6QOIjyoK1ERPrMwSufXJUNu2pMWIqruhFvmz+LbOqsEmKmA==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", @@ -5388,9 +5388,9 @@ "license": "MIT" }, "node_modules/@xmldom/xmldom": { - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.12.tgz", - "integrity": "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg==", + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -10948,14 +10948,14 @@ } }, "node_modules/mermaid": { - "version": "11.13.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.13.0.tgz", - "integrity": "sha512-fEnci+Immw6lKMFI8sqzjlATTyjLkRa6axrEgLV2yHTfv8r+h1wjFbV6xeRtd4rUV1cS4EpR9rwp3Rci7TRWDw==", + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz", + "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==", "license": "MIT", "dependencies": { "@braintree/sanitize-url": "^7.1.1", "@iconify/utils": "^3.0.2", - "@mermaid-js/parser": "^1.0.1", + "@mermaid-js/parser": "^1.1.0", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.1", diff --git a/package.json b/package.json index ab246848c0..edd77762e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.9.1", + "version": "0.9.2", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", From 3560d2f6305a9ddcdf9e3db54ad283deec94dd22 Mon Sep 17 00:00:00 2001 From: Constantine Date: Fri, 24 Apr 2026 12:34:57 +0300 Subject: [PATCH 400/404] perf(chats): drop redundant db.refresh after commit in update_chat_by_id (#24024) The chat table has no computed columns (no DEFAULT, SERIAL/IDENTITY, or TRIGGER that populate server-side values on UPDATE), and every column modified by update_chat_by_id is set explicitly from Python values earlier in the function. db.refresh therefore issues a SELECT that replaces those just-written Python values with the round-tripped database representation of the same values, which is a no-op for functional purposes but pulls the entire chat.chat JSON blob back over the network and through the driver's JSON decoder. On large, active chats where chat.chat can reach tens of megabytes, skipping the refresh measurably reduces latency and eliminates one ~JSON-sized transient allocation per write. --- backend/open_webui/models/chats.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index ba6611a811..bcf6951e49 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -393,7 +393,6 @@ class ChatTable: chat_item.updated_at = int(time.time()) await db.commit() - await db.refresh(chat_item) return ChatModel.model_validate(chat_item) except Exception: From f48b8ffbf0a232b8487cd2b7d0181039b14f0586 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:38:57 +0900 Subject: [PATCH 401/404] refac --- CHANGELOG.md | 35 ++++++++++++++++++++++---- backend/open_webui/utils/middleware.py | 9 +++++++ backend/open_webui/utils/misc.py | 32 ++++++++++++++++++++--- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b37ca58ad5..b78fd6b99b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,22 +9,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- 🧠 **PaddleOCR-vl document extraction.** Administrators can now use PaddleOCR-vl as a content extraction engine for document processing, with configurable API URL and token settings in document retrieval configuration. [Commit](https://github.com/open-webui/open-webui/commit/04c7e9535d330906891eefa5eda516f661c1cf79..331b7520db719d2f1c76c4b06603a9a59a9b7c25) -- 🧵 **Streaming markdown performance stability.** Streaming responses now stay more memory-efficient by preventing repeated cleanup callback registration during markdown updates. [#24048](https://github.com/open-webui/open-webui/pull/24048) +- 🧠 **PaddleOCR-vl document extraction.** Administrators can now use PaddleOCR-vl as a content extraction engine for document processing, with configurable API URL and token settings in document retrieval configuration. [#23945](https://github.com/open-webui/open-webui/pull/23945) +- 🔥 **Firecrawl v2 API.** Firecrawl web loading now uses the v2 API directly with proper retry logic, exponential backoff on rate limits, and configurable timeout handling, improving reliability for both cloud and self-hosted Firecrawl setups. [#23934](https://github.com/open-webui/open-webui/pull/23934) +- ⏰ **Calendar event reminder customization.** Calendar events now support a configurable `reminder_minutes` parameter, allowing models to set custom reminder durations instead of the default 10-minute notification. +- 🔑 **Custom API key header.** Administrators can now configure a custom header name for API key authentication via the `CUSTOM_API_KEY_HEADER` environment variable, enabling compatibility with reverse proxies that use the `Authorization` header for their own authentication. +- 🔌 **OAuth session disconnection.** Users can now disconnect OAuth sessions for specific providers (e.g., MCP connections) through a new API endpoint, enabling cleaner re-authentication workflows. - 📚 **Source overflow indicator.** The Sources button now shows a +N badge when more than three sources are available, so hidden sources are clearly indicated in chat responses. [#23918](https://github.com/open-webui/open-webui/pull/23918) -- ⚡ **Model avatar cache reuse.** Default model profile images now reuse a shared static path to reduce repeated downloads and improve loading efficiency when multiple models use the fallback icon. [#24015](https://github.com/open-webui/open-webui/pull/24015) -- 🚀 **Faster splash image loading.** Splash screen images are now prioritized earlier during page load, improving first-load LCP behavior and reducing delayed image discovery. [#24011](https://github.com/open-webui/open-webui/pull/24011) +- ⚡ **Model list performance.** Model list API responses now strip base64 profile image data from paginated results, and model tags are fetched via a dedicated efficient query instead of loading all models. This significantly reduces payload sizes and improves workspace Models page responsiveness. +- ⚡ **Model avatar cache reuse.** Default model profile images now redirect to a shared static path instead of reading files from disk per-request, reducing repeated I/O and improving loading efficiency when multiple models use the fallback icon. [#24015](https://github.com/open-webui/open-webui/pull/24015) +- 🚀 **Faster splash image loading.** Splash screen images are now prioritized earlier during page load with preload links, improving first-load LCP behavior and reducing delayed image discovery. [#24011](https://github.com/open-webui/open-webui/pull/24011) +- 🧵 **Streaming markdown performance stability.** Streaming responses now stay more memory-efficient by preventing repeated cleanup callback registration during markdown updates. [#24048](https://github.com/open-webui/open-webui/pull/24048) +- 📊 **Telemetry gauge reliability.** OpenTelemetry user gauge callbacks now use synchronous database queries directly, eliminating cross-thread async bridging issues that could cause silent failures in metric collection. - 🔄 **General improvements.** Various improvements were implemented across the application to enhance performance, stability, and security. - 🌐 **Translation updates.** Translations for Finnish, Korean, Portuguese (Brazil), and Dutch were enhanced and expanded. ### Fixed +- 🔧 **MCP task cancellation stability.** Interrupted MCP tool calls no longer cause CPU spikes or runaway cleanup behavior. MCP client disconnection now runs in the same asyncio task as connection, respecting cancel scope constraints, and chat-active events are properly shielded during cancellation. +- 🧠 **Persistent chat skill injection.** Skills mentioned in persisted chats now inject into the system prompt reliably. Skill ID extraction from `<$skillId|label>` message tags is now handled server-side, and tags are stripped before messages reach the model. +- 🗄️ **Async database driver migration.** The async database backend now uses psycopg (v3) instead of asyncpg, eliminating brittle SSL parameter translation and supporting native libpq connection strings including `sslmode`, `options`, and `target_session_attrs` without any stripping or conversion. +- 🐳 **Docker ARM64 reliability.** Docker images built for arm64 via QEMU cross-compilation no longer produce 0-byte corrupted Python dependencies. `UV_LINK_MODE=copy` is now set in the Dockerfile to force reliable file installation. - 🛠️ **Throttle request handling.** Request handling no longer fails when user activity status updates are throttled with a non-zero interval. [#23979](https://github.com/open-webui/open-webui/pull/23979) - ✍️ **Rich text extension conflicts.** Rich text editing no longer triggers duplicate extension conflicts for lists and code blocks, improving editor stability. [#24009](https://github.com/open-webui/open-webui/pull/24009) +- 🔇 **Fetch URL null content guard.** The `fetch_url` built-in tool now safely handles `None` content returned by web loaders instead of crashing with a `TypeError`. +- 🌐 **OAuth discovery fallback.** OAuth protected resource discovery now falls back to well-known RFC 9728 URIs when the `WWW-Authenticate` header doesn't contain a `resource_metadata` link, improving compatibility with more MCP server implementations. +- 🔐 **Session token resolution.** Session user endpoints now gracefully handle missing `Authorization` headers by falling back to cookie and request state tokens, preventing errors when used behind forward-auth proxies. +- 🚫 **Direct API error responses.** Chat completion requests without a WebSocket channel (direct API calls) now return proper HTTP error responses instead of silently returning null on failure. +- 📡 **Cancelled response stream cleanup.** Cancelled chat generation now explicitly closes the upstream response body iterator, preventing orphaned async generators from spinning in anyio internals. +- 🔒 **Model profile image path safety.** Model profile image endpoints now validate and sanitize static asset redirect paths, preventing path traversal through encoded dots or malicious URL patterns. +- 📊 **RAG template validation UI.** The Documents settings page now displays a warning when RAG templates contain multiple `[context]` or `{{CONTEXT}}` placeholders, helping administrators avoid accidental redundant context injection. +- 🧩 **Automation model detection.** The `create_automation` tool now correctly detects the current model ID even when `model_id` is not yet set in metadata, falling back to the model dict. +- 🔄 **MCP resource content handling.** MCP tool results with the `resource` content type are now correctly detected and their `resource.text` payload is extracted, instead of being silently ignored. +- 🔄 **Ollama and OpenAI metadata forwarding.** Ollama and OpenAI proxy routes now forward request metadata to downstream handlers, ensuring consistent context propagation. +- 🧹 **Browser-native message virtualization.** The custom JavaScript-based message culling system (spacers, height caching, scroll listeners) was replaced with CSS `content-visibility: auto`, letting the browser natively skip rendering of off-screen messages without destroying component trees. This eliminates scroll jump artifacts and mount/destroy thrashing while preserving memory efficiency in long conversations. +- 📻 **Redis notification compatibility.** Redis pub/sub now handles missing or incompatible `client_name` support more gracefully, preventing connection errors with certain Redis configurations. ### Changed -- +- ⚙️ **psycopg v3 async driver.** The async database driver has been migrated from `asyncpg` to `psycopg` (v3). This is a transparent change for most deployments, but custom connection strings with `asyncpg`-specific parameters may need adjustment. +- 🔑 **Brotli dependency update.** Brotli has been updated to address CVE-2025-6176. +- 🖥️ **Windows startup script.** The Windows startup batch script has been updated for improved compatibility. + ## [0.9.1] - 2026-04-21 diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index ab2ca104f4..5b1da36d37 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1164,6 +1164,15 @@ async def process_tool_result( 'url': file_url, } ) + elif item.get('type') == 'resource': + resource = item.get('resource', {}) + text = resource.get('text', '') + if isinstance(text, str) and text: + try: + text = json.loads(text) + except json.JSONDecodeError: + pass + tool_response.append(text) tool_result = tool_response[0] if len(tool_response) == 1 else tool_response else: # OpenAPI for item in tool_result: diff --git a/backend/open_webui/utils/misc.py b/backend/open_webui/utils/misc.py index 5af84dd5cd..dec5dce94c 100644 --- a/backend/open_webui/utils/misc.py +++ b/backend/open_webui/utils/misc.py @@ -597,6 +597,9 @@ def sanitize_text_for_db(text: str) -> str: """Remove null bytes and invalid UTF-8 surrogates from text for PostgreSQL storage.""" if not isinstance(text, str): return text + # Fast path: skip work when there are no null bytes (the common case) + if '\x00' not in text: + return text # Remove null bytes text = text.replace('\x00', '').replace('\u0000', '') # Remove invalid UTF-8 surrogate characters that can cause encoding errors @@ -608,17 +611,38 @@ def sanitize_text_for_db(text: str) -> str: return text -def sanitize_data_for_db(obj): - """Recursively sanitize all strings in a data structure for database storage.""" +def _strip_null_bytes_deep(obj): + """Inner recursive walk — only called when null bytes are known to be present.""" if isinstance(obj, str): return sanitize_text_for_db(obj) elif isinstance(obj, dict): - return {k: sanitize_data_for_db(v) for k, v in obj.items()} + return {k: _strip_null_bytes_deep(v) for k, v in obj.items()} elif isinstance(obj, list): - return [sanitize_data_for_db(v) for v in obj] + return [_strip_null_bytes_deep(v) for v in obj] return obj +def sanitize_data_for_db(obj): + """Recursively sanitize all strings in a data structure for database storage. + + Performs a fast pre-check: serializes the structure once and scans for + null bytes. If none are found (the overwhelmingly common case), the + original object is returned immediately, skipping the expensive + recursive walk. + """ + if isinstance(obj, str): + return sanitize_text_for_db(obj) + # Fast path: check for null bytes in the serialized form. + # json.dumps is implemented in C and much faster than a Python-level + # recursive walk over every leaf string. + try: + if '\x00' not in json.dumps(obj, ensure_ascii=False): + return obj + except (TypeError, ValueError): + pass + return _strip_null_bytes_deep(obj) + + def sanitize_metadata(metadata: dict) -> dict: """ Return a JSON-safe copy of a metadata dict for database storage. From 8ff7ff459b360e62ff9cbe0d6d2f6fc79cca6089 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:48:21 +0900 Subject: [PATCH 402/404] chore: format --- CHANGELOG.md | 1 - backend/open_webui/internal/db.py | 8 +- backend/open_webui/main.py | 4 +- backend/open_webui/models/models.py | 8 +- backend/open_webui/models/oauth_sessions.py | 4 +- backend/open_webui/retrieval/loaders/main.py | 5 +- .../retrieval/loaders/paddleocr_vl.py | 94 +++++++++---------- backend/open_webui/routers/auths.py | 4 +- backend/open_webui/routers/tools.py | 1 - backend/open_webui/utils/plugin.py | 4 +- src/lib/apis/configs/index.ts | 1 - src/lib/apis/tools/index.ts | 1 - src/lib/apis/users/index.ts | 1 - .../admin/Settings/Documents.svelte | 7 +- .../chat/MessageInput/IntegrationsMenu.svelte | 2 +- .../components/chat/Messages/Message.svelte | 1 - src/lib/i18n/locales/ko-KR/translation.json | 10 +- src/routes/+layout.svelte | 5 +- 18 files changed, 73 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b78fd6b99b..0b7755d7f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,7 +50,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🔑 **Brotli dependency update.** Brotli has been updated to address CVE-2025-6176. - 🖥️ **Windows startup script.** The Windows startup batch script has been updated for improved compatibility. - ## [0.9.1] - 2026-04-21 ### Fixed diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index 4592aa6cb8..c9e4f318e1 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -57,9 +57,7 @@ def _pop_first(params: dict[str, list[str]], key: str) -> str | None: def _is_postgres_url(url: str) -> bool: """Return True if *url* looks like a PostgreSQL connection string.""" - return bool(url) and any( - url.startswith(p) for p in ('postgresql://', 'postgresql+', 'postgres://') - ) + return bool(url) and any(url.startswith(p) for p in ('postgresql://', 'postgresql+', 'postgres://')) def extract_ssl_params_from_url(url: str) -> tuple[str, dict[str, str]]: @@ -180,9 +178,7 @@ if ENABLE_DB_MIGRATIONS: _url_without_ssl, _ssl_dict = extract_ssl_params_from_url(DATABASE_URL) # For psycopg2 (sync engine), re-append sslmode + cert-file params. -SQLALCHEMY_DATABASE_URL = ( - reattach_ssl_params_to_url(_url_without_ssl, _ssl_dict) if _ssl_dict else DATABASE_URL -) +SQLALCHEMY_DATABASE_URL = reattach_ssl_params_to_url(_url_without_ssl, _ssl_dict) if _ssl_dict else DATABASE_URL def _make_async_url(url: str) -> str: diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 9bc6b5177d..af570af0af 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1869,6 +1869,7 @@ async def chat_completion( except asyncio.CancelledError: log.info('Chat processing was cancelled') try: + async def emit_cancel_event(): event_emitter = await get_event_emitter(metadata) if event_emitter: @@ -1940,6 +1941,7 @@ async def chat_completion( try: if metadata.get('chat_id'): + async def emit_inactive_event(): try: event_emitter = await get_event_emitter(metadata, update_db=False) @@ -1947,7 +1949,7 @@ async def chat_completion( await event_emitter({'type': 'chat:active', 'data': {'active': False}}) except Exception: pass - + try: # Shield the event emission so it finishes even if the main task is cancelled await asyncio.shield(emit_inactive_event()) diff --git a/backend/open_webui/models/models.py b/backend/open_webui/models/models.py index db9459e028..79c13153ac 100755 --- a/backend/open_webui/models/models.py +++ b/backend/open_webui/models/models.py @@ -391,15 +391,11 @@ class ModelsTable: return ModelListResponse(items=models, total=total) - async def get_model_meta_by_id( - self, id: str, db: Optional[AsyncSession] = None - ) -> Optional[tuple[dict, int]]: + async def get_model_meta_by_id(self, id: str, db: Optional[AsyncSession] = None) -> Optional[tuple[dict, int]]: """Return (meta, updated_at) for a model, skipping access grant resolution.""" try: async with get_async_db_context(db) as db: - result = await db.execute( - select(Model.meta, Model.updated_at).filter_by(id=id) - ) + result = await db.execute(select(Model.meta, Model.updated_at).filter_by(id=id)) return result.first() except Exception: return None diff --git a/backend/open_webui/models/oauth_sessions.py b/backend/open_webui/models/oauth_sessions.py index fce18ae586..c43567f670 100644 --- a/backend/open_webui/models/oauth_sessions.py +++ b/backend/open_webui/models/oauth_sessions.py @@ -326,9 +326,7 @@ class OAuthSessionTable: """Delete all OAuth sessions for a specific user and provider""" try: async with get_async_db_context(db) as db: - result = await db.execute( - delete(OAuthSession).filter_by(user_id=user_id, provider=provider) - ) + result = await db.execute(delete(OAuthSession).filter_by(user_id=user_id, provider=provider)) await db.commit() return result.rowcount > 0 except Exception as e: diff --git a/backend/open_webui/retrieval/loaders/main.py b/backend/open_webui/retrieval/loaders/main.py index 7a115ca6d7..2daa641bf2 100644 --- a/backend/open_webui/retrieval/loaders/main.py +++ b/backend/open_webui/retrieval/loaders/main.py @@ -400,10 +400,7 @@ class Loader: api_key=self.kwargs.get('MISTRAL_OCR_API_KEY'), file_path=file_path, ) - elif ( - self.engine == 'paddleocr_vl' - and self.kwargs.get('PADDLEOCR_VL_TOKEN') != '' - ): + elif self.engine == 'paddleocr_vl' and self.kwargs.get('PADDLEOCR_VL_TOKEN') != '': loader = PaddleOCRVLLoader( api_url=self.kwargs.get('PADDLEOCR_VL_BASE_URL'), token=self.kwargs.get('PADDLEOCR_VL_TOKEN'), diff --git a/backend/open_webui/retrieval/loaders/paddleocr_vl.py b/backend/open_webui/retrieval/loaders/paddleocr_vl.py index ab7632b3f8..b89369b2a4 100644 --- a/backend/open_webui/retrieval/loaders/paddleocr_vl.py +++ b/backend/open_webui/retrieval/loaders/paddleocr_vl.py @@ -11,6 +11,7 @@ from open_webui.env import GLOBAL_LOG_LEVEL logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) log = logging.getLogger(__name__) + class PaddleOCRVLLoader: """Loader that uses PaddleOCR-vl API to extract text from PDF/images.""" @@ -21,9 +22,9 @@ class PaddleOCRVLLoader: file_path: str, ): if not api_url or not token: - raise ValueError("PaddleOCR-vl API URL and Token are required.") + raise ValueError('PaddleOCR-vl API URL and Token are required.') if not os.path.exists(file_path): - raise FileNotFoundError(f"File not found at {file_path}") + raise FileNotFoundError(f'File not found at {file_path}') self.api_url = api_url.rstrip('/') self.token = token @@ -31,20 +32,17 @@ class PaddleOCRVLLoader: self.file_name = os.path.basename(file_path) def load(self) -> List[Document]: - log.info(f"Processing with PaddleOCR-vl: {self.file_path}") + log.info(f'Processing with PaddleOCR-vl: {self.file_path}') try: - with open(self.file_path, "rb") as file: + with open(self.file_path, 'rb') as file: file_bytes = file.read() - file_data = base64.b64encode(file_bytes).decode("ascii") + file_data = base64.b64encode(file_bytes).decode('ascii') except Exception as e: - log.error(f"Failed to read file {self.file_path}: {e}") + log.error(f'Failed to read file {self.file_path}: {e}') raise - headers = { - "Authorization": f"token {self.token}", - "Content-Type": "application/json" - } + headers = {'Authorization': f'token {self.token}', 'Content-Type': 'application/json'} # Detect fileType based on file extension ext = self.file_path.lower().split('.')[-1] @@ -52,76 +50,76 @@ class PaddleOCRVLLoader: file_type = 1 if ext in image_extensions else 0 payload = { - "file": file_data, - "fileType": file_type, - "useDocOrientationClassify": False, - "useDocUnwarping": False, - "useChartRecognition": False, + 'file': file_data, + 'fileType': file_type, + 'useDocOrientationClassify': False, + 'useDocUnwarping': False, + 'useChartRecognition': False, } try: - response = requests.post(f"{self.api_url}/layout-parsing", json=payload, headers=headers) + response = requests.post(f'{self.api_url}/layout-parsing', json=payload, headers=headers) response.raise_for_status() - - result = response.json().get("result", {}) - layout_results = result.get("layoutParsingResults", []) - + + result = response.json().get('result', {}) + layout_results = result.get('layoutParsingResults', []) + documents = [] total_pages = len(layout_results) skipped_pages = 0 - + for i, res in enumerate(layout_results): - markdown_text = res.get("markdown", {}).get("text", "") - + markdown_text = res.get('markdown', {}).get('text', '') + if isinstance(markdown_text, str): cleaned_content = markdown_text.strip() else: cleaned_content = str(markdown_text).strip() - + if not cleaned_content: skipped_pages += 1 continue - + documents.append( Document( page_content=cleaned_content, metadata={ - "page": i, - "page_label": i + 1, - "total_pages": total_pages, - "file_name": self.file_name, - "processing_engine": "paddleocr-vl" - } + 'page': i, + 'page_label': i + 1, + 'total_pages': total_pages, + 'file_name': self.file_name, + 'processing_engine': 'paddleocr-vl', + }, ) ) - + if skipped_pages > 0: - log.info(f"PaddleOCR-vl: Processed {len(documents)} pages, skipped {skipped_pages} empty pages.") - + log.info(f'PaddleOCR-vl: Processed {len(documents)} pages, skipped {skipped_pages} empty pages.') + if not documents: - log.warning("No valid text content found by PaddleOCR-vl.") + log.warning('No valid text content found by PaddleOCR-vl.') return [ Document( - page_content="No valid text content found in document", + page_content='No valid text content found in document', metadata={ - "error": "no_valid_pages", - "file_name": self.file_name, - "processing_engine": "paddleocr-vl" - } + 'error': 'no_valid_pages', + 'file_name': self.file_name, + 'processing_engine': 'paddleocr-vl', + }, ) ] - + return documents - + except Exception as e: - log.error(f"Error calling PaddleOCR-vl: {e}") + log.error(f'Error calling PaddleOCR-vl: {e}') return [ Document( - page_content=f"Error during OCR processing: {e}", + page_content=f'Error during OCR processing: {e}', metadata={ - "error": "processing_failed", - "file_name": self.file_name, - "processing_engine": "paddleocr-vl" - } + 'error': 'processing_failed', + 'file_name': self.file_name, + 'processing_engine': 'paddleocr-vl', + }, ) ] diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 7cb6ca3681..6d2349f89f 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -877,9 +877,7 @@ async def delete_oauth_session_by_provider( The provider string matches the 'provider' field in the oauth_session table (e.g. 'mcp:server-id' for MCP connections). """ - result = await OAuthSessions.delete_sessions_by_user_id_and_provider( - user.id, provider, db=db - ) + result = await OAuthSessions.delete_sessions_by_user_id_and_provider(user.id, provider, db=db) if not result: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index af5e795511..04d845c3de 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -917,4 +917,3 @@ async def update_tools_user_valves_by_id( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND, ) - diff --git a/backend/open_webui/utils/plugin.py b/backend/open_webui/utils/plugin.py index 5b945749ec..43ff4fe2e7 100644 --- a/backend/open_webui/utils/plugin.py +++ b/backend/open_webui/utils/plugin.py @@ -335,7 +335,9 @@ async def get_tool_module_from_cache(request, tool_id, load_from_db=True): return tool_module, frontmatter -async def get_function_module_from_cache(request, function_id, function: FunctionModel | None = None, load_from_db=True): +async def get_function_module_from_cache( + request, function_id, function: FunctionModel | None = None, load_from_db=True +): if load_from_db: # Always load from the database by default # This is useful for hooks like "inlet" or "outlet" where the content might change diff --git a/src/lib/apis/configs/index.ts b/src/lib/apis/configs/index.ts index b0dd6541ee..6b7bf6f47b 100644 --- a/src/lib/apis/configs/index.ts +++ b/src/lib/apis/configs/index.ts @@ -647,4 +647,3 @@ export const setBanners = async (token: string, banners: Banner[]) => { return res; }; - diff --git a/src/lib/apis/tools/index.ts b/src/lib/apis/tools/index.ts index 1d812b3f0f..5d26e50fee 100644 --- a/src/lib/apis/tools/index.ts +++ b/src/lib/apis/tools/index.ts @@ -483,4 +483,3 @@ export const updateUserValvesById = async (token: string, id: string, valves: ob return res; }; - diff --git a/src/lib/apis/users/index.ts b/src/lib/apis/users/index.ts index 13044c09d5..91b63338de 100644 --- a/src/lib/apis/users/index.ts +++ b/src/lib/apis/users/index.ts @@ -550,4 +550,3 @@ export const getUserGroupsById = async (token: string, userId: string) => { return res; }; - diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index 6416b2d05a..e173c74969 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -1369,12 +1369,13 @@ )} /> -
- {#if RAGConfig.RAG_TEMPLATE && ((RAGConfig.RAG_TEMPLATE.match(/\[context\]/g) || []).length + (RAGConfig.RAG_TEMPLATE.match(/\{\{CONTEXT\}\}/g) || []).length) > 1} + {#if RAGConfig.RAG_TEMPLATE && (RAGConfig.RAG_TEMPLATE.match(/\[context\]/g) || []).length + (RAGConfig.RAG_TEMPLATE.match(/\{\{CONTEXT\}\}/g) || []).length > 1}
- {$i18n.t('This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.')} + {$i18n.t( + 'This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.' + )}
{/if}
diff --git a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte index a62b3a2438..2fc2c4bc5f 100644 --- a/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte +++ b/src/lib/components/chat/MessageInput/IntegrationsMenu.svelte @@ -406,7 +406,7 @@ } }} > - +
diff --git a/src/lib/components/chat/Messages/Message.svelte b/src/lib/components/chat/Messages/Message.svelte index b161aa8556..242e84f459 100644 --- a/src/lib/components/chat/Messages/Message.svelte +++ b/src/lib/components/chat/Messages/Message.svelte @@ -138,4 +138,3 @@ contain-intrinsic-size: auto 150px; } - diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 2acbd0b8a1..748d8de646 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -517,7 +517,7 @@ "Delete a model": "모델 삭제", "Delete All": "모두 삭제", "Delete All Chats": "모든 채팅 삭제", - "Delete all contents inside this folder":"이 폴더 내 모든 콘텐츠 삭제", + "Delete all contents inside this folder": "이 폴더 내 모든 콘텐츠 삭제", "Delete automation?": "자동 삭제하시겠습니까?", "Delete Chat": "채팅 삭제", "Delete chat?": "채팅을 삭제하시겠습니까?", @@ -1350,7 +1350,7 @@ "new-channel": "새 채널", "Next message": "다음 메시지", "Next run": "다음 실행", - "No access grants. Private to you.": "접근 권한이 없습니다. 개인용입니다.", + "No access grants. Private to you.": "접근 권한이 없습니다. 개인용입니다.", "No activity data": "활동 데이터가 없습니다", "No authentication": "권한 인증이 없습니다", "No automations found": "자동화된 항목을 찾을 수 없습니다.", @@ -1697,8 +1697,8 @@ "Search": "검색", "Search a model": "모델 검색", "Search all emojis": "모든 이모지 검색", - "Search and manage user memories":"사용자 기억 검색 및 관리", - "Search and view user chat history":"사용자 채팅 기록 검색 및 보기", + "Search and manage user memories": "사용자 기억 검색 및 관리", + "Search and view user chat history": "사용자 채팅 기록 검색 및 보기", "Search Automations": "자동 검색", "Search Base": "검색 기반", "Search channels and channel messages": "채널 및 채널 메시지 검색", @@ -2003,7 +2003,7 @@ "Tika Server URL required.": "Tika 서버 URL이 필요합니다.", "Tiktoken": "틱토큰 (Tiktoken)", "Time": "시간", - "Time & Calculation":"시간 및 계산", + "Time & Calculation": "시간 및 계산", "Timeout": "시간 초과", "Title": "제목", "Title Auto-Generation": "제목 자동 생성", diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 01d9c10b65..4ba065d44c 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -489,7 +489,10 @@ const displayTitle = title || $i18n.t('New Chat'); if (done) { - if (($settings?.notificationSound ?? true) && ($settings?.notificationSoundAlways ?? false)) { + if ( + ($settings?.notificationSound ?? true) && + ($settings?.notificationSoundAlways ?? false) + ) { playingNotificationSound.set(true); const audio = new Audio(`/audio/notification.mp3`); From f93d20ac425b06d35cf283b2f770f070b600b950 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:48:45 +0900 Subject: [PATCH 403/404] chore: i18n --- src/lib/i18n/locales/ar-BH/translation.json | 10 +- src/lib/i18n/locales/ar/translation.json | 10 +- src/lib/i18n/locales/az-AZ/translation.json | 10 +- src/lib/i18n/locales/bg-BG/translation.json | 10 +- src/lib/i18n/locales/bn-BD/translation.json | 10 +- src/lib/i18n/locales/bo-TB/translation.json | 10 +- src/lib/i18n/locales/bs-BA/translation.json | 10 +- src/lib/i18n/locales/ca-ES/translation.json | 10 +- src/lib/i18n/locales/ceb-PH/translation.json | 10 +- src/lib/i18n/locales/cs-CZ/translation.json | 10 +- src/lib/i18n/locales/da-DK/translation.json | 10 +- src/lib/i18n/locales/de-DE/translation.json | 10 +- src/lib/i18n/locales/dg-DG/translation.json | 10 +- src/lib/i18n/locales/el-GR/translation.json | 10 +- src/lib/i18n/locales/en-GB/translation.json | 10 +- src/lib/i18n/locales/en-US/translation.json | 11 +- src/lib/i18n/locales/es-ES/translation.json | 10 +- src/lib/i18n/locales/et-EE/translation.json | 10 +- src/lib/i18n/locales/eu-ES/translation.json | 10 +- src/lib/i18n/locales/fa-IR/translation.json | 10 +- src/lib/i18n/locales/fi-FI/translation.json | 10 +- src/lib/i18n/locales/fr-CA/translation.json | 10 +- src/lib/i18n/locales/fr-FR/translation.json | 10 +- src/lib/i18n/locales/gl-ES/translation.json | 10 +- src/lib/i18n/locales/he-IL/translation.json | 10 +- src/lib/i18n/locales/hi-IN/translation.json | 10 +- src/lib/i18n/locales/hr-HR/translation.json | 10 +- src/lib/i18n/locales/hu-HU/translation.json | 10 +- src/lib/i18n/locales/id-ID/translation.json | 10 +- src/lib/i18n/locales/ie-GA/translation.json | 10 +- src/lib/i18n/locales/it-IT/translation.json | 10 +- src/lib/i18n/locales/ja-JP/translation.json | 10 +- src/lib/i18n/locales/ka-GE/translation.json | 10 +- src/lib/i18n/locales/kab-DZ/translation.json | 10 +- src/lib/i18n/locales/ko-KR/translation.json | 45 +++++- src/lib/i18n/locales/lt-LT/translation.json | 10 +- src/lib/i18n/locales/lv-LV/translation.json | 10 +- src/lib/i18n/locales/ms-MY/translation.json | 10 +- src/lib/i18n/locales/nb-NO/translation.json | 10 +- src/lib/i18n/locales/nl-NL/translation.json | 134 +++++++++--------- src/lib/i18n/locales/pa-IN/translation.json | 10 +- src/lib/i18n/locales/pl-PL/translation.json | 10 +- src/lib/i18n/locales/pt-BR/translation.json | 10 +- src/lib/i18n/locales/pt-PT/translation.json | 10 +- src/lib/i18n/locales/ro-RO/translation.json | 10 +- src/lib/i18n/locales/ru-RU/translation.json | 10 +- src/lib/i18n/locales/sk-SK/translation.json | 10 +- src/lib/i18n/locales/sr-RS/translation.json | 10 +- src/lib/i18n/locales/sv-SE/translation.json | 10 +- src/lib/i18n/locales/ta-IN/translation.json | 10 +- src/lib/i18n/locales/th-TH/translation.json | 10 +- src/lib/i18n/locales/tk-TM/translation.json | 10 +- src/lib/i18n/locales/tr-TR/translation.json | 10 +- src/lib/i18n/locales/ug-CN/translation.json | 10 +- src/lib/i18n/locales/uk-UA/translation.json | 10 +- src/lib/i18n/locales/ur-PK/translation.json | 10 +- .../i18n/locales/uz-Cyrl-UZ/translation.json | 10 +- .../i18n/locales/uz-Latn-Uz/translation.json | 10 +- src/lib/i18n/locales/vi-VN/translation.json | 10 +- src/lib/i18n/locales/zh-CN/translation.json | 11 +- src/lib/i18n/locales/zh-TW/translation.json | 10 +- 61 files changed, 583 insertions(+), 188 deletions(-) diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index 13e9aed4e9..0e88fb3370 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -62,7 +62,6 @@ "Account Activation Pending": "", "Accurate information": "معلومات دقيقة", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "إجراء مطلوب لتخزين سجل الدردشة", "Actions": "", "Activate": "", @@ -163,7 +162,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "مساعد", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -583,6 +581,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "معطل", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "اكتشف نموذجا", "Discover a prompt": "اكتشاف موجه", @@ -772,6 +771,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "(e.g. 50) أدخل عدد الخطوات", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -902,6 +903,7 @@ "Failed to create API Key.": "فشل في إنشاء مفتاح API.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1456,6 +1458,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "اكتوبر", "Off": "أغلاق", "Okay, Let's Go!": "حسنا دعنا نذهب!", @@ -1522,6 +1525,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2032,6 +2037,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/ar/translation.json b/src/lib/i18n/locales/ar/translation.json index 3eb53e68bd..ab9b78e1ca 100644 --- a/src/lib/i18n/locales/ar/translation.json +++ b/src/lib/i18n/locales/ar/translation.json @@ -62,7 +62,6 @@ "Account Activation Pending": "انتظار تفعيل الحساب", "Accurate information": "معلومات دقيقة", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "إجراء مطلوب لتخزين سجل الدردشة", "Actions": "الإجراءات", "Activate": "تفعيل", @@ -163,7 +162,6 @@ "Always Play Notification Sound": "", "Amazing": "رائع", "an assistant": "مساعد", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "تم التحليل", "Analyzing...": "جارٍ التحليل...", @@ -583,6 +581,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "معطّل", + "Disconnect OAuth": "", "Discover a function": "اكتشف وظيفة", "Discover a model": "اكتشف نموذجا", "Discover a prompt": "اكتشاف موجه", @@ -772,6 +771,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "(e.g. 50) أدخل عدد الخطوات", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "أدخل مفتاح API لـ Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -902,6 +903,7 @@ "Failed to create API Key.": "فشل في إنشاء مفتاح API.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1456,6 +1458,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "معرّف OAuth", + "OAuth session disconnected": "", "October": "اكتوبر", "Off": "أغلاق", "Okay, Let's Go!": "حسنا دعنا نذهب!", @@ -1522,6 +1525,8 @@ "Output format": "تنسيق الإخراج", "Output Format": "", "Overview": "نظرة عامة", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "صفحة", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2032,6 +2037,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "يحدد هذا الخيار الحد الأقصى لعدد الرموز التي يمكن للنموذج توليدها في الرد. زيادته تتيح للنموذج تقديم إجابات أطول، لكنها قد تزيد من احتمالية توليد محتوى غير مفيد أو غير ذي صلة.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "سيؤدي هذا الخيار إلى حذف جميع الملفات الحالية في المجموعة واستبدالها بالملفات التي تم تحميلها حديثًا.", "This response was generated by \"{{model}}\"": "تم توليد هذا الرد بواسطة \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "هذا سيقوم بالحذف", "This will delete {{NAME}} and all its contents.": "هذا سيحذف {{NAME}} وكل محتوياته.", "This will delete all models including custom models": "هذا سيحذف جميع النماذج بما في ذلك النماذج المخصصة", diff --git a/src/lib/i18n/locales/az-AZ/translation.json b/src/lib/i18n/locales/az-AZ/translation.json index 8eec5e5732..1567a0c8a1 100644 --- a/src/lib/i18n/locales/az-AZ/translation.json +++ b/src/lib/i18n/locales/az-AZ/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Hesabın aktivləşdirilməsi gözlənilir", "Accurate information": "Dəqiq məlumat", "Action": "Fəaliyyət", - "Action not found": "Fəaliyyət tapılmadı", "Action Required for Chat Log Storage": "Söhbət tarixçəsinin saxlanılması üçün hərəkət tələb olunur", "Actions": "Fəaliyyətlər", "Activate": "Aktivləşdir", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Bildiriş səsini həmişə çal", "Amazing": "Möhtəşəm", "an assistant": "bir köməkçi", - "An error occurred while fetching the explanation": "İzahı gətirərkən xəta baş verdi", "Analytics": "Analitika", "Analyzed": "Analiz edildi", "Analyzing...": "Analiz edilir...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Şəkil çıxarılmasını söndür", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDF-dən şəkil çıxarılmasını söndürün. 'LLM istifadə et' aktivdirsə, şəkillərə avtomatik altyazı veriləcək. Standart olaraq 'Xeyr' (False) təyin edilib.", "Disabled": "Söndürülüb", + "Disconnect OAuth": "", "Discover a function": "Funksiya kəşf edin", "Discover a model": "Model kəşf edin", "Discover a prompt": "Göstəriş kəşf edin", @@ -768,6 +767,8 @@ "Enter New Password": "Yeni şifrəni daxil edin", "Enter Number of Steps (e.g. 50)": "Addım sayını daxil edin (məs. 50)", "Enter Ollama Cloud API Key": "Ollama Cloud API açarını daxil edin", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity API açarını daxil edin", "Enter Perplexity Search API URL": "Perplexity axtarış API URL-ini daxil edin", "Enter Playwright Timeout": "Playwright vaxt aşımını daxil edin", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API açarı yaradılmadı.", "Failed to delete calendar": "", "Failed to delete note": "Qeyd silinmədi", + "Failed to disconnect": "", "Failed to download image": "Şəkil yüklənmədi", "Failed to extract content from the file: {{error}}": "Fayldan məzmun çıxarıla bilmədi: {{error}}", "Failed to extract content from the file.": "Fayldan məzmun çıxarıla bilmədi.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Oktyabr", "Off": "Bağlı", "Okay, Let's Go!": "Yaxşı, başlayaq!", @@ -1518,6 +1521,8 @@ "Output format": "Çıxış formatı", "Output Format": "Çıxış Formatı", "Overview": "İcmal", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "səhifə", "Page": "Səhifə", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Səhifə rejimi hər səhifə üçün bir sənəd yaradır. Tək rejim isə səhifə sərhədləri arasında daha yaxşı hissələrə ayırma (chunking) üçün bütün səhifələri bir sənəddə birləşdirir.", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Bu seçim modelin cavabında yarada biləcəyi maksimum token sayını təyin edir. Bu limiti artırmaq modelə daha uzun cavablar verməyə imkan verir, lakin faydasız və ya mövzuya aid olmayan məzmunun yaranma ehtimalını da artıra bilər.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Bu seçim kolleksiyadakı bütün mövcud faylları siləcək və onları yeni yüklənmiş fayllarla əvəz edəcək.", "This response was generated by \"{{model}}\"": "Bu cavab \"{{model}}\" tərəfindən yaradılmışdır", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Bu, siləcək:", "This will delete {{NAME}} and all its contents.": "Bu, {{NAME}} adlı elementi və onun bütün məzmununu siləcək.", "This will delete all models including custom models": "Bu, fərdi modellər də daxil olmaqla bütün modelləri siləcək", diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index 685debf883..a08459e7ca 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Активирането на акаунта е в процес на изчакване", "Accurate information": "Точна информация", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Изисква се действие за съхраняване на дневника на чата", "Actions": "Действия", "Activate": "Активиране", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "Невероятно", "an assistant": "асистент", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Анализирано", "Analyzing...": "Анализиране...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Деактивирано", + "Disconnect OAuth": "", "Discover a function": "Открийте функция", "Discover a model": "Открийте модел", "Discover a prompt": "Откриване на промпт", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Въведете брой стъпки (напр. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Неуспешно създаване на API ключ.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "ID на OAuth", + "OAuth session disconnected": "", "October": "Октомври", "Off": "Изкл.", "Okay, Let's Go!": "ОК, Нека започваме!", @@ -1518,6 +1521,8 @@ "Output format": "Изходен формат", "Output Format": "", "Overview": "Преглед", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "страница", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Тази опция ще изтрие всички съществуващи файлове в колекцията и ще ги замени с новокачени файлове.", "This response was generated by \"{{model}}\"": "Този отговор беше генериран от \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Това ще изтрие", "This will delete {{NAME}} and all its contents.": "Това ще изтрие {{NAME}} и цялото му съдържание.", "This will delete all models including custom models": "Това ще изтрие всички модели, включително персонализираните модели", diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index 9437c8a347..d5fd18ed59 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "সঠিক তথ্য", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "চ্যাট লগ সংরক্ষণের জন্য পদক্ষেপ প্রয়োজন", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "একটা এসিস্ট্যান্ট", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "নিষ্ক্রিয়", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "একটি মডেল আবিষ্কার করুন", "Discover a prompt": "একটি প্রম্পট খুঁজে বের করুন", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "ধাপের সংখ্যা দিন (যেমন: 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API Key তৈরি করা যায়নি।", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "অক্টোবর", "Off": "বন্ধ", "Okay, Let's Go!": "ঠিক আছে, চলুন যাই!", @@ -1518,6 +1521,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/bo-TB/translation.json b/src/lib/i18n/locales/bo-TB/translation.json index a65771c7b5..0f343ac5fd 100644 --- a/src/lib/i18n/locales/bo-TB/translation.json +++ b/src/lib/i18n/locales/bo-TB/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "རྩིས་ཁྲ་སྒུལ་བསྐྱོད་སྒུག་བཞིན་པ།", "Accurate information": "གནས་ཚུལ་ཡང་དག", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "ཁ་བསྡམས་ཟིན་ཐོ་ཉར་ཚགས་ལ་བྱ་བ་དགོས།", "Actions": "བྱ་སྤྱོད།", "Activate": "སྒུལ་བསྐྱོད།", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "", "Amazing": "ངོ་མཚར་ཆེན།", "an assistant": "ལག་རོགས་པ།", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "དབྱེ་ཞིབ་བྱས་པ།", "Analyzing...": "དབྱེ་ཞིབ་བྱེད་བཞིན་པ།...", @@ -578,6 +576,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "ནུས་མེད།", + "Disconnect OAuth": "", "Discover a function": "ལས་འགན་ཞིག་རྙེད་པ།", "Discover a model": "དཔེ་དབྱིབས་ཤིག་རྙེད་པ།", "Discover a prompt": "འགུལ་སློང་ཞིག་རྙེད་པ།", @@ -767,6 +766,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "གོམ་གྲངས་འཇུག་པ། (དཔེར་ན། ༥༠)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity API ལྡེ་མིག་འཇུག་པ།", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -897,6 +898,7 @@ "Failed to create API Key.": "API ལྡེ་མིག་བཟོ་མ་ཐུབ།", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1451,6 +1453,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "ཟླ་བ་བཅུ་པ།", "Off": "ཁ་རྒྱག་པ།", "Okay, Let's Go!": "འགྲིག་སོང་། འགྲོ།", @@ -1517,6 +1520,8 @@ "Output format": "ཐོན་འབྲས་ཀྱི་བཀོད་པ།", "Output Format": "", "Overview": "སྤྱི་མཐོང་།", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "ཤོག་ངོས།", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2017,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "འདེམས་ཀ་འདིས་དཔེ་དབྱིབས་ཀྱིས་དེའི་ལན་ནང་བཟོ་ཐུབ་པའི་ཊོཀ་ཀེན་གྱི་གྲངས་མང་ཤོས་འཇོག་པ། ཚད་བཀག་འདི་མང་དུ་བཏང་ན་དཔེ་དབྱིབས་ཀྱིས་ལན་རིང་བ་སྤྲོད་པར་གནང་བ་སྤྲོད། འོན་ཀྱང་དེས་ཕན་ཐོགས་མེད་པའམ་འབྲེལ་མེད་ཀྱི་ནང་དོན་བཟོ་བའི་ཆགས་ཚུལ་མང་དུ་གཏོང་སྲིད།", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "འདེམས་ཀ་འདིས་བསྡུ་གསོག་ནང་གི་ཡོད་པའི་ཡིག་ཆ་ཡོངས་རྫོགས་བསུབ་ནས་དེ་དག་གསར་དུ་སྤར་བའི་ཡིག་ཆས་ཚབ་བྱེད་ངེས།", "This response was generated by \"{{model}}\"": "ལན་འདི་ \"{{model}}\" ཡིས་བཟོས་པ།", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "འདིས་བསུབ་ངེས།", "This will delete {{NAME}} and all its contents.": "འདིས་ {{NAME}} དང་ དེའི་ནང་དོན་ཡོངས་རྫོགས་ བསུབ་ངེས།", "This will delete all models including custom models": "འདིས་སྲོལ་བཟོས་དཔེ་དབྱིབས་ཚུད་པའི་དཔེ་དབྱིབས་ཡོངས་རྫོགས་བསུབ་ངེས།", diff --git a/src/lib/i18n/locales/bs-BA/translation.json b/src/lib/i18n/locales/bs-BA/translation.json index d28abefd59..fe02a9b08d 100644 --- a/src/lib/i18n/locales/bs-BA/translation.json +++ b/src/lib/i18n/locales/bs-BA/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "", "Accurate information": "Tačne informacije", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Potrebna je radnja za pohranu zapisnika razgovora", "Actions": "", "Activate": "", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "asistent", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "Analiziranje ... ", @@ -580,6 +578,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Onemogućeno", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "Otkrijte model", "Discover a prompt": "Otkrijte prompt", @@ -769,6 +768,8 @@ "Enter New Password": "Unesite Novu Sifru", "Enter Number of Steps (e.g. 50)": "Unesite broj koraka (npr. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Neuspješno stvaranje API ključa.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "Oktobar", "Off": "Isključeno", "Okay, Let's Go!": "U redu, idemo!", @@ -1519,6 +1522,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index a3793e5e42..4db97a3ca2 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Activació del compte pendent", "Accurate information": "Informació precisa", "Action": "Acció", - "Action not found": "Acció no trobada", "Action Required for Chat Log Storage": "Cal una acció per desar el registre del xat", "Actions": "Accions", "Activate": "Activar", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Reproduir sempre un so de notificació", "Amazing": "Al·lucinant", "an assistant": "un assistent", - "An error occurred while fetching the explanation": "S'ha produït un error mentre s'obtenia l'explicació", "Analytics": "Analítica", "Analyzed": "Analitzat", "Analyzing...": "Analitzant...", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Deshabilitar l'extracció d'imatges", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Desactiva l'extracció d'imatges del PDF. Si Utilitza LLM està habilitat, les imatges es descriuran automàticament. Per defecte és Fals.", "Disabled": "Deshabilitat", + "Disconnect OAuth": "", "Discover a function": "Descobrir una funció", "Discover a model": "Descobrir un model", "Discover a prompt": "Descobrir una indicació", @@ -769,6 +768,8 @@ "Enter New Password": "Introdueix un nova contrasenya", "Enter Number of Steps (e.g. 50)": "Introdueix el nombre de passos (p. ex. 50)", "Enter Ollama Cloud API Key": "Introdueix la clau API de Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Introdueix la clau API de Perplexity", "Enter Perplexity Search API URL": "Introduïu l'URL de l'API de cerca de Perplexity", "Enter Playwright Timeout": "Introdueix el temps d'espera de Playwright", @@ -899,6 +900,7 @@ "Failed to create API Key.": "No s'ha pogut crear la clau API.", "Failed to delete calendar": "", "Failed to delete note": "No s'ha pogut eliminar la nota", + "Failed to disconnect": "", "Failed to download image": "No s'ha pogut descarregar la imatge", "Failed to extract content from the file: {{error}}": "No s'ha pogut extreure el contingut del fitxer: {{error}}", "Failed to extract content from the file.": "No s'ha pogut extreure el contingut del fitxer", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Estàtic)", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Octubre", "Off": "Desactivat", "Okay, Let's Go!": "D'acord, som-hi!", @@ -1519,6 +1522,8 @@ "Output format": "Format de sortida", "Output Format": "Format de sortida", "Overview": "Vista general", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "pàgina", "Page": "Pàgina", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "El mode de pàgina crea un document per pàgina. El mode únic combina totes les pàgines en un sol document per a una millor segmentació entre els límits de les pàgines.", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Aquesta opció estableix el nombre màxim de tokens que el model pot generar en la seva resposta. Augmentar aquest límit permet que el model proporcioni respostes més llargues, però també pot augmentar la probabilitat que es generi contingut poc útil o irrellevant.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Aquesta opció eliminarà tots els fitxers existents de la col·lecció i els substituirà per fitxers recentment penjats.", "This response was generated by \"{{model}}\"": "Aquesta resposta l'ha generat el model \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Això eliminarà", "This will delete {{NAME}} and all its contents.": "Això eliminarà {{NAME}} i tots els continguts.", "This will delete all models including custom models": "Això eliminarà tots els models incloent els personalitzats", diff --git a/src/lib/i18n/locales/ceb-PH/translation.json b/src/lib/i18n/locales/ceb-PH/translation.json index d1278ac30b..9028e5339a 100644 --- a/src/lib/i18n/locales/ceb-PH/translation.json +++ b/src/lib/i18n/locales/ceb-PH/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Gikinahanglan ang aksyon aron matipigan ang chat log", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "usa ka katabang", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Gipalong", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "", "Discover a prompt": "Pagkaplag usa ka prompt", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Pagsulod sa gidaghanon sa mga lakang (e.g. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "", "Off": "Napuo", "Okay, Let's Go!": "Okay, lakaw na!", @@ -1518,6 +1521,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/cs-CZ/translation.json b/src/lib/i18n/locales/cs-CZ/translation.json index a787579837..3cbab3a4b0 100644 --- a/src/lib/i18n/locales/cs-CZ/translation.json +++ b/src/lib/i18n/locales/cs-CZ/translation.json @@ -60,7 +60,6 @@ "Account Activation Pending": "Čeká se na aktivaci účtu", "Accurate information": "Přesné informace", "Action": "Akce", - "Action not found": "Akce nenalezena", "Action Required for Chat Log Storage": "Je vyžadována akce pro uložení záznamu chatu", "Actions": "Akce", "Activate": "Aktivovat", @@ -161,7 +160,6 @@ "Always Play Notification Sound": "Vždy přehrát zvuk oznámení", "Amazing": "Úžasné", "an assistant": "asistent", - "An error occurred while fetching the explanation": "Při načítání vysvětlení došlo k chybě", "Analytics": "Analytika", "Analyzed": "Analyzováno", "Analyzing...": "Analyzuji...", @@ -581,6 +579,7 @@ "Disable Image Extraction": "Zakázat extrakci obrázků", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Zakázat extrakci obrázků z PDF. Pokud je povoleno Použít LLM, obrázky budou automaticky opatřeny popisky. Výchozí hodnota je False.", "Disabled": "Zakázáno", + "Disconnect OAuth": "", "Discover a function": "Objevit funkci", "Discover a model": "Objevit model", "Discover a prompt": "Objevit instrukci", @@ -770,6 +769,8 @@ "Enter New Password": "Zadejte nové heslo", "Enter Number of Steps (e.g. 50)": "Zadejte počet kroků (např. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Zadejte API klíč pro Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Zadejte časový limit pro Playwright", @@ -900,6 +901,7 @@ "Failed to create API Key.": "Nepodařilo se vytvořit API klíč.", "Failed to delete calendar": "", "Failed to delete note": "Nepodařilo se smazat poznámku", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Nepodařilo se extrahovat obsah ze souboru: {{error}}", "Failed to extract content from the file.": "Nepodařilo se extrahovat obsah ze souboru.", @@ -1454,6 +1456,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Říjen", "Off": "Vypnuto", "Okay, Let's Go!": "Dobře, jdeme na to!", @@ -1520,6 +1523,8 @@ "Output format": "Formát výstupu", "Output Format": "Formát výstupu", "Overview": "Přehled", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "stránka", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2026,6 +2031,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Tato možnost nastavuje maximální počet tokenů, které může model vygenerovat ve své odpovědi. Zvýšení tohoto limitu umožňuje modelu poskytovat delší odpovědi, ale může také zvýšit pravděpodobnost generování neužitečného nebo irelevantního obsahu.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Tato volba smaže všechny existující soubory v kolekci a nahradí je nově nahranými soubory.", "This response was generated by \"{{model}}\"": "Tato odpověď byla vygenerována modelem \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Tím se smaže", "This will delete {{NAME}} and all its contents.": "Tím se smaže {{NAME}} a veškerý jeho obsah.", "This will delete all models including custom models": "Tím se smažou všechny modely včetně vlastních modelů", diff --git a/src/lib/i18n/locales/da-DK/translation.json b/src/lib/i18n/locales/da-DK/translation.json index cde38de62f..ee31431f81 100644 --- a/src/lib/i18n/locales/da-DK/translation.json +++ b/src/lib/i18n/locales/da-DK/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Aktivering af profil afventer", "Accurate information": "Profilinformation", "Action": "Handling", - "Action not found": "Handling ikke fundet", "Action Required for Chat Log Storage": "Handling påkrævet for lagring af chatlog", "Actions": "Handlinger", "Activate": "Aktiver", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Afspil altid notifikationslyde", "Amazing": "Fantastisk", "an assistant": "en assistent", - "An error occurred while fetching the explanation": "En fejl opstod under hentning af forklaringen", "Analytics": "Analytics", "Analyzed": "Analyseret", "Analyzing...": "Analyserer...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Deaktiver billedudtrækning", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Deaktiver billedudtrækning fra PDF'en. Hvis Use LLM er aktiveret, vil billeder automatisk få undertekster. Standard er False.", "Disabled": "Deaktiveret", + "Disconnect OAuth": "", "Discover a function": "Find en funktion", "Discover a model": "Find en model", "Discover a prompt": "Find en prompt", @@ -768,6 +767,8 @@ "Enter New Password": "Indtast ny adgangskode", "Enter Number of Steps (e.g. 50)": "Indtast antal trin (f.eks. 50)", "Enter Ollama Cloud API Key": "Indtast Ollama Cloud API nøgle", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Indtast Perplexity API nøgle", "Enter Perplexity Search API URL": "Indtast Perplexity Search API URL", "Enter Playwright Timeout": "Indtast Playwright timeout", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Kunne ikke oprette API-nøgle.", "Failed to delete calendar": "", "Failed to delete note": "Kunne ikke slette note", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Kunne ikke udtrække indhold fra filen: {{error}}", "Failed to extract content from the file.": "Kunne ikke udtrække indhold fra filen.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth-ID", + "OAuth session disconnected": "", "October": "Oktober", "Off": "Fra", "Okay, Let's Go!": "Okay, lad os komme i gang!", @@ -1518,6 +1521,8 @@ "Output format": "Outputformat", "Output Format": "Output format", "Overview": "Oversigt", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "side", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Denne indstilling sætter det maksimale antal tokens modellen kan generere i sit svar. At øge denne grænse tillader modellen at give længere svar, men det kan også øge sandsynligheden for at unyttigt eller irrelevant indhold genereres.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Denne indstilling sletter alle eksisterende filer i samlingen og erstatter dem med nyligt uploadede filer.", "This response was generated by \"{{model}}\"": "Dette svar blev genereret af \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Dette vil slette", "This will delete {{NAME}} and all its contents.": "Dette vil slette {{NAME}} og alt dens indhold.", "This will delete all models including custom models": "Dette vil slette alle modeller, inklusive brugerdefinerede modeller", diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index aec1910274..20abba53a8 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Kontoaktivierung ausstehend", "Accurate information": "Präzise Informationen", "Action": "Aktion", - "Action not found": "Aktion nicht gefunden", "Action Required for Chat Log Storage": "Handlung erforderlich: Speicherung des Chat-Protokolls", "Actions": "Aktionen", "Activate": "Aktivieren", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Benachrichtigungston immer abspielen", "Amazing": "Fantastisch", "an assistant": "ein Assistent", - "An error occurred while fetching the explanation": "Beim Abrufen der Erklärung ist ein Fehler aufgetreten", "Analytics": "Analyse", "Analyzed": "Analysiert", "Analyzing...": "Analysiere...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Bildextraktion deaktivieren", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Deaktiviert Bildextraktion aus PDFs. Wenn 'LLM verwenden' aktiv ist, werden Bilder automatisch beschriftet. Standard: False.", "Disabled": "Deaktiviert", + "Disconnect OAuth": "", "Discover a function": "Funktion entdecken", "Discover a model": "Modell entdecken", "Discover a prompt": "Prompt entdecken", @@ -768,6 +767,8 @@ "Enter New Password": "Neues Passwort eingeben", "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 PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity API-Schlüssel eingeben", "Enter Perplexity Search API URL": "Perplexity Search API-URL eingeben", "Enter Playwright Timeout": "Playwright-Timeout eingeben", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API-Schlüssel konnte nicht erstellt werden.", "Failed to delete calendar": "", "Failed to delete note": "Notiz konnte nicht gelöscht werden", + "Failed to disconnect": "", "Failed to download image": "Bild konnte nicht heruntergeladen werden", "Failed to extract content from the file: {{error}}": "Inhaltsextraktion fehlgeschlagen: {{error}}", "Failed to extract content from the file.": "Inhaltsextraktion fehlgeschlagen.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Statisch)", "OAuth ID": "OAuth-ID", + "OAuth session disconnected": "", "October": "Oktober", "Off": "Aus", "Okay, Let's Go!": "Okay, los geht's!", @@ -1518,6 +1521,8 @@ "Output format": "Ausgabeformat", "Output Format": "Ausgabeformat", "Overview": "Übersicht", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "Seite", "Page": "Seite", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Der Seitenmodus erstellt ein Dokument pro Seite. Der Einzelmodus fasst alle Seiten zu einem Dokument zusammen, um besser über Seitenumbrüche hinweg zu chunking/segmentieren.", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Diese Option legt die maximale Anzahl von Token fest, die das Modell generieren darf. Ein höheres Limit ermöglicht längere Antworten, kann aber auch die Wahrscheinlichkeit für irrelevante Inhalte erhöhen.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Diese Option löscht alle vorhandenen Dateien in der Sammlung und ersetzt sie durch die neu hochgeladenen Dateien.", "This response was generated by \"{{model}}\"": "Diese Antwort wurde von \"{{model}}\" generiert", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Dies löscht", "This will delete {{NAME}} and all its contents.": "Dies löscht {{NAME}} und alle Inhalte.", "This will delete all models including custom models": "Dies löscht alle Modelle, einschließlich benutzerdefinierter Modelle", diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index b4a402abac..ff98cd2b3b 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Much action require for chat log storage", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "such assistant", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Disabled sad", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "", "Discover a prompt": "Discover a prompt", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Enter Number of Steps (e.g. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "", "Off": "Off", "Okay, Let's Go!": "Okay, Let's Go!", @@ -1518,6 +1521,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/el-GR/translation.json b/src/lib/i18n/locales/el-GR/translation.json index 22391542aa..e5e0701f19 100644 --- a/src/lib/i18n/locales/el-GR/translation.json +++ b/src/lib/i18n/locales/el-GR/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Ενεργοποίηση Λογαριασμού Εκκρεμεί", "Accurate information": "Ακριβείς πληροφορίες", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Απαιτείται ενέργεια για την αποθήκευση του αρχείου συνομιλίας", "Actions": "Ενέργειες", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Πάντα να αναπαράγετε ο ήχος ειδοποίησης", "Amazing": "Καταπληκτικό", "an assistant": "ένας βοηθός", - "An error occurred while fetching the explanation": "", "Analytics": "Αναλυτικά", "Analyzed": "Αναλυμένα", "Analyzing...": "Ανάλυση...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Απενεργοποιημένο", + "Disconnect OAuth": "", "Discover a function": "Ανακάλυψη λειτουργίας", "Discover a model": "Ανακάλυψη μοντέλου", "Discover a prompt": "Ανακάλυψη προτροπής", @@ -768,6 +767,8 @@ "Enter New Password": "Εισάγετε νέο κωδικό", "Enter Number of Steps (e.g. 50)": "Εισάγετε τον Αριθμό Βημάτων (π.χ. 50)", "Enter Ollama Cloud API Key": "Εισάγετε το Κλειδί API Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Εισάγετε το Κλειδί API Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Εισάγετε το χρονικό όριο του Playwright", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Αποτυχία δημιουργίας Κλειδιού API.", "Failed to delete calendar": "", "Failed to delete note": "Αποτυχία διαγραφής σημειώσεως", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Οκτώβριος", "Off": "Ανενεργό", "Okay, Let's Go!": "Εντάξει, Πάμε!", @@ -1518,6 +1521,8 @@ "Output format": "Μορφή εξόδου", "Output Format": "Μορφή Εξόδου", "Overview": "Επισκόπηση", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "σελίδα", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Αυτή η επιλογή θα διαγράψει όλα τα υπάρχοντα αρχεία στη συλλογή και θα τα αντικαταστήσει με νέα ανεβασμένα αρχεία.", "This response was generated by \"{{model}}\"": "Αυτή η απάντηση δημιουργήθηκε από \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Αυτό θα διαγράψει", "This will delete {{NAME}} and all its contents.": "Αυτό θα διαγράψει το {{NAME}} και όλο το περιεχόμενό του.", "This will delete all models including custom models": "Αυτό θα διαγράψει όλα τα μοντέλα, συμπεριλαμβανομένων των προσαρμοσμένων μοντέλων", diff --git a/src/lib/i18n/locales/en-GB/translation.json b/src/lib/i18n/locales/en-GB/translation.json index 88cfb9a311..390ff5ccce 100644 --- a/src/lib/i18n/locales/en-GB/translation.json +++ b/src/lib/i18n/locales/en-GB/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Analysed", "Analyzing...": "Analysing", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "", "Discover a prompt": "", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "", "Off": "", "Okay, Let's Go!": "", @@ -1518,6 +1521,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index 36ad93ad61..fa95605898 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "", "Discover a prompt": "", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -775,8 +776,6 @@ "Enter prompt here.": "", "Enter proxy URL (e.g. https://user:password@host:port)": "", "Enter reasoning effort": "", - "Enter PaddleOCR-vl API Token": "", - "Enter PaddleOCR-vl API Base URL": "", "Enter Score": "", "Enter SearchApi API Key": "", "Enter SearchApi Engine": "", @@ -900,6 +899,7 @@ "Failed to create API Key.": "", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1454,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "", "Off": "", "Okay, Let's Go!": "", @@ -1521,6 +1522,7 @@ "Output Format": "", "Overview": "", "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 2f44afcee4..3b601af36b 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Activación de cuenta Pendiente", "Accurate information": "Información precisa", "Action": "Acción", - "Action not found": "Acción no encontrada", "Action Required for Chat Log Storage": "Se requiere acción para almacenar el registro del chat", "Actions": "Acciones", "Activate": "Activar", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Reproducir Siempre Sonido de Notificación", "Amazing": "Emocionante", "an assistant": "un asistente", - "An error occurred while fetching the explanation": "Se ha producido un error al obtener la explicación", "Analytics": "Analíticas", "Analyzed": "Analizado", "Analyzing...": "Analizando..", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Deshabilitar Extracción de Imágenes", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Desabilita la extracción de imágenes del pdf. Si está habilitado Usar LLM las imágenes se capturan automáticamente. Por defecto el valor es Falso (las imágenes se extraen).", "Disabled": "Deshabilitado", + "Disconnect OAuth": "", "Discover a function": "Descubrir Funciónes", "Discover a model": "Descubrir Modelos", "Discover a prompt": "Descubrir Indicadores", @@ -769,6 +768,8 @@ "Enter New Password": "Ingresar Contraseña Nueva", "Enter Number of Steps (e.g. 50)": "Ingresar Número de Pasos (p.ej., 50)", "Enter Ollama Cloud API Key": "Ingresar Clave API de Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Ingresar Clave API de Perplexity", "Enter Perplexity Search API URL": "Ingresar URL API para la Búsqueda de Perplexity", "Enter Playwright Timeout": "Ingresar límite de tiempo de espera de Playwright", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Fallo al crear la Clave API.", "Failed to delete calendar": "", "Failed to delete note": "Fallo al eliminar nota", + "Failed to disconnect": "", "Failed to download image": "Fallo al descargar imagen", "Failed to extract content from the file: {{error}}": "Fallo al extraer el contenido del archivo: {{error}}", "Failed to extract content from the file.": "Fallo al extraer el contenido del archivo.", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Estático)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Octubre", "Off": "Desactivado", "Okay, Let's Go!": "Vale, ¡Vamos!", @@ -1519,6 +1522,8 @@ "Output format": "Formato de salida", "Output Format": "Formato de Salida", "Overview": "Vista General", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "página", "Page": "Página", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "El modo Página crea un documento por página. El modo Individual combina todas las páginas en un solo documento para una mejor segmentación entre páginas.", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Esta opción establece el número máximo de tokens que el modelo puede generar en sus respuestas. Aumentar este límite permite al modelo proporcionar respuestas más largas, pero también puede aumentar la probabilidad de que se genere contenido inútil o irrelevante.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Esta opción eliminará todos los archivos existentes en la colección y los reemplazará con los nuevos archivos subidos.", "This response was generated by \"{{model}}\"": "Esta respuesta fue generada por \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Esto eliminará", "This will delete {{NAME}} and all its contents.": "Esto eliminará {{NAME}} y todo su contenido.", "This will delete all models including custom models": "Esto eliminará todos los modelos, incluidos los modelos personalizados", diff --git a/src/lib/i18n/locales/et-EE/translation.json b/src/lib/i18n/locales/et-EE/translation.json index a0ce487ea6..1513f577e5 100644 --- a/src/lib/i18n/locales/et-EE/translation.json +++ b/src/lib/i18n/locales/et-EE/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Konto aktiveerimine ootel", "Accurate information": "Täpne informatsioon", "Action": "Toiming", - "Action not found": "Toimingut ei leitud", "Action Required for Chat Log Storage": "Vestluse logi salvestamiseks on vaja toimingut", "Actions": "Toimingud", "Activate": "Aktiveeri", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Esita teavitusheli alati", "Amazing": "Suurepärane", "an assistant": "assistent", - "An error occurred while fetching the explanation": "Selgituse toomisel tekkis viga", "Analytics": "Analüütika", "Analyzed": "Analüüsitud", "Analyzing...": "Analüüsimine...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Keela piltide väljavõte", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Keela piltide eraldamine PDF-ist. Kui 'Kasuta LLM-i' on lubatud, lisatakse piltidele automaatselt pealdised. Vaikimisi välja lülitatud.", "Disabled": "Keelatud", + "Disconnect OAuth": "", "Discover a function": "Avasta funktsioon", "Discover a model": "Avasta mudel", "Discover a prompt": "Avasta sisend", @@ -768,6 +767,8 @@ "Enter New Password": "Sisestage uus parool", "Enter Number of Steps (e.g. 50)": "Sisestage sammude arv (nt 50)", "Enter Ollama Cloud API Key": "Sisestage Ollama Cloud API võti", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Sisestage Perplexity API võti", "Enter Perplexity Search API URL": "Sisestage Perplexity Search API URL", "Enter Playwright Timeout": "Sisestage Playwright aegumine", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API võtme loomine ebaõnnestus.", "Failed to delete calendar": "", "Failed to delete note": "Märkme kustutamine ebaõnnestus", + "Failed to disconnect": "", "Failed to download image": "Pildi allalaadimine ebaõnnestus", "Failed to extract content from the file: {{error}}": "Failist sisu eraldamine ebaõnnestus: {{error}}", "Failed to extract content from the file.": "Failist sisu eraldamine ebaõnnestus.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Oktoober", "Off": "Väljas", "Okay, Let's Go!": "Hea küll, lähme!", @@ -1518,6 +1521,8 @@ "Output format": "Väljundformaat", "Output Format": "Väljundformaat", "Overview": "Ülevaade", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "leht", "Page": "Leht", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Lehe režiim loob ühe dokumendi lehe kohta. Üksikrežiim ühendab kõik lehed üheks dokumendiks parema tükeldamise jaoks üle lehepiiride.", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "See valik määrab maksimaalse tokenite arvu, mida mudel saab oma vastuses genereerida. Selle piirmäära suurendamine võimaldab mudelil anda pikemaid vastuseid, kuid võib suurendada ka ebavajaliku või ebaolulise sisu genereerimise tõenäosust.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "See valik kustutab kõik olemasolevad failid kogust ja asendab need äsja üleslaaditud failidega.", "This response was generated by \"{{model}}\"": "Selle vastuse genereeris \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "See kustutab", "This will delete {{NAME}} and all its contents.": "See kustutab {{NAME}} ja kogu selle sisu.", "This will delete all models including custom models": "See kustutab kõik mudelid, sealhulgas kohandatud mudelid", diff --git a/src/lib/i18n/locales/eu-ES/translation.json b/src/lib/i18n/locales/eu-ES/translation.json index bbb86b2023..bd36a6aded 100644 --- a/src/lib/i18n/locales/eu-ES/translation.json +++ b/src/lib/i18n/locales/eu-ES/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Kontuaren Aktibazioa Zain", "Accurate information": "Informazio zehatza", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Txataren erregistroa gordetzeko ekintza behar da", "Actions": "Ekintzak", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "Harrigarria", "an assistant": "laguntzaile bat", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Desgaituta", + "Disconnect OAuth": "", "Discover a function": "Aurkitu funtzio bat", "Discover a model": "Aurkitu eredu bat", "Discover a prompt": "Aurkitu prompt bat", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Sartu Urrats Kopurua (adib. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Huts egin du API Gakoa sortzean.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Urria", "Off": "Itzalita", "Okay, Let's Go!": "Ados, Goazen!", @@ -1518,6 +1521,8 @@ "Output format": "Irteera formatua", "Output Format": "", "Overview": "Ikuspegi orokorra", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "orria", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Aukera honek bilduman dauden fitxategi guztiak ezabatuko ditu eta berriki kargatutako fitxategiekin ordezkatuko ditu.", "This response was generated by \"{{model}}\"": "Erantzun hau \"{{model}}\" modeloak sortu du", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Honek ezabatuko du", "This will delete {{NAME}} and all its contents.": "Honek {{NAME}} eta bere eduki guztiak ezabatuko ditu.", "This will delete all models including custom models": "Honek modelo guztiak ezabatuko ditu, modelo pertsonalizatuak barne", diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index 39de7bb016..4b4c53f9cf 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "فعال\u200cسازی حساب در حال انتظار", "Accurate information": "اطلاعات دقیق", "Action": "عملیات", - "Action not found": "عملیات یافت نشد", "Action Required for Chat Log Storage": "برای ذخیره گزارش گفت\u200cوگو اقدام لازم است", "Actions": "کنش\u200cها", "Activate": "فعال کردن", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "همیشه صدای اعلان پخش شود", "Amazing": "شگفت\u200cانگیز", "an assistant": "یک دستیار", - "An error occurred while fetching the explanation": "هنگام واکشی توضیح خطایی رخ داد", "Analytics": "تحلیل و بررسی", "Analyzed": "تحلیل شده", "Analyzing...": "در حال تحلیل...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "غیرفعال کردن استخراج تصویر", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "غیرفعال کردن استخراج تصویر از PDF. اگر «استفاده از LLM» فعال باشد، تصاویر به\u200cطور خودکار زیرنویس خواهند شد. پیش\u200cفرض: False.", "Disabled": "غیرفعال", + "Disconnect OAuth": "", "Discover a function": "کشف یک تابع", "Discover a model": "کشف یک مدل", "Discover a prompt": "یک اعلان را کشف کنید", @@ -768,6 +767,8 @@ "Enter New Password": "رمز عبور جدید را وارد کنید", "Enter Number of Steps (e.g. 50)": "تعداد گام\u200cها را وارد کنید (مثال: 50)", "Enter Ollama Cloud API Key": "کلید API ابری اُلاما را وارد کنید", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "کلید API پرپلکسیتی را وارد کنید", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "مهلت پلی\u200cرایت را وارد کنید", @@ -898,6 +899,7 @@ "Failed to create API Key.": "ایجاد کلید API با خطا مواجه شد.", "Failed to delete calendar": "", "Failed to delete note": "حذف یادداشت ناموفق بود", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "استخراج محتوا از فایل ناموفق بود: {{error}}", "Failed to extract content from the file.": "استخراج محتوا از فایل ناموفق بود.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "شناسه OAuth", + "OAuth session disconnected": "", "October": "اکتبر", "Off": "خاموش", "Okay, Let's Go!": "باشه، بزن بریم!", @@ -1518,6 +1521,8 @@ "Output format": "قالب خروجی", "Output Format": "قالب خروجی", "Overview": "نمای کلی", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "صفحه", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "این گزینه حداکثر تعداد توکن\u200cهایی را که مدل می\u200cتواند در پاسخ خود تولید کند تنظیم می\u200cکند. افزایش این محدودیت به مدل اجازه می\u200cدهد پاسخ\u200cهای طولانی\u200cتری ارائه دهد، اما ممکن است احتمال تولید محتوای بی\u200cفایده یا نامربوط را نیز افزایش دهد.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "این گزینه تمام فایل\u200cهای موجود در مجموعه را حذف کرده و با فایل\u200cهای جدید آپلود شده جایگزین می\u200cکند.", "This response was generated by \"{{model}}\"": "این پاسخ توسط \"{{model}}\" تولید شده است", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "این حذف خواهد شد", "This will delete {{NAME}} and all its contents.": "این {{NAME}} و تمام محتویات آن را حذف خواهد کرد.", "This will delete all models including custom models": "این همه مدل\u200cها از جمله مدل\u200cهای سفارشی را حذف خواهد کرد", diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index c21491242b..fcd2c7cefe 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Tilin aktivointi odottaa", "Accurate information": "Tarkkaa tietoa", "Action": "Toiminto", - "Action not found": "Toimintoa ei löytynyt", "Action Required for Chat Log Storage": "Toiminto vaaditaan keskustelulokin tallentamiseksi", "Actions": "Toiminnot", "Activate": "Aktivoi", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Toista aina ilmoitusääni", "Amazing": "Hämmästyttävä", "an assistant": "avustaja", - "An error occurred while fetching the explanation": "Tapahtui virhe hakiessa selitystä", "Analytics": "Analytiikka", "Analyzed": "Analysoitu", "Analyzing...": "Analysoidaan..", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Poista kuvien poiminta käytöstä", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Poista kuvien poiminta käytöstä PDF tiedostoista. Jos LLM on käytössä, kuvat tekstitetään automaattisesti. Oletuksena ei käytössä.", "Disabled": "Ei käytössä", + "Disconnect OAuth": "", "Discover a function": "Löydä toiminto", "Discover a model": "Tutustu malliin", "Discover a prompt": "Löydä kehote", @@ -768,6 +767,8 @@ "Enter New Password": "Kirjoita uusi salasana", "Enter Number of Steps (e.g. 50)": "Kirjoita askelten määrä (esim. 50)", "Enter Ollama Cloud API Key": "Kirjoita Ollama Cloud API avain", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Aseta Perplexity API-avain", "Enter Perplexity Search API URL": "Aseta Perplexity Search API verkko-osoite", "Enter Playwright Timeout": "Aseta Playwright aikakatkaisu", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API-avaimen luonti epäonnistui.", "Failed to delete calendar": "Kalenterin poistaminen epäonnistui", "Failed to delete note": "Muistiinpanon poistaminen epäonnistui", + "Failed to disconnect": "", "Failed to download image": "Kuvan lataaminen epäonnistui", "Failed to extract content from the file: {{error}}": "Tiedoston sisällön pomiminen epäonnistui: {{error}}", "Failed to extract content from the file.": "Tiedoston sisällön pomiminen epäonnistui.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Staattinen)", "OAuth ID": "OAuth-tunnus", + "OAuth session disconnected": "", "October": "lokakuu", "Off": "Pois päältä", "Okay, Let's Go!": "Okei, mennään!", @@ -1518,6 +1521,8 @@ "Output format": "Tulosteen muoto", "Output Format": "Tulosteen muoto", "Overview": "Yleiskatsaus", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "sivu", "Page": "Sivu", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Sivutila luo yhden dokumentin sivua kohden. Yksittäistila yhdistää kaikki sivut yhdeksi dokumentiksi, mikä parantaa paloittelua sivurajojen yli.", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Tämä vaihtoehto asettaa mallin vastauksessaan luomien tokenien enimmäismäärän. Tämän rajan nostaminen antaa mallille mahdollisuuden tarjota pidempiä vastauksia, mutta se voi myös lisätä hyödyttömän tai epäolennaisen sisällön luomisen todennäköisyyttä.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Tämä vaihtoehto poistaa kaikki kokoelman nykyiset tiedostot ja korvaa ne uusilla ladatuilla tiedostoilla.", "This response was generated by \"{{model}}\"": "Tämän vastauksen tuotti \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Tämä poistaa", "This will delete {{NAME}} and all its contents.": "Tämä poistaa {{NAME}} ja kaikki sen sisällöt.", "This will delete all models including custom models": "Tämä poistaa kaikki mallit mukaan lukien mukautetut mallit", diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index d59ea0abf3..20bb251a40 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Activation du compte en attente", "Accurate information": "Information exacte", "Action": "Action", - "Action not found": "", "Action Required for Chat Log Storage": "Action requise pour l’enregistrement du journal de discussion", "Actions": "Actions", "Activate": "Activer", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Toujours jouer la notification sonore", "Amazing": "Incroyable", "an assistant": "un assistant", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Analysé", "Analyzing...": "Analyse en cours", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Empecher l'extraction d'image", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Désactive l'extraction d'images du PDF. Si l'option Utiliser le LLM est activée, les images seront automatiquement légendées. La valeur par défaut est False.", "Disabled": "Désactivé", + "Disconnect OAuth": "", "Discover a function": "Trouvez une fonction", "Discover a model": "Trouvez un modèle", "Discover a prompt": "Trouvez un prompt", @@ -769,6 +768,8 @@ "Enter New Password": "Entrez votre nouveau mots de passe", "Enter Number of Steps (e.g. 50)": "Entrez le nombre d'étapes (par ex. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Entrez la clé pour l'API de Perplixity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Entrez le délai d'expiration Playwright", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Échec de la création de la clé API.", "Failed to delete calendar": "", "Failed to delete note": "Échec de la délétion de la note", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Octobre", "Off": "Désactivé", "Okay, Let's Go!": "D'accord, allons-y !", @@ -1519,6 +1522,8 @@ "Output format": "Format de sortie", "Output Format": "Format de sortie", "Overview": "Aperçu", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "page", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Cette option définit le nombre maximal de Token que le modèle peut générer dans sa réponse. Une valeur plus élevée permet des réponses plus longues, mais peut aussi générer du contenu moins pertinent.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Cette option supprimera tous les fichiers existants dans la collection et les remplacera par les fichiers nouvellement téléchargés.", "This response was generated by \"{{model}}\"": "Cette réponse a été générée par \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Cela supprimera", "This will delete {{NAME}} and all its contents.": "Cela supprimera {{NAME}} et tout son contenu.", "This will delete all models including custom models": "Cela supprimera tous les modèles, y compris les modèles personnalisés", diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 4572e362c8..2f3671c827 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Activation du compte en attente", "Accurate information": "Information exacte", "Action": "Action", - "Action not found": "Action non trouvée", "Action Required for Chat Log Storage": "Action requise pour l’enregistrement du journal de discussion", "Actions": "Actions", "Activate": "Activer", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Toujours jouer la notification sonore", "Amazing": "Incroyable", "an assistant": "un assistant", - "An error occurred while fetching the explanation": "Une erreur s'est produite lors de la récupération de l'explication", "Analytics": "Analytique", "Analyzed": "Analysé", "Analyzing...": "Analyse en cours", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Empecher l'extraction d'image", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Désactive l'extraction d'images du PDF. Si l'option Utiliser le LLM est activée, les images seront automatiquement légendées. La valeur par défaut est False.", "Disabled": "Désactivé", + "Disconnect OAuth": "", "Discover a function": "Trouvez une fonction", "Discover a model": "Trouvez un modèle", "Discover a prompt": "Trouvez un prompt", @@ -769,6 +768,8 @@ "Enter New Password": "Entrez votre nouveau mots de passe", "Enter Number of Steps (e.g. 50)": "Entrez le nombre d'étapes (par ex. 50)", "Enter Ollama Cloud API Key": "Entrez la clé API Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Entrez la clé API Perplexity", "Enter Perplexity Search API URL": "Entrez l'URL de l'API Perplexity", "Enter Playwright Timeout": "Entrez le délai d'expiration Playwright", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Échec de la création de la clé API.", "Failed to delete calendar": "", "Failed to delete note": "Échec de la délétion de la note", + "Failed to disconnect": "", "Failed to download image": "Échec du téléchargement de l'image", "Failed to extract content from the file: {{error}}": "Échec de l'extraction du contenu du fichier : {{error}}", "Failed to extract content from the file.": "Échec de l'extraction du contenu du fichier", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Octobre", "Off": "Désactivé", "Okay, Let's Go!": "D'accord, allons-y !", @@ -1519,6 +1522,8 @@ "Output format": "Format de sortie", "Output Format": "Format de sortie", "Overview": "Aperçu", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "page", "Page": "Page", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Le mode Page crée un document par page. Le mode Unique combine toutes les pages en un seul document pour une meilleure segmentation à travers les limites de page.", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Cette option définit le nombre maximal de tokens que le modèle peut générer dans sa réponse. Une valeur plus élevée permet des réponses plus longues, mais peut aussi générer du contenu moins pertinent.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Cette option supprimera tous les fichiers existants dans la collection et les remplacera par les fichiers nouvellement téléchargés.", "This response was generated by \"{{model}}\"": "Cette réponse a été générée par \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Cela supprimera", "This will delete {{NAME}} and all its contents.": "Cela supprimera {{NAME}} et tout son contenu.", "This will delete all models including custom models": "Cela supprimera tous les modèles, y compris les modèles personnalisés", diff --git a/src/lib/i18n/locales/gl-ES/translation.json b/src/lib/i18n/locales/gl-ES/translation.json index df434bfa1a..f7624ffe65 100644 --- a/src/lib/i18n/locales/gl-ES/translation.json +++ b/src/lib/i18n/locales/gl-ES/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Activación da conta pendente", "Accurate information": "Información precisa", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Requírese unha acción para gardar o rexistro do chat", "Actions": "Accións", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "Sorprendente", "an assistant": "un asistente", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Analizado", "Analyzing...": "Analizando..", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Desactivado", + "Disconnect OAuth": "", "Discover a function": "Descubre unha función", "Discover a model": "Descubrir un modelo", "Discover a prompt": "Descubre un Prompt", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Ingrese o número de pasos (p.ej., 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Ingrese a chave API de Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Non pudo xerarse a chave API.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Octubre", "Off": "Desactivado", "Okay, Let's Go!": "Bien, ¡Vamos!", @@ -1518,6 +1521,8 @@ "Output format": "Formato de saida", "Output Format": "", "Overview": "Vista xeral", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "Páxina", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Esta opción eliminará todos os arquivos existentes na colección y os reemplazará con novos arquivos subidos.", "This response was generated by \"{{model}}\"": "Esta resposta fue generada por \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Esto eliminará", "This will delete {{NAME}} and all its contents.": "Esto eliminará {{NAME}} y todo su contido.", "This will delete all models including custom models": "Esto eliminará todos os modelos, incluidos os modelos personalizados", diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index f36e6d332e..ef8c4e647b 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "", "Accurate information": "מידע מדויק", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "נדרשת פעולה לשמירת יומן הצ'אט", "Actions": "פעולה", "Activate": "", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "", "Amazing": "מדהים", "an assistant": "עוזר", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -580,6 +578,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "מושבת", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "גלה מודל", "Discover a prompt": "גלה פקודה", @@ -769,6 +768,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "הזן מספר שלבים (למשל 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -899,6 +900,7 @@ "Failed to create API Key.": "יצירת מפתח API נכשלה.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "אוקטובר", "Off": "כבוי", "Okay, Let's Go!": "בסדר, בואו נתחיל!", @@ -1519,6 +1522,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "עמוד", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index eeeff64210..6e3b0fbe1c 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "सटीक जानकारी", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "चैट लॉग सहेजने के लिए कार्रवाई आवश्यक है", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "एक सहायक", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "अक्षम", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "एक मॉडल की खोज करें", "Discover a prompt": "प्रॉम्प्ट खोजें", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "चरणों की संख्या दर्ज करें (उदा. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "एपीआई कुंजी बनाने में विफल.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "अक्टूबर", "Off": "बंद", "Okay, Let's Go!": "ठीक है, चलिए चलते हैं!", @@ -1518,6 +1521,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/hr-HR/translation.json b/src/lib/i18n/locales/hr-HR/translation.json index c0525013e9..e27f8eecfd 100644 --- a/src/lib/i18n/locales/hr-HR/translation.json +++ b/src/lib/i18n/locales/hr-HR/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "", "Accurate information": "Točne informacije", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Potrebna je radnja za pohranu zapisnika chata", "Actions": "", "Activate": "", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "asistent", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -580,6 +578,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Onemogućeno", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "Otkrijte model", "Discover a prompt": "Otkrijte prompt", @@ -769,6 +768,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Unesite broj koraka (npr. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Neuspješno stvaranje API ključa.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "Listopad", "Off": "Isključeno", "Okay, Let's Go!": "U redu, idemo!", @@ -1519,6 +1522,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/hu-HU/translation.json b/src/lib/i18n/locales/hu-HU/translation.json index 22f4ea62cf..f3d91fcf9a 100644 --- a/src/lib/i18n/locales/hu-HU/translation.json +++ b/src/lib/i18n/locales/hu-HU/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Fiók aktiválása folyamatban", "Accurate information": "Pontos információ", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Művelet szükséges a csevegési napló mentéséhez", "Actions": "Műveletek", "Activate": "Aktiválás", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "Csodálatos", "an assistant": "egy asszisztens", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Elemezve", "Analyzing...": "Elemzés...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Letiltva", + "Disconnect OAuth": "", "Discover a function": "Funkció felfedezése", "Discover a model": "Modell felfedezése", "Discover a prompt": "Prompt felfedezése", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Add meg a lépések számát (pl. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Add meg a Perplexity API kulcsot", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Nem sikerült létrehozni az API kulcsot.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth azonosító", + "OAuth session disconnected": "", "October": "Október", "Off": "Ki", "Okay, Let's Go!": "Rendben, kezdjük!", @@ -1518,6 +1521,8 @@ "Output format": "Kimeneti formátum", "Output Format": "", "Overview": "Áttekintés", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "oldal", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Ez az opció beállítja a modell által generálható tokenek maximális számát a válaszban. Ezen limit növelése hosszabb válaszokat tesz lehetővé, de növelheti a nem hasznos vagy irreleváns tartalom generálásának valószínűségét.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Ez az opció törli az összes meglévő fájlt a gyűjteményben és lecseréli őket az újonnan feltöltött fájlokkal.", "This response was generated by \"{{model}}\"": "Ezt a választ a \"{{model}}\" generálta", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Ez törölni fogja", "This will delete {{NAME}} and all its contents.": "Ez törölni fogja a {{NAME}}-t és minden tartalmát.", "This will delete all models including custom models": "Ez törölni fogja az összes modellt, beleértve az egyéni modelleket is", diff --git a/src/lib/i18n/locales/id-ID/translation.json b/src/lib/i18n/locales/id-ID/translation.json index c537fb24bb..2f02c5f8ac 100644 --- a/src/lib/i18n/locales/id-ID/translation.json +++ b/src/lib/i18n/locales/id-ID/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "Aktivasi Akun Tertunda", "Accurate information": "Informasi yang akurat", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Diperlukan tindakan untuk menyimpan log obrolan", "Actions": "", "Activate": "", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "asisten", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -578,6 +576,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Dinonaktifkan", + "Disconnect OAuth": "", "Discover a function": "Menemukan sebuah fungsi", "Discover a model": "Menemukan sebuah model", "Discover a prompt": "Temukan petunjuk", @@ -767,6 +766,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Masukkan Jumlah Langkah (mis. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -897,6 +898,7 @@ "Failed to create API Key.": "Gagal membuat API Key.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1451,6 +1453,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Oktober", "Off": "Mati", "Okay, Let's Go!": "Oke, Ayo Kita Pergi!", @@ -1517,6 +1520,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2017,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Ini akan menghapus", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/ie-GA/translation.json b/src/lib/i18n/locales/ie-GA/translation.json index e5550ac069..e4d57d5b70 100644 --- a/src/lib/i18n/locales/ie-GA/translation.json +++ b/src/lib/i18n/locales/ie-GA/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Gníomhachtaithe Cuntas", "Accurate information": "Faisnéis chruinn", "Action": "Gníomh", - "Action not found": "Níor aimsíodh gníomh", "Action Required for Chat Log Storage": "Gníomh riachtanach chun logáil comhrá a shábháil", "Actions": "Gníomhartha", "Activate": "Gníomhachtaigh", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Seinn Fuaim Fógra i gCónaí", "Amazing": "Iontach", "an assistant": "cúntóir", - "An error occurred while fetching the explanation": "Tharla earráid agus an míniú á fháil", "Analytics": "Anailísíocht", "Analyzed": "Anailísithe", "Analyzing...": "Ag déanamh anailíse...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Díchumasaigh Eastóscadh Íomhá", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Díchumasaigh eastóscadh íomhánna ón PDF. Má tá Úsáid LLM cumasaithe, cuirfear fotheidil leis na híomhánna go huathoibríoch. Is é Bréag an réamhshocrú.", "Disabled": "Díchumasaithe", + "Disconnect OAuth": "", "Discover a function": "Faigh amach feidhm", "Discover a model": "Faigh amach samhail", "Discover a prompt": "Faigh amach treoir", @@ -768,6 +767,8 @@ "Enter New Password": "Cuir isteach Pasfhocal Nua", "Enter Number of Steps (e.g. 50)": "Iontráil Líon na gCéimeanna (m.sh. 50)", "Enter Ollama Cloud API Key": "Cuir isteach Eochair API Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Cuir isteach Eochair API Perplexity", "Enter Perplexity Search API URL": "Cuir isteach URL API Cuardaigh na Measctha", "Enter Playwright Timeout": "Iontráil Teorainn Ama na nDrámadóir", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Theip ar an eochair API a chruthú.", "Failed to delete calendar": "", "Failed to delete note": "Theip ar an nóta a scriosadh", + "Failed to disconnect": "", "Failed to download image": "Theip ar an íomhá a íoslódáil", "Failed to extract content from the file: {{error}}": "Theip ar an ábhar a bhaint as an gcomhad: {{error}}", "Failed to extract content from the file.": "Theip ar an ábhar a bhaint as an gcomhad.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Statach)", "OAuth ID": "Aitheantas OAuth", + "OAuth session disconnected": "", "October": "Deireadh Fómhair", "Off": "As", "Okay, Let's Go!": "Ceart go leor, Déanaimis Téigh!", @@ -1518,6 +1521,8 @@ "Output format": "Formáid aschuir", "Output Format": "Formáid Aschuir", "Overview": "Forbhreathnú", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "leathanach", "Page": "Leathanach", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Cruthaíonn mód leathanaigh doiciméad amháin in aghaidh an leathanaigh. Comhcheanglaíonn mód aonair na leathanaigh go léir in aon doiciméad amháin le haghaidh roinnt níos fearr trasna teorainneacha leathanaigh.", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Socraíonn an rogha seo an t-uaslíon comharthaí is féidir leis an tsamhail a ghiniúint ina fhreagra. Tríd an teorainn seo a mhéadú is féidir leis an tsamhail freagraí níos faide a sholáthar, ach d'fhéadfadh go méadódh sé an dóchúlacht go nginfear ábhar neamhchabhrach nó nach mbaineann le hábhar.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Scriosfaidh an rogha seo gach comhad atá sa bhailiúchán agus cuirfear comhaid nua-uaslódála ina n-ionad.", "This response was generated by \"{{model}}\"": "Gin an freagra seo ag \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Scriosfaidh sé seo", "This will delete {{NAME}} and all its contents.": "Scriosfaidh sé seo {{NAME}} agus a bhfuil ann go léir.", "This will delete all models including custom models": "Scriosfaidh sé seo gach samhail lena n-áirítear samhlacha saincheaptha", diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index c94b0f7f5a..b8a2c5f5e9 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Account in attesa di attivazione", "Accurate information": "Informazioni accurate", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Azione richiesta per salvare il registro chat", "Actions": "Azioni", "Activate": "Attiva", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Riproduci sempre il suono di notifica", "Amazing": "Fantastico", "an assistant": "un assistente", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Analizzato", "Analyzing...": "Analisi in corso...", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Disattiva l'estrazione immagini", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Disattiva l'estrazione immagini dai PDF. Se LLM è attivo le immagini saranno didascalizzate. Predefinito a Falso.", "Disabled": "Disabilitato", + "Disconnect OAuth": "", "Discover a function": "Scopri una funzione", "Discover a model": "Scopri un modello", "Discover a prompt": "Scopri un prompt", @@ -769,6 +768,8 @@ "Enter New Password": "Inserisci la Nuova Password", "Enter Number of Steps (e.g. 50)": "Inserisci Numero di Passaggi (ad esempio 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Inserisci Chiave API di Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Inserisci Timeout di Playwright", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Impossibile creare Chiave API.", "Failed to delete calendar": "", "Failed to delete note": "Impossibile eliminare la nota", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "Ottobre", "Off": "Disattivato", "Okay, Let's Go!": "Ok, andiamo!", @@ -1519,6 +1522,8 @@ "Output format": "Formato di output", "Output Format": "Formato output", "Overview": "Panoramica", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "pagina", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Questa opzione imposta il numero massimo di token che il modello può generare nella sua risposta. Aumentare questo limite consente al modello di fornire risposte più lunghe, ma potrebbe anche aumentare la probabilità che vengano generati contenuti non utili o irrilevanti.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Questa opzione eliminerà tutti i file esistenti nella collezione e li sostituirà con i file appena caricati.", "This response was generated by \"{{model}}\"": "Questa risposta è stata generata da \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Questa opzione eliminerà", "This will delete {{NAME}} and all its contents.": "Questa opzione eliminerà {{NAME}} e tutti i suoi contenuti.", "This will delete all models including custom models": "Questa opzione eliminerà tutti i modelli, compresi i modelli personalizzati", diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index af0c4211b5..c69a21f3a1 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "アカウント承認待ち", "Accurate information": "情報が正確", "Action": "アクション", - "Action not found": "アクションが見つかりません", "Action Required for Chat Log Storage": "チャットログの保存には操作が必要です", "Actions": "アクション", "Activate": "アクティブ化", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "常に通知音を再生", "Amazing": "素晴らしい", "an assistant": "アシスタント", - "An error occurred while fetching the explanation": "説明の取得中にエラーが発生しました", "Analytics": "分析", "Analyzed": "分析済み", "Analyzing...": "分析中...", @@ -578,6 +576,7 @@ "Disable Image Extraction": "画像の抽出を無効化", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDFからの画像の抽出を無効化します。LLMを使用 が有効の場合、画像は自動で説明文に変換されます。デフォルトで無効", "Disabled": "無効", + "Disconnect OAuth": "", "Discover a function": "Functionを探す", "Discover a model": "モデルを探す", "Discover a prompt": "プロンプトを探す", @@ -767,6 +766,8 @@ "Enter New Password": "新しいパスワードを入力", "Enter Number of Steps (e.g. 50)": "ステップ数を入力 (例: 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity APIキーを入力", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Playwrightタイムアウトを入力", @@ -897,6 +898,7 @@ "Failed to create API Key.": "APIキーの作成に失敗しました。", "Failed to delete calendar": "", "Failed to delete note": "ノートの削除に失敗しました。", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "ファイルから中身の取得に失敗しました: {{error}}", "Failed to extract content from the file.": "ファイルから中身の取得に失敗しました。", @@ -1451,6 +1453,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "10月", "Off": "オフ", "Okay, Let's Go!": "OK、始めましょう!", @@ -1517,6 +1520,8 @@ "Output format": "出力形式", "Output Format": "出力形式", "Overview": "概要", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "ページ", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2017,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "このオプションは、モデルが生成できるトークンの最大数を設定します。この制限を増加すると、モデルはより長い回答を生成できるようになりますが、不適切な内容や関連性の低い内容が生成される可能性も高まります。", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "このオプションを有効にすると、コレクション内の既存ファイルがすべて削除され、新たにアップロードしたファイルに置き換わります。", "This response was generated by \"{{model}}\"": "このレスポンスは\"{{model}}\"によって生成されました。", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "削除します", "This will delete {{NAME}} and all its contents.": "これは{{NAME}}とそのすべての内容を削除します。", "This will delete all models including custom models": "これはカスタムモデルを含むすべてのモデルを削除します", diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index acdc14db3c..edfd074bc4 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "დარჩენილი ანგარიშის აქტივაცია", "Accurate information": "სწორი ინფორმაცია", "Action": "ქმედება", - "Action not found": "ქმედება აღმოჩენილი არაა", "Action Required for Chat Log Storage": "საჭიროა მოქმედება ჩატის ჟურნალის შესანახად", "Actions": "ქმედებები", "Activate": "აქტივაცია", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "გაფრთხილების ხმის ყოველთვის დაკვრა", "Amazing": "გადასარევია", "an assistant": "დამხმარე", - "An error occurred while fetching the explanation": "", "Analytics": "ანალიტიკა", "Analyzed": "გაანაზლიებულია", "Analyzing...": "ანალიზი...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "გამორთული", + "Disconnect OAuth": "", "Discover a function": "აღმოაჩინეთ ფუნქცია", "Discover a model": "აღმოაჩინეთ მოდელი", "Discover a prompt": "აღმოაჩინეთ მოთხოვნა", @@ -768,6 +767,8 @@ "Enter New Password": "შეიყვანეთ ახალი პაროლი", "Enter Number of Steps (e.g. 50)": "შეიყვანეთ ნაბიჯების რაოდენობა (მაგ. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API-ის გასაღების შექმნა ჩავარდა.", "Failed to delete calendar": "", "Failed to delete note": "შენიშვნის წაშლა ჩავარდა", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "ოქტომბერი", "Off": "გამორთ", "Okay, Let's Go!": "აბა, წავედით!", @@ -1518,6 +1521,8 @@ "Output format": "გამოტანის ფორმატი", "Output Format": "გამოტანის ფორმატი", "Overview": "მიმოხილვა", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "პანელი", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "ეს წაშლის", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/kab-DZ/translation.json b/src/lib/i18n/locales/kab-DZ/translation.json index 0fc3787813..ecd7eae337 100644 --- a/src/lib/i18n/locales/kab-DZ/translation.json +++ b/src/lib/i18n/locales/kab-DZ/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Armad n umiḍan deg uṛaǧu", "Accurate information": "Talɣut tusdidt", "Action": "Tigawt", - "Action not found": "Tigawt ulac-itt", "Action Required for Chat Log Storage": "Isefk tigawt i usekles n uɣmis n udiwenni", "Actions": "Tigawin", "Activate": "Sermed", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Rmed yal tikkelt alɣu s ṣṣut", "Amazing": "Igerrez", "an assistant": "d amallal", - "An error occurred while fetching the explanation": "Teḍra-d tuccḍa lawan n tririt n usegzi", "Analytics": "Tasleḍt", "Analyzed": "Yettwasekyed", "Analyzing...": "La yettwasekyad…", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Sens afsay n tugniwin", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Kkes-d asufeɣ n tugna seg PDF. Ma yella aseqdec n LLM yermed, tugniwin ad ttwakelsent s wudem awurman. Imezwura ɣer False.", "Disabled": "Yensa", + "Disconnect OAuth": "", "Discover a function": "Af-d tasɣent", "Discover a model": "Snirem tamudemt", "Discover a prompt": "Snirem aneftaɣ", @@ -768,6 +767,8 @@ "Enter New Password": "Sekcem-d awal n uɛeddi amaynut", "Enter Number of Steps (e.g. 50)": "Sekcem uṭṭun n yisurifen (amedya 50)", "Enter Ollama Cloud API Key": "Sekcem-d tasarut API n Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Sekcem-d tasarut API n Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Ur yessaweḍ ara ad d-yesnulfu tasarut API.", "Failed to delete calendar": "", "Failed to delete note": "Ur yessaweḍ ara ad yekkes tazmilt", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Ur yessaweḍ ara ad d-yekkes agbur seg ufaylu: {{error}}", "Failed to extract content from the file.": "Ur yessaweḍ ara ad d-yekkes agbur seg ufaylu-nni.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "Asulay OAuth", + "OAuth session disconnected": "", "October": "Tubeṛ", "Off": "Yensa", "Okay, Let's Go!": "Yerbaḥ, aha yya!", @@ -1518,6 +1521,8 @@ "Output format": "Amasal n tuffɣa", "Output Format": "Amasal n tuffɣa", "Overview": "Tamuɣli s umata", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "asebter", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "Tiririt-a teslal-itt-id \"{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Aya ad yekkes", "This will delete {{NAME}} and all its contents.": "Aya ad yekkes {NAME}} akked akk ayen yellan deg-s.", "This will delete all models including custom models": "Aya ad yekkes akk timudmin yellan gar-asent timudmin n tannumi", diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 748d8de646..83ff4863f7 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -32,8 +32,13 @@ "{{user}}'s Chats": "{{user}}의 채팅", "{{webUIName}} Backend Required": "{{webUIName}} 백엔드가 필요합니다.", "*Prompt node ID(s) are required for image generation": "이미지 생성에는 프롬프트 노드 ID가 필요합니다.", + "1 hour before": "", "1 Source": "소스 1", + "10 minutes before": "", + "15 minutes before": "", "1m_time_ago": "1분 전", + "30 minutes before": "", + "5 minutes before": "", "A collaboration channel where people join as members": "사람들이 멤버로 참여하는 협업 채널", "A discussion channel where access is controlled by groups and permissions": "그룹과 권한으로 접근이 제어되는 토론 채널", "A new version (v{{LATEST_VERSION}}) is now available.": "새로운 버전 (v{{LATEST_VERSION}})을 사용할 수 있습니다.", @@ -52,7 +57,6 @@ "Account Activation Pending": "계정 활성화 대기", "Accurate information": "정확한 정보", "Action": "작업", - "Action not found": "작업을 찾을 수 없습니다.", "Action Required for Chat Log Storage": "채팅 로그 저장을 위해 조치가 필요합니다", "Actions": "작업", "Activate": "활성화", @@ -72,9 +76,11 @@ "Add content here": "여기에 내용을 추가하세요", "Add Custom Parameter": "사용자 정의 매개변수 추가", "Add Custom Prompt": "사용자 정의 프롬프트 추가", + "Add description": "", "Add Details": "디테일 추가", "Add Files": "파일 추가", "Add Image": "이미지 추가", + "Add location": "", "Add Member": "멤버 추가", "Add Members": "멤버 추가", "Add Memory": "메모리 추가", @@ -110,6 +116,7 @@ "AI": "AI", "All": "전체", "All chats have been unarchived.": "모든 채팅이 보관 해제되었습니다.", + "All day": "", "All models are now hidden": "모든 모델이 이제 숨김 처리되었습니다", "All models are now visible": "모든 모델이 이제 표시됩니다", "All models deleted successfully": "성공적으로 모든 모델이 삭제되었습니다", @@ -150,7 +157,6 @@ "Always Play Notification Sound": "항상 알림 소리 재생", "Amazing": "놀라움", "an assistant": "어시스턴트", - "An error occurred while fetching the explanation": "설명을 가져오는 동안 오류가 발생했습니다.", "Analytics": "분석", "Analyzed": "분석됨", "Analyzing...": "분석 중...", @@ -182,6 +188,7 @@ "Are you sure you want to archive all chats? This action cannot be undone.": "정말 모든 채팅을 보관하시겠습니까? 이 작업은 되돌릴 수 없습니다.", "Are you sure you want to clear all memories? This action cannot be undone.": "정말 모든 메모리를 지우시겠습니까? 이 작업은 되돌릴 수 없습니다.", "Are you sure you want to delete \"{{NAME}}\"?": "정말 \"{{NAME}}\"을 삭제하시겠습니까?", + "Are you sure you want to delete **{{modelName}}**?": "", "Are you sure you want to delete all chats? This action cannot be undone.": "정말 모든 채팅을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", "Are you sure you want to delete this channel?": "정말 이 채널을 삭제하시겠습니까?", "Are you sure you want to delete this connection? This action cannot be undone.": "정말 이 연결을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.", @@ -197,6 +204,7 @@ "Ask a question": "질문하기", "Assistant": "어시스턴트", "Async Embedding Processing": "비동기 임베딩 처리", + "At time of event": "", "Attach File From Knowledge": "지식 기반에서 파일 첨부", "Attach Files": "첨부 파일", "Attach Knowledge": "지식 기반 첨부", @@ -271,6 +279,8 @@ "Bypass Web Loader": "웹 콘텐츠 불러오기 생략", "Cache Base Model List": "기본 모델 목록 캐시", "Calendar": "캘린더", + "Calendar deleted": "", + "Calendars": "", "Call": "음성 기능", "Call feature is not supported when using Web STT engine": "웹 STT 엔진 사용 시, 음성 기능은 지원되지 않습니다.", "Camera": "카메라", @@ -407,6 +417,7 @@ "Connect to your own OpenAPI compatible external tool servers.": "OpenAPI 호환 외부 도구 서버에 연결합니다.", "Connected ({{type}})": "{{type}}에 연결됨", "Connection failed": "연결 실패", + "Connection lost. Reconnecting...": "", "Connection successful": "연결 성공", "Connection Type": "연결 방식", "Connections": "연결", @@ -519,8 +530,11 @@ "Delete All Chats": "모든 채팅 삭제", "Delete all contents inside this folder": "이 폴더 내 모든 콘텐츠 삭제", "Delete automation?": "자동 삭제하시겠습니까?", + "Delete calendar": "", + "Delete Calendar": "", "Delete Chat": "채팅 삭제", "Delete chat?": "채팅을 삭제하시겠습니까?", + "Delete Event": "", "Delete File": "파일 삭제", "Delete folder?": "폴더를 삭제하시겠습니까?", "Delete function?": "함수를 삭제하시겠습니까?", @@ -562,6 +576,7 @@ "Disable Image Extraction": "이미지 추출 비활성화", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDF에서 이미지 추출을 비활성화합니다. Use LLM이 활성화된 경우 이미지는 자동으로 캡션이 달립니다. 기본값은 False입니다.", "Disabled": "제한됨", + "Disconnect OAuth": "", "Discover a function": "함수 검색", "Discover a model": "모델 검색", "Discover a prompt": "프롬프트 검색", @@ -751,6 +766,8 @@ "Enter New Password": "새로운 비밀번호 입력", "Enter Number of Steps (e.g. 50)": "단계 수 입력(예: 50)", "Enter Ollama Cloud API Key": "Ollama 클라우드 API 키 입력", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity API 키 입력", "Enter Perplexity Search API URL": "Perplexity 검색 API URL 입력", "Enter Playwright Timeout": "Playwright 시간 초과 입력", @@ -827,6 +844,10 @@ "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "오류: ID가 '{{modelId}}'인 모델이 이미 존재합니다. 계속하려면 다른 ID를 선택하세요.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "오류: 모델 ID는 비워둘 수 없습니다. 계속하려면 유효한 ID를 입력하세요.", "Evaluations": "평가", + "Event created": "", + "Event deleted": "", + "Event title": "", + "Event updated": "", "Exa API Key": "Exa API 키", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "예: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "예: 전체", @@ -875,7 +896,9 @@ "Failed to connect to {{URL}} terminal server": "{{URL}} 터미널 서버 연결에 실패했습니다", "Failed to copy link": "링크 복사 실패", "Failed to create API Key.": "API 키 생성에 실패했습니다.", + "Failed to delete calendar": "", "Failed to delete note": "노트 삭제 실패", + "Failed to disconnect": "", "Failed to download image": "이미지 다운로드에 실패했습니다", "Failed to extract content from the file: {{error}}": "파일 내용 추출 실패: {{error}}", "Failed to extract content from the file.": "파일 내용 추출 실패.", @@ -1196,6 +1219,7 @@ "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "동시 검색 쿼리 수를 제한합니다. 0은 무제한(기본값)입니다. 순차 실행하려면 1로 설정하세요(Brave 무료 요금제처럼 엄격한 속도 제한이 있는 API에 권장됩니다).", "Limits the number of concurrent embedding requests. Set to 0 for unlimited.": "동시 임베딩 요청 수를 제한합니다. 무제한은 0으로 설정하세요.", "List": "목록", + "List calendars, search, create, update, and delete calendar events": "", "Listening...": "듣는 중...", "Live": "실시간", "Llama.cpp": "Llama.cpp", @@ -1206,6 +1230,7 @@ "local": "로컬", "Local": "로컬", "Local Task Model": "로컬 작업 모델", + "Location": "", "Location access not allowed": "위치 접근이 허용되지 않습니다", "Lost": "패배", "Low": "낮음", @@ -1315,6 +1340,7 @@ "Models Sharing": "모델 공유", "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API 키", + "Month": "", "Monthly": "월간", "More": "더보기", "More Concise": "더 간결하게", @@ -1333,6 +1359,7 @@ "New Automation": "새로운 자동", "New Button": "새 버튼", "New Chat": "새 채팅", + "New Event": "", "New File": "새 파일", "New Folder": "새 폴더", "New Function": "새 함수", @@ -1426,6 +1453,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Static)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "10월", "Off": "끄기", "Okay, Let's Go!": "좋아요, 시작합시다!", @@ -1492,6 +1520,8 @@ "Output format": "출력 형식", "Output Format": "출력 형식", "Overview": "개요", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "페이지", "Page": "페이지", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "페이지 모드는 페이지마다 하나의 문서를 생성합니다. 단일 모드는 모든 페이지를 하나의 문서로 결합하여 페이지 경계를 넘어 더 나은 청킹을 제공합니다.", @@ -1610,6 +1640,7 @@ "Reasoning Effort": "추론 난이도", "Reasoning Tags": "추론 태그", "Recently Used": "최근 사용", + "Reconnected": "", "Record": "녹음", "Record voice": "음성 녹음", "Redirecting you to Open WebUI Community": "OpenWebUI 커뮤니티로 리디렉션 중", @@ -1633,6 +1664,7 @@ "Relevance": "관련도", "Relevance Threshold": "관련성 임계값", "Remember Dismissal": "다시 보지 않기", + "Reminder": "", "Remove": "삭제", "Remove {{MODELID}} from list.": "{{MODELID}}를 목록에서 제거.", "Remove action": "작업 제거", @@ -1878,7 +1910,10 @@ "Start a new conversation": "새 대화 시작", "Start of the channel": "채널 시작", "Start Tag": "시작 태그", + "Starting in {{count}} minutes_other": "", + "Starting in 1 minute": "", "Starting kernel...": "커널 시작 중...", + "Starting now": "", "State": "상태", "Status": "상태", "Status cleared successfully": "상태 초기화에 성공했습니다", @@ -1987,10 +2022,12 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "이 옵션은 모델이 응답에서 생성할 수 있는 최대 토큰 수를 설정합니다. 이 한도를 늘리면 모델이 더 긴 답변을 제공할 수 있지만, 도움이 되지 않거나 관련 없는 콘텐츠가 생성될 가능성도 높아질 수 있습니다.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "이 옵션을 선택하면 기존 컬렉션의 모든 파일이 삭제되고, 새로 업로드된 파일로 대체됩니다.", "This response was generated by \"{{model}}\"": "\"{{model}}\"이 생성한 응답입니다", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "삭제합니다.", "This will delete {{NAME}} and all its contents.": "{{NAME}}모든 내용을 삭제합니다.", "This will delete all models including custom models": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제됩니다", "This will delete all models including custom models and cannot be undone.": "이렇게 하면 사용자 지정 모델을 포함한 모든 모델이 삭제되며 실행 취소할 수 없습니다.", + "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "", "This will reset the knowledge base and sync all files. Do you wish to continue?": "지식 기반과 모든 파일 연동을 초기화합니다. 계속 하시겠습니까?", "Thorough explanation": "완전한 설명", "Thought": "생각", @@ -2010,6 +2047,7 @@ "Title cannot be an empty string.": "제목은 빈 문자열일 수 없습니다.", "Title Generation": "제목 생성", "Title Generation Prompt": "제목 생성 프롬프트", + "Title is required": "", "TLS": "TLS", "To access the available model names for downloading,": "다운로드 가능한 모델명을 확인하려면,", "To access the GGUF models available for downloading,": "다운로드 가능한 GGUF 모델을 확인하려면,", @@ -2076,6 +2114,7 @@ "Unloads {{FROM_NOW}}": "{{FROM_NOW}} 언로드", "Unlock mysteries": "미스터리 풀기", "Unpin": "고정 해제", + "Unpin from Sidebar": "", "Unravel secrets": "비밀 풀기", "Unshare Chat": "채팅 공유 해제", "Unsupported file type.": "지원하지 않는 파일 형식", @@ -2180,6 +2219,7 @@ "WebUI will make requests to \"{{url}}\"": "WebUI가 \"{{url}}\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI가 \"{{url}}/api/chat\"로 요청을 보냅니다", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI가 \"{{url}}/chat/completions\"로 요청을 보냅니다", + "Week": "", "Weekly": "주간", "What are you trying to achieve?": "무엇을 성취하고 싶으신가요?", "What are you working on?": "어떤 작업을 하고 계신가요?", @@ -2187,6 +2227,7 @@ "What is shared:": "공유되는 것:", "What's New in": "새로운 기능:", "What's on your mind?": "무슨 생각을 하고 계신가요?", + "When": "", "When enabled, the model will respond to each chat message in real-time, generating a response as soon as the user sends a message. This mode is useful for live chat applications, but may impact performance on slower hardware.": "활성화하면 모델이 각 채팅 메시지에 실시간으로 응답하여 사용자가 메시지를 보내는 즉시 응답을 생성합니다. 이 모드는 실시간 채팅 애플리케이션에 유용하지만, 느린 하드웨어에서는 성능에 영향을 미칠 수 있습니다.", "wherever you are": "당신이 어디에 있든", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "출력을 페이지로 나눌지 여부입니다. 각 페이지는 구분선과 페이지 번호로 구분됩니다. 기본값은 False입니다.", diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json index 784832cde7..ccc65e16a5 100644 --- a/src/lib/i18n/locales/lt-LT/translation.json +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -60,7 +60,6 @@ "Account Activation Pending": "Laukiama paskyros patvirtinimo", "Accurate information": "Tiksli informacija", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Reikia veiksmo, kad būtų išsaugotas pokalbių žurnalas", "Actions": "Veiksmai", "Activate": "", @@ -161,7 +160,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "assistentas", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -581,6 +579,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Išjungta", + "Disconnect OAuth": "", "Discover a function": "Atrasti funkciją", "Discover a model": "Atrasti modelį", "Discover a prompt": "Atrasti užklausas", @@ -770,6 +769,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Įveskite žingsnių kiekį (pvz. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -900,6 +901,7 @@ "Failed to create API Key.": "Nepavyko sukurti API rakto", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1454,6 +1456,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "spalis", "Off": "Išjungta", "Okay, Let's Go!": "Gerai, važiuojam!", @@ -1520,6 +1523,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2026,6 +2031,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Tai ištrins", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/lv-LV/translation.json b/src/lib/i18n/locales/lv-LV/translation.json index 09ae34c6a3..af6f5c21be 100644 --- a/src/lib/i18n/locales/lv-LV/translation.json +++ b/src/lib/i18n/locales/lv-LV/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Gaida konta aktivizēšanu", "Accurate information": "Precīza informācija", "Action": "Darbība", - "Action not found": "Darbība nav atrasta", "Action Required for Chat Log Storage": "Nepieciešama darbība tērzēšanas žurnāla glabāšanai", "Actions": "Darbības", "Activate": "Aktivizēt", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Vienmēr atskaņot paziņojuma skaņu", "Amazing": "Lieliski", "an assistant": "asistents", - "An error occurred while fetching the explanation": "Iegūstot skaidrojumu, radās kļūda", "Analytics": "Analītika", "Analyzed": "Analizēts", "Analyzing...": "Analizē...", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Atspējot attēlu ekstrakciju", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Atspējot attēlu ekstrakciju no PDF. Ja ir iespējots Lietot LLM, attēliem automātiski tiks pievienoti paraksti. Noklusējums ir False.", "Disabled": "Atspējots", + "Disconnect OAuth": "", "Discover a function": "Atklāt funkciju", "Discover a model": "Atklāt modeli", "Discover a prompt": "Atklāt uzvedni", @@ -769,6 +768,8 @@ "Enter New Password": "Ievadiet jaunu paroli", "Enter Number of Steps (e.g. 50)": "Ievadiet soļu skaitu (piem., 50)", "Enter Ollama Cloud API Key": "Ievadiet Ollama Cloud API atslēgu", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Ievadiet Perplexity API atslēgu", "Enter Perplexity Search API URL": "Ievadiet Perplexity Search API URL", "Enter Playwright Timeout": "Ievadiet Playwright taimautu", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Neizdevās izveidot API atslēgu.", "Failed to delete calendar": "", "Failed to delete note": "Neizdevās dzēst piezīmi", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Neizdevās ekstrahēt saturu no faila: {{error}}", "Failed to extract content from the file.": "Neizdevās ekstrahēt saturu no faila.", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Oktobris", "Off": "Izslēgts", "Okay, Let's Go!": "Labi, ejam!", @@ -1519,6 +1522,8 @@ "Output format": "Izvades formāts", "Output Format": "Izvades formāts", "Overview": "Pārskats", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "lapa", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Šī opcija iestata maksimālo tokenu skaitu, ko modelis var ģenerēt savā atbildē. Šī ierobežojuma palielināšana ļauj modelim sniegt garākas atbildes, bet var arī palielināt nevēlama vai neatbilstoša satura ģenerēšanas iespējamību.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Šī opcija dzēsīs visus esošos failus kolekcijā un aizstās tos ar jaunaugšupielādētiem failiem.", "This response was generated by \"{{model}}\"": "Šo atbildi ģenerēja \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Tas dzēsīs", "This will delete {{NAME}} and all its contents.": "Tas dzēsīs {{NAME}} un visu tā saturu.", "This will delete all models including custom models": "Tas dzēsīs visus modeļus, ieskaitot pielāgotos modeļus", diff --git a/src/lib/i18n/locales/ms-MY/translation.json b/src/lib/i18n/locales/ms-MY/translation.json index 8dd75ac052..309ace4761 100644 --- a/src/lib/i18n/locales/ms-MY/translation.json +++ b/src/lib/i18n/locales/ms-MY/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "Pengaktifan Akaun belum selesai", "Accurate information": "Informasi tepat", "Action": "Tindakan", - "Action not found": "Tindakan tidak ditemui", "Action Required for Chat Log Storage": "Tindakan diperlukan untuk menyimpan log sembang", "Actions": "Tindakan", "Activate": "Aktifkan", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "Sentiasa Mainkan Bunyi Pemberitahuan", "Amazing": "Hebat", "an assistant": "seorang pembantu", - "An error occurred while fetching the explanation": "Ralat berlaku semasa mengambil penjelasan", "Analytics": "Analitik", "Analyzed": "Sudah dianalisis", "Analyzing...": "Menganalisis...", @@ -578,6 +576,7 @@ "Disable Image Extraction": "Nyahlumpuhkan Pengekstrakan Imej", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Melumpuhkan pengekstrakan imej daripada PDF. Jika Gunakan LLM didayakan, imej akan diselia secara automatik. Lalai kepada Palsu.", "Disabled": "Dilumpuhkan", + "Disconnect OAuth": "", "Discover a function": "Temui fungsi", "Discover a model": "Temui model", "Discover a prompt": "Temui arahan", @@ -767,6 +766,8 @@ "Enter New Password": "Masukkan Kata Laluan Baharu", "Enter Number of Steps (e.g. 50)": "Masukkan Bilangan Langkah (cth 50)", "Enter Ollama Cloud API Key": "Masukkan Kunci API Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Masukkan Kunci API Perplexity", "Enter Perplexity Search API URL": "Masukkan URL API Pencarian Perplexity", "Enter Playwright Timeout": "Masukkan Masa Tamat Playwright", @@ -897,6 +898,7 @@ "Failed to create API Key.": "Gagal mencipta kekunci API", "Failed to delete calendar": "", "Failed to delete note": "Gagal memadamkan nota", + "Failed to disconnect": "", "Failed to download image": "Gagal memuat turun imej", "Failed to extract content from the file: {{error}}": "Gagal mengekstrak kandungan daripada fail: {{error}}", "Failed to extract content from the file.": "Gagal mengekstrak kandungan daripada fail.", @@ -1451,6 +1453,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Oktober", "Off": "Mati", "Okay, Let's Go!": "Baiklah, Jom!", @@ -1517,6 +1520,8 @@ "Output format": "Format output", "Output Format": "Format Output", "Overview": "Gambaran Keseluruhan", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "halaman", "Page": "Halaman", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Mode Halaman membuat satu dokumen per halaman. Mode Tunggal menggabungkan semua halaman ke dalam satu dokumen untuk chunking yang lebih baik merentas sempadan halaman.", @@ -2017,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Pilihan ini menetapkan bilangan maksimum token yang boleh dijana oleh model dalam responsnya. Meningkatkan had ini membenarkan model memberikan jawapan yang lebih panjang, tetapi ia juga mungkin meningkatkan kemungkinan kandungan yang tidak berguna atau tidak relevan dijana.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Pilihan ini akan memadamkan semua fail sedia ada dalam koleksi dan menggantinya dengan fail yang baru dimuat naik.", "This response was generated by \"{{model}}\"": "Respons ini dijana oleh \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Ini akan memadam", "This will delete {{NAME}} and all its contents.": "Ini akan memadam {{NAME}} dan semua kandungannya.", "This will delete all models including custom models": "Ini akan memadam semua model termasuk model tersuai", diff --git a/src/lib/i18n/locales/nb-NO/translation.json b/src/lib/i18n/locales/nb-NO/translation.json index 7f45c82157..a27ca6fa7e 100644 --- a/src/lib/i18n/locales/nb-NO/translation.json +++ b/src/lib/i18n/locales/nb-NO/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Venter på kontoaktivering", "Accurate information": "Nøyaktig informasjon", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Handling kreves for å lagre chatlogg", "Actions": "Handlinger", "Activate": "Aktiver", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "Flott", "an assistant": "en assistent", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Analysert", "Analyzing...": "Analyserer...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Deaktivert", + "Disconnect OAuth": "", "Discover a function": "Oppdag en funksjon", "Discover a model": "Oppdag en modell", "Discover a prompt": "Oppdag en ledetekst", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Angi antall steg (f.eks. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Kan ikke opprette en API-nøkkel.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth-ID", + "OAuth session disconnected": "", "October": "oktober", "Off": "Av", "Okay, Let's Go!": "OK, kjør på!", @@ -1518,6 +1521,8 @@ "Output format": "Format på utdata", "Output Format": "", "Overview": "Oversikt", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "side", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Dette alternativet sletter alle eksisterende filer i samlingen og erstatter dem med nyopplastede filer.", "This response was generated by \"{{model}}\"": "Dette svaret er generert av \"{{modell}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Dette sletter", "This will delete {{NAME}} and all its contents.": "Dette sletter {{NAME}} og alt innholdet.", "This will delete all models including custom models": "Dette sletter alle modeller, inkludert tilpassede modeller", diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index dbaf9bcb13..8bf77d68eb 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -33,15 +33,15 @@ "{{user}}'s Chats": "Chats van {{user}}", "{{webUIName}} Backend Required": "{{webUIName}} Backend verplicht", "*Prompt node ID(s) are required for image generation": "*Prompt node ID(s) zijn vereist voor het genereren van afbeeldingen", - "1 Source": "1 bron", - "1m_time_ago": "1m geleden", - "A collaboration channel where people join as members": "Een samenwerkingskanaal waar mensen als leden kunnen deelnemen", - "A discussion channel where access is controlled by groups and permissions": "Een discussiekanaal waar toegang wordt beheerd via groepen en machtigingen", "1 hour before": "1 uur voor", + "1 Source": "1 bron", "10 minutes before": "10 minuten voor", "15 minutes before": "15 minuten voor", + "1m_time_ago": "1m geleden", "30 minutes before": "30 minuten voor", "5 minutes before": "5 minuten voor", + "A collaboration channel where people join as members": "Een samenwerkingskanaal waar mensen als leden kunnen deelnemen", + "A discussion channel where access is controlled by groups and permissions": "Een discussiekanaal waar toegang wordt beheerd via groepen en machtigingen", "A new version (v{{LATEST_VERSION}}) is now available.": "Een nieuwe versie (v{{LATEST_VERSION}}) is nu beschikbaar", "A private conversation between you and selected users": "Een privégesprek tussen jou en geselecteerde gebruikers", "A task model is used when performing tasks such as generating titles for chats and web search queries": "Een taakmodel wordt gebruikt bij het uitvoeren van taken zoals het genereren van titels voor chats en zoekopdrachten op het internet", @@ -58,7 +58,6 @@ "Account Activation Pending": "Accountactivatie in afwachting", "Accurate information": "Nauwkeurige informatie", "Action": "Actie", - "Action not found": "Actie niet gevonden", "Action Required for Chat Log Storage": "Actie vereist voor het opslaan van het chatlog", "Actions": "Acties", "Activate": "Activeren", @@ -78,13 +77,13 @@ "Add content here": "Voeg hier content toe", "Add Custom Parameter": "Aangepaste parameter toevoegen", "Add Custom Prompt": "Aangepaste prompt toevoegen", + "Add description": "Voeg beschrijving toe", "Add Details": "Details toevoegen", "Add Files": "Voeg bestanden toe", "Add Image": "Afbeelding toevoegen", + "Add location": "Voeg locatie toe", "Add Member": "Lid toevoegen", "Add Members": "Leden toevoegen", - "Add description": "Voeg beschrijving toe", - "Add location": "Voeg locatie toe", "Add Memory": "Voeg geheugen toe", "Add Model": "Voeg model toe", "Add Reaction": "Voeg reactie toe", @@ -118,9 +117,9 @@ "AI": "AI", "All": "Alle", "All chats have been unarchived.": "Alle chats zijn gedearchiveerd.", + "All day": "De hele dag", "All models are now hidden": "Alle modellen zijn nu verborgen", "All models are now visible": "Alle modellen zijn nu zichtbaar", - "All day": "De hele dag", "All models deleted successfully": "Alle modellen zijn succesvol verwijderd", "All time": "Altijd", "All Users": "Alle gebruikers", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Meldingsgeluid altijd afspelen", "Amazing": "Geweldig", "an assistant": "een assistent", - "An error occurred while fetching the explanation": "Er is een fout opgetreden bij het ophalen van de uitleg", "Analytics": "Analyse", "Analyzed": "Geanalyseerd", "Analyzing...": "Aan het analyseren...", @@ -191,8 +189,8 @@ "Are you sure you want to archive all chats? This action cannot be undone.": "Weet je zeker dat je alle chats wilt archiveren? Deze actie kan niet ongedaan worden gemaakt.", "Are you sure you want to clear all memories? This action cannot be undone.": "Weet je zeker dat je alle herinneringen wil verwijderen? Deze actie kan niet ongedaan worden gemaakt.", "Are you sure you want to delete \"{{NAME}}\"?": "Weet je zeker dat je \"{{NAME}}\" wilt verwijderen?", - "Are you sure you want to delete all chats? This action cannot be undone.": "Weet je zeker dat je alle chats wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", "Are you sure you want to delete **{{modelName}}**?": "Weet je zeker dat je **{{modelName}}** wilt verwijderen?", + "Are you sure you want to delete all chats? This action cannot be undone.": "Weet je zeker dat je alle chats wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", "Are you sure you want to delete this channel?": "Weet je zeker dat je dit kanaal wil verwijderen?", "Are you sure you want to delete this connection? This action cannot be undone.": "Weet je zeker dat je deze verbinding wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", "Are you sure you want to delete this memory? This action cannot be undone.": "Weet je zeker dat je dit geheugen wilt verwijderen? Deze actie kan niet ongedaan worden gemaakt.", @@ -207,13 +205,13 @@ "Ask a question": "Stel een vraag", "Assistant": "Assistent", "Async Embedding Processing": "Asynchrone embeddingverwerking", + "At time of event": "Op het moment van de gebeurtenis", "Attach File From Knowledge": "Bestand uit kennis toevoegen", + "Attach Files": "Bestanden toevoegen", "Attach Knowledge": "Kennis toevoegen", "Attach Notes": "Notities toevoegen", "Attach Webpage": "Webpagina toevoegen", "Attention to detail": "Aandacht voor detail", - "Attach Files": "Bestanden toevoegen", - "At time of event": "Op het moment van de gebeurtenis", "Attribute for Mail": "Attribuut voor mail", "Attribute for Username": "Attribuut voor gebruikersnaam", "Audio": "Audio", @@ -269,6 +267,7 @@ "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Versterken of bestraffen van specifieke tokens voor beperkte reacties. Biaswaarden worden geklemd tussen -100 en 100 (inclusief). (Standaard: none)", "Brave": "Brave", "Brave Search API Key": "Brave Search API-sleutel", + "Break down complex requests into trackable steps": "Splits complexe verzoeken op in traceerbare stappen", "Browse and query knowledge bases": "Kennisbanken doorzoeken en bevragen", "Builtin Tools": "Ingebouwde tools", "Bullet List": "Lijst met opsommingstekens", @@ -280,7 +279,6 @@ "Bypass Embedding and Retrieval": "Embedding en ophalen omzeilen", "Bypass Web Loader": "Webloader omzeilen", "Cache Base Model List": "Basismodellijst cachen", - "Break down complex requests into trackable steps": "Splits complexe verzoeken op in traceerbare stappen", "Calendar": "Agenda", "Calendar deleted": "Agenda verwijderd", "Calendars": "Agenda's", @@ -452,9 +450,9 @@ "Copy Last Response": "Laatste antwoord kopiëren", "Copy link": "Kopieer link", "Copy Link": "Kopieer link", + "Copy Path": "Pad kopiëren", "Copy Prompt": "Prompt kopiëren", "Copy Share Link": "Deellink kopiëren", - "Copy Path": "Pad kopiëren", "Copy to clipboard": "Kopieer naar klembord", "Copy Token": "Token kopiëren", "Copy URL": "URL kopiëren", @@ -478,8 +476,8 @@ "Create new secret key": "Maak nieuwe geheime sleutel", "Create note": "Notitie maken", "Create Note": "Maak notitie", - "Create your first note by clicking on the plus button below.": "Maak je eerste notitie door op de plusknop hieronder te klikken.", "Create scheduled prompts that run automatically on a recurring basis.": "Maak geplande prompts die automatisch op terugkerende basis worden uitgevoerd.", + "Create your first note by clicking on the plus button below.": "Maak je eerste notitie door op de plusknop hieronder te klikken.", "Created at": "Gemaakt op", "Created At": "Gemaakt op", "Created by": "Gemaakt door", @@ -494,19 +492,19 @@ "Custom Gender": "Aangepast geslacht", "Custom Parameter Name": "Naam van aangepaste parameter", "Custom Parameter Value": "Waarde van aangepaste parameter", - "Daily Messages": "Dagelijkse berichten", "Daily": "Dagelijks", + "Daily Messages": "Dagelijkse berichten", "Danger Zone": "Gevarenzone", "Dark": "Donker", "Data Controls": "Gegevensbeheer", "Database": "Database", "Datalab Marker API": "Datalab Marker-API", + "Day": "Dag", "DD/MM/YYYY": "DD/MM/JJJJ", "DDGS Backend": "DDGS-backend", "December": "december", "Decrease UI Scale": "UI-schaal verkleinen", "Deepgram": "Deepgram", - "Day": "Dag", "Default": "Standaard", "Default (Open AI)": "Standaard (Open AI)", "Default (SentenceTransformers)": "Standaard (SentenceTransformers)", @@ -532,13 +530,13 @@ "Delete All": "Alles verwijderen", "Delete All Chats": "Verwijder alle chats", "Delete all contents inside this folder": "Alle inhoud in deze map verwijderen", + "Delete automation?": "Verwijder automatisering?", "Delete calendar": "Verwijder kalender", "Delete Calendar": "Verwijder kalender", "Delete Chat": "Verwijder chat", "Delete chat?": "Verwijder chat?", - "Delete File": "Bestand verwijderen", - "Delete automation?": "Verwijder automatisering?", "Delete Event": "Verwijder gebeurtenis?", + "Delete File": "Bestand verwijderen", "Delete folder?": "Verwijder map?", "Delete function?": "Verwijder functie?", "Delete Memory?": "Geheugen verwijderen?", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Afbeeldingsextractie uitschakelen", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Schakel afbeeldingsextractie uit de PDF uit. Als Use LLM is ingeschakeld, krijgen afbeeldingen automatisch beschrijvingen. Standaard is False.", "Disabled": "Uitgeschakeld", + "Disconnect OAuth": "", "Discover a function": "Ontdek een functie", "Discover a model": "Ontdek een model", "Discover a prompt": "Ontdek een prompt", @@ -680,10 +679,10 @@ "Embedding Concurrent Requests": "Gelijktijdige embeddingverzoeken", "Embedding Model": "Embedding Model", "Embedding Model Engine": "Embedding Model Engine", + "Emojis": "Emojis", "Empty message": "Leeg bericht", "Enable All": "Alles inschakelen", "Enable API Keys": "API-sleutels inschakelen", - "Emojis": "Emojis", "Enable autocomplete generation for chat messages": "Automatische aanvullingsgeneratie voor chatberichten inschakelen", "Enable Code Execution": "Code-uitvoer inschakelen", "Enable Code Interpreter": "Code-interpretatie inschakelen", @@ -768,6 +767,8 @@ "Enter New Password": "Voer nieuw wachtwoord in", "Enter Number of Steps (e.g. 50)": "Voeg aantal stappen toe (Bijv. 50)", "Enter Ollama Cloud API Key": "Voer Ollama Cloud API-sleutel in", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Voer Perplexity API-sleutel in", "Enter Perplexity Search API URL": "Voer Perplexity Search API-URL in", "Enter Playwright Timeout": "Voer Playwright-time-out in", @@ -837,9 +838,9 @@ "Error accessing directory": "Fout bij toegang tot map", "Error accessing Google Drive: {{error}}": "Fout bij het benaderen van Google Drive: {{error}}", "Error accessing media devices.": "Fout bij toegang tot media-apparaten.", + "Error deleting model: {{error}}": "Fout bij het verwijderen van model: {{error}}", "Error starting recording.": "Fout bij het starten van de opname.", "Error unloading model: {{error}}": "Fout bij het ontladen van model: {{error}}", - "Error deleting model: {{error}}": "Fout bij het verwijderen van model: {{error}}", "Error uploading file: {{error}}": "Fout bij het uploaden van bestand: {{error}}", "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Fout: Een model met de ID '{{modelId}}' bestaat al. Selecteer een andere ID om door te gaan.", "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Fout: Model-ID mag niet leeg zijn. Voer een geldige ID in om door te gaan.", @@ -896,11 +897,12 @@ "Failed to connect to {{URL}} terminal server": "Kan geen verbinding maken met {{URL}} terminalserver", "Failed to copy link": "Link kopiëren mislukt", "Failed to create API Key.": "Kan API Key niet aanmaken.", + "Failed to delete calendar": "Kalender verwijderen mislukt", "Failed to delete note": "Notitie verwijderen mislukt", + "Failed to disconnect": "", "Failed to download image": "Afbeelding downloaden mislukt", "Failed to extract content from the file: {{error}}": "Inhoud uit bestand extraheren mislukt: {{error}}", "Failed to extract content from the file.": "Inhoud uit bestand extraheren mislukt.", - "Failed to delete calendar": "Kalender verwijderen mislukt", "Failed to fetch models": "Kan modellen niet ophalen", "Failed to generate title": "Titel genereren mislukt", "Failed to import models": "Modellen importeren mislukt", @@ -981,32 +983,18 @@ "Follow Up Generation Prompt": "Prompt voor vervolggeneratie", "Follow up: {{question}}": "Vervolg: {{question}}", "Follow-Up Auto-Generation": "Automatische vervolggeneratie", + "Followed instructions perfectly": "Volgde instructies perfect", "for placeholders": "voor placeholders", "Force OCR": "OCR forceren", "Force OCR on all pages of the PDF. This can lead to worse results if you have good text in your PDFs. Defaults to False.": "Forceer OCR op alle pagina's van de PDF. Dit kan slechtere resultaten geven als je PDF's al goede tekst bevatten. Standaard is False.", + "Forge new paths": "Baan nieuwe paden", + "Form": "Formulier", "Format Lines": "Regels opmaken", "Format the lines in the output. Defaults to False. If set to True, the lines will be formatted to detect inline math and styles.": "Formatteer de regels in de uitvoer. Standaard is False. Als ingesteld op True worden regels opgemaakt om inline wiskunde en stijlen te detecteren.", "Formatting may be inconsistent from source.": "Opmaak kan afwijken van de bron.", "Forward": "Vooruit", "Forwards system user OAuth access token to authenticate": "Stuurt OAuth-toegangstoken van systeemgebruiker door voor authenticatie", "Forwards system user session credentials to authenticate": "Stuurt sessiegegevens van systeemgebruiker door voor authenticatie", - "Model accepts file inputs": "Model accepteert bestandsinvoer", - "Model can execute code and perform calculations": "Model kan code uitvoeren en berekeningen maken", - "Model can generate images based on text prompts": "Model kan afbeeldingen genereren op basis van tekstprompts", - "Model can search the web for information": "Model kan het web doorzoeken naar informatie", - "Model Capabilities": "Modelmogelijkheden", - "New File": "Nieuw bestand", - "New Function": "Nieuwe functie", - "New Group": "Nieuwe groep", - "New Knowledge": "Nieuwe kennis", - "New Model": "Nieuw model", - "New Note": "Nieuwe notitie", - "New Prompt": "Nieuwe prompt", - "Generated Image": "Gegenereerde afbeelding", - "Generated images will appear here": "Gegenereerde afbeeldingen verschijnen hier", - "Followed instructions perfectly": "Volgde instructies perfect", - "Forge new paths": "Baan nieuwe paden", - "Form": "Formulier", "Fr_day_of_week": "vr", "Full Context Mode": "Volledige contextmodus", "Function": "Functie", @@ -1035,6 +1023,8 @@ "Generate an image": "Genereer een afbeelding", "Generate and edit images": "Afbeeldingen genereren en bewerken", "Generate Message Pair": "Berichtenpaar genereren", + "Generated Image": "Gegenereerde afbeelding", + "Generated images will appear here": "Gegenereerde afbeeldingen verschijnen hier", "Generating search query": "Zoekopdracht genereren", "Generating...": "Genereren...", "Get current time and perform date/time calculations": "Haal de huidige tijd op en voer datum-/tijdberekeningen uit", @@ -1271,6 +1261,7 @@ "Maximum number of files allowed per folder.": "Maximaal aantal toegestane bestanden per map.", "Maximum number of files per folder is {{max}}.": "Maximum aantal bestanden per map is {{max}}.", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximaal 3 modellen kunnen tegelijkertijd worden gedownload. Probeer het later opnieuw.", + "May": "Mei", "MBR": "MBR", "MCP": "MCP", "MCP support is experimental and its specification changes often, which can lead to incompatibilities. OpenAPI specification support is directly maintained by the Open WebUI team, making it the more reliable option for compatibility.": "MCP-ondersteuning is experimenteel en de specificatie verandert vaak, wat tot incompatibiliteiten kan leiden. Ondersteuning voor de OpenAPI-specificatie wordt direct onderhouden door het Open WebUI-team, waardoor dit de betrouwbaardere optie voor compatibiliteit is.", @@ -1278,7 +1269,6 @@ "Member removed successfully": "Lid succesvol verwijderd", "members": "leden", "Members": "Leden", - "May": "Mei", "Members added successfully": "Leden succesvol toegevoegd", "Memories": "Geheugen", "Memories accessible by LLMs will be shown here.": "Geheugen toegankelijk voor LLMs wordt hier getoond.", @@ -1315,8 +1305,13 @@ "Model {{name}} is now {{status}}": "Model {{name}} is nu {{status}}", "Model {{name}} is now hidden": "Model {{name}} is nu verborgen", "Model {{name}} is now visible": "Model {{name}} is nu zichtbaar", + "Model accepts file inputs": "Model accepteert bestandsinvoer", "Model accepts image inputs": "Model accepteerd afbeeldingsinvoer", "Model can access Open Terminal for command execution and file management": "Model heeft toegang tot Open Terminal voor uitvoeren van opdrachten en bestandsbeheer", + "Model can execute code and perform calculations": "Model kan code uitvoeren en berekeningen maken", + "Model can generate images based on text prompts": "Model kan afbeeldingen genereren op basis van tekstprompts", + "Model can search the web for information": "Model kan het web doorzoeken naar informatie", + "Model Capabilities": "Modelmogelijkheden", "Model created successfully!": "Model succesvol gecreëerd", "Model filesystem path detected. Model shortname is required for update, cannot continue.": "Model filesystem path gedetecteerd. Model shortname is vereist voor update, kan niet doorgaan.", "Model Filtering": "Modelfiltratie", @@ -1360,14 +1355,21 @@ "Name your knowledge base": "Geef je kennisbasis een naam", "Name, prompt, and model are required": "Naam, prompt en model zijn verplicht", "Native": "Native", + "Never": "Nooit", "New": "Nieuw", + "New Automation": "Nieuwe automatisering", "New Button": "Nieuwe knop", "New Chat": "Nieuwe Chat", - "Never": "Nooit", - "New Automation": "Nieuwe automatisering", "New Event": "Nieuwe gebeurtenis", + "New File": "Nieuw bestand", "New Folder": "Nieuwe map", + "New Function": "Nieuwe functie", + "New Group": "Nieuwe groep", + "New Knowledge": "Nieuwe kennis", + "New Model": "Nieuw model", + "New Note": "Nieuwe notitie", "New Password": "Nieuw Wachtwoord", + "New Prompt": "Nieuwe prompt", "New Skill": "Nieuwe vaardigheid", "New Temporary Chat": "Nieuwe tijdelijke chat", "New Terminal": "Nieuwe terminal", @@ -1375,24 +1377,24 @@ "New Webhook": "Nieuwe webhook", "new-channel": "nieuw-kanaal", "Next message": "Volgend bericht", + "Next run": "Volgende uitvoering", "No access grants. Private to you.": "Geen toegangsrechten. Alleen privé voor jou.", "No activity data": "Geen activiteitsgegevens", "No authentication": "Geen authenticatie", + "No automations found": "Geen automatiseringen gevonden", "No chats found": "Geen chats gevonden", "No chats found for this user.": "Geen chats gevonden voor deze gebruiker.", "No chats found.": "Geen chats gevonden.", "No content": "Geen inhoud", - "Next run": "Volgende uitvoering", - "No automations found": "Geen automatiseringen gevonden", "No content found": "Geen content gevonden", "No content to speak": "Geen inhoud om over te spreken", "No conversation to save": "Geen gesprek om op te slaan", "No data": "Geen gegevens", "No data found": "Geen gegevens gevonden", "No distance available": "Geen afstand beschikbaar", + "No execution logs available yet": "Geen uitvoerlogs beschikbaar", "No expiration can pose security risks.": "Geen vervaldatum kan veiligheidsrisico's opleveren.", "No feedback found": "Geen feedback gevonden", - "No execution logs available yet": "Geen uitvoerlogs beschikbaar", "No file selected": "Geen bestand geselecteerd", "No files found": "Geen bestanden gevonden", "No files in this knowledge base.": "Geen bestanden in deze kennisbank.", @@ -1437,9 +1439,9 @@ "Not factually correct": "Niet feitelijk juist", "Not helpful": "Niet nuttig", "Not Registered": "Niet geregistreerd", + "Not scheduled": "Niet ingepland", "Note": "Notitie", "Note deleted successfully": "Notitie succesvol verwijderd", - "Not scheduled": "Niet ingepland", "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Opmerking: Als je een minimumscore instelt, levert de zoekopdracht alleen documenten op met een score groter dan of gelijk aan de minimumscore.", "Notes": "Aantekeningen", "Notes Public Sharing": "Openbaar delen van notities", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Statisch)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "oktober", "Off": "Uit", "Okay, Let's Go!": "Oké, laten we gaan!", @@ -1512,12 +1515,14 @@ "or": "of", "Ordered List": "Genummerde lijst", "Other": "Andere", - "Output": "Uitvoer", "out of": "van de", + "Output": "Uitvoer", "OUTPUT": "UITVOER", "Output format": "Uitvoerformaat", "Output Format": "Uitvoerformaat", "Overview": "Overzicht", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "pagina", "Page": "Pagina", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Paginamodus maakt per pagina een document. De enkele modus combineert alle pagina's in één document voor betere chunking over paginagrens heen.", @@ -1635,9 +1640,9 @@ "Reason": "Reden", "Reasoning Effort": "Redeneerinspanning", "Reasoning Tags": "Redeneertags", - "Record": "Opnemen", "Recently Used": "Onlangs gebruikt", "Reconnected": "Opnieuw verbonden", + "Record": "Opnemen", "Record voice": "Neem stem op", "Redirecting you to Open WebUI Community": "Je wordt doorgestuurd naar OpenWebUI Community", "Reduces the probability of generating nonsense. A higher value (e.g. 100) will give more diverse answers, while a lower value (e.g. 10) will be more conservative.": "Vermindert de kans op het genereren van onzin. Een hogere waarde (bijv. 100) zal meer diverse antwoorden geven, terwijl een lagere waarde (bijv. 10) conservatiever zal zijn.", @@ -1673,14 +1678,14 @@ "Renamed to {{name}}": "Hernoemd naar {{name}}", "Render Markdown in Previews": "Markdown renderen in voorvertoningen", "Reorder Models": "Herschik modellen", + "Repeats": "Herhalingen", "Reply": "Antwoorden", "Reply in Thread": "Antwoord in draad", "Reply to thread...": "Reageren op draad...", "Replying to {{NAME}}": "Reageren op {{NAME}}", "required": "vereist", - "Reranking Engine": "Herschikkingsengine", - "Repeats": "Herhalingen", "Reranking Batch Size": "Batchgrootte voor herordenen", + "Reranking Engine": "Herschikkingsengine", "Reranking Model": "Reranking Model", "Reset": "Herstellen", "Reset All Models": "Herstel alle modellen", @@ -1707,11 +1712,11 @@ "RTL": "RNL", "Run": "Uitvoeren", "Run All": "Alles uitvoeren", + "Run now": "Nu uitvoeren", + "Run Now": "Nu uitvoeren", "Running": "Aan het uitvoeren", "Running...": "Aan het uitvoeren...", "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Voert embeddingtaken gelijktijdig uit om de verwerking te versnellen. Schakel uit als rate limits een probleem worden.", - "Run now": "Nu uitvoeren", - "Run Now": "Nu uitvoeren", "Sa_day_of_week": "za", "Save": "Opslaan", "Save & Create": "Opslaan & Creëren", @@ -1720,14 +1725,14 @@ "Save Chat": "Chat opslaan", "Saved": "Opgeslagen", "Saving chat logs directly to your browser's storage is no longer supported. Please take a moment to download and delete your chat logs by clicking the button below. Don't worry, you can easily re-import your chat logs to the backend through": "Chat logs direct opslaan in de opslag van je browser wordt niet langer ondersteund. Neem even de tijd om je chat logs te downloaden en te verwijderen door op de knop hieronder te klikken. Maak je geen zorgen, je kunt je chat logs eenvoudig opnieuw importeren naar de backend via", + "Schedule": "Planning", + "Scheduled time must be in the future": "Ingeplande tijd moet in de toekomst liggen", "Scroll On Branch Change": "Scrollen bij wijziging van branch", "Search": "Zoeken", "Search a model": "Zoek een model", "Search all emojis": "Alle emoji's zoeken", "Search and manage user memories": "Gebruikersherinneringen zoeken en beheren", "Search and view user chat history": "Gebruikerschatgeschiedenis zoeken en bekijken", - "Schedule": "Planning", - "Scheduled time must be in the future": "Ingeplande tijd moet in de toekomst liggen", "Search Automations": "Zoek automatiseringen", "Search Base": "Zoeken naar basis", "Search channels and channel messages": "Kanalen en kanaalberichten zoeken", @@ -1907,16 +1912,16 @@ "Start a new conversation": "Start een nieuw gesprek", "Start of the channel": "Begin van het kanaal", "Start Tag": "Starttag", + "Starting in {{count}} minutes_one": "Begint over {{count}} minuut", + "Starting in {{count}} minutes_other": "Begint over {{count}} minuten", + "Starting in 1 minute": "Begint over 1 minuut", "Starting kernel...": "Kernel wordt gestart...", + "Starting now": "Begint nu", + "State": "Status", "Status": "Status", "Status cleared successfully": "Status succesvol gewist", "Status updated successfully": "Status succesvol bijgewerkt", "Status Updates": "Statusupdates", - "State": "Status", - "Starting in {{count}} minutes_one": "Begint over {{count}} minuut", - "Starting in {{count}} minutes_other": "Begint over {{count}} minuten", - "Starting in 1 minute": "Begint over 1 minuut", - "Starting now": "Begint nu", "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Stappen", "Stop": "Stop", @@ -1933,10 +1938,10 @@ "STT Model": "STT Model", "STT Settings": "STT Instellingen", "Stylized PDF Export": "Gestileerde PDF-export", + "Su_day_of_week": "zo", "Submit question": "Vraag indienen", "Submit suggestion": "Suggestie indienen", "Subtitle": "Ondertitel", - "Su_day_of_week": "zo", "Success": "Succes", "Successfully imported {{userCount}} users.": "{{userCount}} gebruikers succesvol geimporteerd.", "Successfully updated.": "Succesvol bijgewerkt.", @@ -1964,8 +1969,8 @@ "Talk to Model": "Praat met model", "Tap to interrupt": "Tik om te onderbreken", "Task List": "Takenlijst", - "Task Model": "Taakmodel", "Task Management": "Taakbeheer", + "Task Model": "Taakmodel", "Tasks": "Taken", "tasks completed": "taken voltooid", "Tavily API Key": "Tavily API-sleutel", @@ -2020,12 +2025,13 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Deze optie stelt het maximum aantal tokens in dat het model kan genereren in zijn antwoord. Door deze limiet te verhogen, kan het model langere antwoorden geven, maar het kan ook de kans vergroten dat er onbehulpzame of irrelevante inhoud wordt gegenereerd.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Deze optie verwijdert alle bestaande bestanden in de collectie en vervangt ze door nieuw geüploade bestanden.", "This response was generated by \"{{model}}\"": "Dit antwoord is gegenereerd door \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Dit zal verwijderen", "This will delete {{NAME}} and all its contents.": "Dit zal {{NAME}} verwijderen en al zijn inhoud.", "This will delete all models including custom models": "Dit zal alle modellen, ook aangepaste modellen, verwijderen", "This will delete all models including custom models and cannot be undone.": "Dit zal alle modellen, ook aangepaste modellen, verwijderen en kan niet ongedaan worden gemaakt", - "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dit zal de kennisdatabase resetten en alle bestanden synchroniseren. Wil je doorgaan?", "This will permanently delete the calendar \"{{name}}\" and all its events. This action cannot be undone.": "Dit zal de kalender \"{{name}}\" en alle gebeurtenissen permanent verwijderen. Deze actie kan niet ongedaan worden gemaakt.", + "This will reset the knowledge base and sync all files. Do you wish to continue?": "Dit zal de kennisdatabase resetten en alle bestanden synchroniseren. Wil je doorgaan?", "Thorough explanation": "Grondige uitleg", "Thought": "Gedachte", "Thought for {{DURATION}}": "Dacht {{DURATION}} na", @@ -2036,9 +2042,9 @@ "Tika": "Tika", "Tika Server URL required.": "Tika Server-URL vereist", "Tiktoken": "Tiktoken", + "Time": "Tijd", "Time & Calculation": "Tijd en berekening", "Timeout": "Time-out", - "Time": "Tijd", "Title": "Titel", "Title Auto-Generation": "Automatische titelgeneratie", "Title cannot be an empty string.": "Titel kan niet leeg zijn.", @@ -2055,6 +2061,7 @@ "To select toolkits here, add them to the \"Tools\" workspace first.": "Om hier gereedschapssets te selecteren, voeg ze eerst aan de \"Gereedschappen\" Werkplaats toe.", "Toast notifications for new updates": "Toon notificaties voor nieuwe updates", "Today": "Vandaag", + "Today at": "Vandaag om", "Today at {{LOCALIZED_TIME}}": "Vandaag om {{LOCALIZED_TIME}}", "Toggle {{COUNT}} sources": "Schakel {{COUNT}} bronnen om", "Toggle 1 source": "Schakel 1 bron om", @@ -2063,7 +2070,6 @@ "Toggle Sidebar": "Zijbalk omzetten", "Toggle status history": "Statusgeschiedenis omzetten", "Toggle whether current connection is active.": "Schakel in of de huidige verbinding actief is.", - "Today at": "Vandaag om", "Token": "Token", "Token counts are estimates and may not reflect actual API usage": "Tokenaantallen zijn schattingen en komen mogelijk niet overeen met het werkelijke API-gebruik", "tokens": "tokens", diff --git a/src/lib/i18n/locales/pa-IN/translation.json b/src/lib/i18n/locales/pa-IN/translation.json index d29adc4b55..84c346acaf 100644 --- a/src/lib/i18n/locales/pa-IN/translation.json +++ b/src/lib/i18n/locales/pa-IN/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "ਸਹੀ ਜਾਣਕਾਰੀ", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "ਚੈਟ ਲਾਗ ਸੰਭਾਲਣ ਲਈ ਕਾਰਵਾਈ ਲੋੜੀਂਦੀ ਹੈ", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "ਇੱਕ ਸਹਾਇਕ", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "ਬੰਦ", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "ਇੱਕ ਮਾਡਲ ਲੱਭੋ", "Discover a prompt": "ਇੱਕ ਪ੍ਰੰਪਟ ਖੋਜੋ", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "ਕਦਮਾਂ ਦੀ ਗਿਣਤੀ ਦਰਜ ਕਰੋ (ਉਦਾਹਰਣ ਲਈ 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API ਕੁੰਜੀ ਬਣਾਉਣ ਵਿੱਚ ਅਸਫਲ।", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "ਅਕਤੂਬਰ", "Off": "ਬੰਦ", "Okay, Let's Go!": "ਠੀਕ ਹੈ, ਚੱਲੋ ਚੱਲੀਏ!", @@ -1518,6 +1521,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index 7143c47bc7..15a573aa23 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -60,7 +60,6 @@ "Account Activation Pending": "Aktywacja konta w toku", "Accurate information": "Precyzyjne informacje", "Action": "Akcja", - "Action not found": "Nie znaleziono akcji", "Action Required for Chat Log Storage": "Wymagane działanie, aby zapisać historię czatu", "Actions": "Akcje", "Activate": "Aktywuj", @@ -161,7 +160,6 @@ "Always Play Notification Sound": "Zawsze odtwarzaj dźwięk powiadomienia", "Amazing": "Niesamowite", "an assistant": "asystent", - "An error occurred while fetching the explanation": "Wystąpił błąd podczas pobierania wyjaśnienia", "Analytics": "Analityka", "Analyzed": "Przeanalizowano", "Analyzing...": "Analizowanie...", @@ -581,6 +579,7 @@ "Disable Image Extraction": "Wyłącz ekstrakcję obrazów", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Wyłącz wyciąganie obrazów z PDF. Jeśli używasz LLM, obrazy będą automatycznie opisywane. Domyślnie Wyłączone.", "Disabled": "Wyłączone", + "Disconnect OAuth": "", "Discover a function": "Odkryj funkcję", "Discover a model": "Odkryj model", "Discover a prompt": "Odkryj prompt", @@ -770,6 +769,8 @@ "Enter New Password": "Wprowadź nowe hasło", "Enter Number of Steps (e.g. 50)": "Wprowadź liczbę kroków (np. 50)", "Enter Ollama Cloud API Key": "Wprowadź klucz API Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Wprowadź klucz API Perplexity", "Enter Perplexity Search API URL": "Wprowadź URL API Perplexity Search", "Enter Playwright Timeout": "Wprowadź timeout Playwright", @@ -900,6 +901,7 @@ "Failed to create API Key.": "Nie udało się utworzyć klucza API.", "Failed to delete calendar": "", "Failed to delete note": "Nie udało się usunąć notatki", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "Nie udało się wyodrębnić treści z pliku: {{error}}", "Failed to extract content from the file.": "Nie udało się wyodrębnić treści z pliku.", @@ -1454,6 +1456,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Październik", "Off": "Wył.", "Okay, Let's Go!": "OK, Jedziemy!", @@ -1520,6 +1523,8 @@ "Output format": "Format wyjściowy", "Output Format": "Format wyjściowy", "Overview": "Przegląd", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "strona", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2026,6 +2031,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Ustawia maksymalną liczbę tokenów w odpowiedzi. Zwiększenie pozwala na dłuższe odpowiedzi.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Ta opcja usunie wszystkie pliki z kolekcji i zastąpi nowymi.", "This response was generated by \"{{model}}\"": "Odpowiedź wygenerowana przez \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "To usunie", "This will delete {{NAME}} and all its contents.": "To usunie {{NAME}} i całą zawartość.", "This will delete all models including custom models": "To usunie wszystkie modele (w tym własne).", diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index ca721304fe..730fd439e7 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Ativação da Conta Pendente", "Accurate information": "Informações precisas", "Action": "Ação", - "Action not found": "Ação não encontrada", "Action Required for Chat Log Storage": "Ação necessária para salvar o registro do chat", "Actions": "Ações", "Activate": "Ativar", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Sempre reproduzir som de notificação", "Amazing": "Incrível", "an assistant": "um assistente", - "An error occurred while fetching the explanation": "Ocorreu um erro ao buscar a explicação", "Analytics": "Análises", "Analyzed": "Analisado", "Analyzing...": "Analisando...", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Desativar extração de imagem", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Desabilite a extração de imagens do PDF. Se a opção Usar LLM estiver habilitada, as imagens serão legendadas automaticamente. O padrão é Falso.", "Disabled": "Desativado", + "Disconnect OAuth": "", "Discover a function": "Descubra uma função", "Discover a model": "Descubra um modelo", "Discover a prompt": "Descubra um prompt", @@ -769,6 +768,8 @@ "Enter New Password": "Digite uma nova senha", "Enter Number of Steps (e.g. 50)": "Digite o Número de Passos (por exemplo, 50)", "Enter Ollama Cloud API Key": "Insira a chave da API do Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Insira a chave da API Perplexity", "Enter Perplexity Search API URL": "Insira a URL da API de pesquisa Perplexity", "Enter Playwright Timeout": "Insira o tempo limite do Playwright", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Falha ao criar a Chave API.", "Failed to delete calendar": "Falha ao excluir calendário", "Failed to delete note": "Falha ao excluir a nota", + "Failed to disconnect": "", "Failed to download image": "Falha ao baixar a imagem", "Failed to extract content from the file: {{error}}": "Falha ao extrair conteúdo do arquivo: {{error}}", "Failed to extract content from the file.": "Falha ao extrair conteúdo do arquivo.", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Estático)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Outubro", "Off": "Desligado", "Okay, Let's Go!": "Ok, Vamos Lá!", @@ -1519,6 +1522,8 @@ "Output format": "Formato de saída", "Output Format": "Formato de Saída", "Overview": "Visão Geral", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "página", "Page": "Página", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "O modo de página cria um documento por página. O modo único combina todas as páginas em um único documento para melhor divisão entre páginas.", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Esta opção define o número máximo de tokens que o modelo pode gerar em sua resposta. Aumentar esse limite permite que o modelo forneça respostas mais longas, mas também pode aumentar a probabilidade de geração de conteúdo inútil ou irrelevante.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Essa opção deletará todos os arquivos existentes na coleção e todos eles serão substituídos.", "This response was generated by \"{{model}}\"": "Esta resposta foi gerada por \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Isso vai excluir", "This will delete {{NAME}} and all its contents.": "Esta ação excluirá {{NAME}} e todos seus conteúdos.", "This will delete all models including custom models": "Isto vai excluir todos os modelos, incluindo personalizados", diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index 1b9c2e7e48..ac1c442590 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Ativação da Conta Pendente", "Accurate information": "Informações precisas", "Action": "Ação", - "Action not found": "Ação não encontrada", "Action Required for Chat Log Storage": "É necessária uma ação para guardar o registo da conversa", "Actions": "Ações", "Activate": "Ativar", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "Sempre Reproduzir Som de Notificação", "Amazing": "Incrível", "an assistant": "um assistente", - "An error occurred while fetching the explanation": "Ocorreu um erro ao obter a explicação", "Analytics": "Análise", "Analyzed": "Analisado", "Analyzing...": "A analisar...", @@ -580,6 +578,7 @@ "Disable Image Extraction": "Desativar Extração de Imagens", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Desabilitar a extração de imgem do PDF. Se a utilização de LLM estiver ativa, as imagens irão ser automaticamente legendadas. Predefenido para Falso.", "Disabled": "Desativado", + "Disconnect OAuth": "", "Discover a function": "Descobrir uma função", "Discover a model": "Descubra um modelo", "Discover a prompt": "Descobrir um prompt", @@ -769,6 +768,8 @@ "Enter New Password": "Introduzir Palavra-passe", "Enter Number of Steps (e.g. 50)": "Introduzir o Número de Etapas (por exemplo, 50)", "Enter Ollama Cloud API Key": "Introduzir Chave da API do Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Introduzir Chave da API do Perplexity Search", "Enter Perplexity Search API URL": "Introduzir URL da Chave API do Perplexity Search", "Enter Playwright Timeout": "Introduzir Tempo Limite do Playwright", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Falha ao criar a Chave da API.", "Failed to delete calendar": "", "Failed to delete note": "Falha ao apagar a nota", + "Failed to disconnect": "", "Failed to download image": "Falha ao transferir a imagem", "Failed to extract content from the file: {{error}}": "Falha ao extrair conteúdo do ficheiro: {{error}}", "Failed to extract content from the file.": "Falha ao extrair conteúdo do ficheiro.", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "ID do OAuth", + "OAuth session disconnected": "", "October": "Outubro", "Off": "Desligado", "Okay, Let's Go!": "Ok, Vamos Lá!", @@ -1519,6 +1522,8 @@ "Output format": "Formato de Saída", "Output Format": "Formato de Saída", "Overview": "Visão Geral", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "página", "Page": "Página", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "O modo de página cria um documento por página. O modo único combina todas as páginas em um único documento para melhor segmentação entre os limites das páginas.", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Esta opção define o número máximo de tokens que o modelo pode gerar em sua resposta. Aumentar esse limite permite que o modelo forneça respostas mais longas, mas também pode aumentar a probabilidade de conteúdo inútil ou irrelevante ser gerado.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Esta opção irá excluir todos os arquivos existentes na coleção e substituí-los por arquivos recém-carregados.", "This response was generated by \"{{model}}\"": "Esta resposta foi gerada por \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Isto irá excluir", "This will delete {{NAME}} and all its contents.": "Isto irá excluir {{NAME}} e todo o seu conteúdo.", "This will delete all models including custom models": "Isto irá excluir todos os modelos, incluindo os modelos personalizados", diff --git a/src/lib/i18n/locales/ro-RO/translation.json b/src/lib/i18n/locales/ro-RO/translation.json index 3028840716..2532909db5 100644 --- a/src/lib/i18n/locales/ro-RO/translation.json +++ b/src/lib/i18n/locales/ro-RO/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Activarea contului în așteptare", "Accurate information": "Informații precise", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Este necesară o acțiune pentru salvarea jurnalului de chat", "Actions": "Acțiuni", "Activate": "Activează", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "", "Amazing": "Uimitor", "an assistant": "un asistent", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Analizat", "Analyzing...": "Se analizează...", @@ -580,6 +578,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Dezactivat", + "Disconnect OAuth": "", "Discover a function": "Descoperă o funcție", "Discover a model": "Descoperă un model", "Discover a prompt": "Descoperă un prompt", @@ -769,6 +768,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Introduceți Numărul de Pași (de ex. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Crearea cheii API a eșuat.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Octombrie", "Off": "Dezactivat", "Okay, Let's Go!": "Ok, Să Începem!", @@ -1519,6 +1522,8 @@ "Output format": "Formatul de ieșire", "Output Format": "", "Overview": "Privire de ansamblu", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "pagina", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Această opțiune va șterge toate fișierelor existente din colecție și le va înlocui cu fișierele nou încărcate.", "This response was generated by \"{{model}}\"": "Acest răspuns a fost generat de \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Aceasta va șterge", "This will delete {{NAME}} and all its contents.": "Acest lucru va șterge {{NAME}} și toate conținuturile sale.", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index 954d8f7f4e..cb7a5ce94a 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -60,7 +60,6 @@ "Account Activation Pending": "Ожидание активации учетной записи", "Accurate information": "Точная информация", "Action": "Действие", - "Action not found": "Действие не найдено", "Action Required for Chat Log Storage": "Требуется действие для сохранения журнала чата", "Actions": "Действия", "Activate": "Активировать", @@ -161,7 +160,6 @@ "Always Play Notification Sound": "Всегда проигрывать звук уведомления", "Amazing": "Удивительно", "an assistant": "ассистент", - "An error occurred while fetching the explanation": "Произошла ошибка при получении объяснения", "Analytics": "Аналитика", "Analyzed": "Проанализировано", "Analyzing...": "Анализирую...", @@ -581,6 +579,7 @@ "Disable Image Extraction": "Отключить извлечение изображений", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Отключить извлечение изображений из PDF. Если включена параметр Использовать LLM, изображения будут подписаны автоматически. По умолчанию установлено значение Выкл.", "Disabled": "Отключено", + "Disconnect OAuth": "", "Discover a function": "Найти функцию", "Discover a model": "Найти модель", "Discover a prompt": "Найти промпт", @@ -770,6 +769,8 @@ "Enter New Password": "Введите новый пароль", "Enter Number of Steps (e.g. 50)": "Введите количество шагов (например, 50)", "Enter Ollama Cloud API Key": "Введите API-ключ Ollama Cloud", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Введите ключ API Perplexity", "Enter Perplexity Search API URL": "Введите URL Perplexity Search API", "Enter Playwright Timeout": "Введите таймаут для Playwright", @@ -900,6 +901,7 @@ "Failed to create API Key.": "Не удалось создать ключ API.", "Failed to delete calendar": "", "Failed to delete note": "Не удалось удалить заметку", + "Failed to disconnect": "", "Failed to download image": "Не удалось загрузить изображение", "Failed to extract content from the file: {{error}}": "Не удалось извлечь содержимое из файла: {{error}}", "Failed to extract content from the file.": "Не удалось извлечь содержимое из файла.", @@ -1454,6 +1456,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (Static)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Октябрь", "Off": "Выключено", "Okay, Let's Go!": "Давайте начнём!", @@ -1520,6 +1523,8 @@ "Output format": "Формат вывода", "Output Format": "Формат Вывода", "Overview": "Обзор", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "страница", "Page": "Страница", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "Постраничный режим создаёт отдельный документ для каждой страницы. Общий режим объединяет все страницы в один документ для более качественного разбиения на фрагменты без привязки к границам страниц.", @@ -2026,6 +2031,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Этот параметр устанавливает максимальное количество токенов, которые модель может генерировать в своем ответе. Увеличение этого ограничения позволяет модели предоставлять более длинные ответы, но также может увеличить вероятность создания бесполезного или нерелевантного контента.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Эта опция удалит все существующие файлы в коллекции и заменит их вновь загруженными файлами.", "This response was generated by \"{{model}}\"": "Этот ответ был сгенерирован для \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Это приведет к удалению", "This will delete {{NAME}} and all its contents.": "При этом будет удален {{NAME}} и все его содержимое.", "This will delete all models including custom models": "Это приведет к удалению всех моделей, включая пользовательские модели.", diff --git a/src/lib/i18n/locales/sk-SK/translation.json b/src/lib/i18n/locales/sk-SK/translation.json index 0ecf193014..5d3ea9dc74 100644 --- a/src/lib/i18n/locales/sk-SK/translation.json +++ b/src/lib/i18n/locales/sk-SK/translation.json @@ -60,7 +60,6 @@ "Account Activation Pending": "Čaká sa na aktiváciu účtu", "Accurate information": "Presné informácie", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Na uloženie záznamu chatu je potrebná akcia", "Actions": "Akcie", "Activate": "", @@ -161,7 +160,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "asistent", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -581,6 +579,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Zakázané", + "Disconnect OAuth": "", "Discover a function": "Objaviť funkciu", "Discover a model": "Objaviť model", "Discover a prompt": "Objaviť prompt", @@ -770,6 +769,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Zadajte počet krokov (napr. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -900,6 +901,7 @@ "Failed to create API Key.": "Nepodarilo sa vytvoriť API kľúč.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1454,6 +1456,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Október", "Off": "Vypnuté", "Okay, Let's Go!": "Dobre, poďme na to!", @@ -1520,6 +1523,8 @@ "Output format": "Formát výstupu", "Output Format": "", "Overview": "Prehľad", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "stránka", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2026,6 +2031,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Táto voľba odstráni všetky existujúce súbory v kolekcii a nahradí ich novo nahranými súbormi.", "This response was generated by \"{{model}}\"": "Táto odpoveď bola vygenerovaná pomocou \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Toto odstráni", "This will delete {{NAME}} and all its contents.": "Týmto dôjde k odstráneniu {{NAME}} a všetkých jeho obsahov.", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/sr-RS/translation.json b/src/lib/i18n/locales/sr-RS/translation.json index 647eb187b5..db5e660eee 100644 --- a/src/lib/i18n/locales/sr-RS/translation.json +++ b/src/lib/i18n/locales/sr-RS/translation.json @@ -59,7 +59,6 @@ "Account Activation Pending": "Налози за активирање", "Accurate information": "Прецизне информације", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Потребна је радња за чување дневника ћаскања", "Actions": "Радње", "Activate": "", @@ -160,7 +159,6 @@ "Always Play Notification Sound": "", "Amazing": "Невероватно", "an assistant": "помоћник", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -580,6 +578,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Онемогућено", + "Disconnect OAuth": "", "Discover a function": "Откријте функцију", "Discover a model": "Откријте модел", "Discover a prompt": "Откриј упит", @@ -769,6 +768,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Унесите број корака (нпр. 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -899,6 +900,7 @@ "Failed to create API Key.": "Неуспешно стварање API кључа.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1453,6 +1455,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "Октобар", "Off": "Искључено", "Okay, Let's Go!": "У реду, хајде да кренемо!", @@ -1519,6 +1522,8 @@ "Output format": "Формат излаза", "Output Format": "", "Overview": "Преглед", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "страница", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2023,6 +2028,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Ово ће обрисати", "This will delete {{NAME}} and all its contents.": "Ово ће обрисати {{NAME}} и сав садржај унутар.", "This will delete all models including custom models": "Ово ће обрисати све моделе укључујући прилагођене моделе", diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index 9915d73f25..aa2784d64b 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Kontoaktivering väntar", "Accurate information": "Exakt information", "Action": "Åtgärd", - "Action not found": "Åtgärd hittades inte", "Action Required for Chat Log Storage": "Åtgärd krävs för att spara chattloggen", "Actions": "Åtgärder", "Activate": "Aktivera", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Spela alltid aviseringsljud", "Amazing": "Fantastiskt", "an assistant": "en assistent", - "An error occurred while fetching the explanation": "", "Analytics": "Analys", "Analyzed": "Analyserad", "Analyzing...": "Analyserar...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Inaktivera bildextrahering", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "Inaktivera bildextrahering från PDF-filen. Om Använd LLM är aktiverat kommer bilder att automatiskt bildtextas. Standardvärdet är False.", "Disabled": "Inaktiverad", + "Disconnect OAuth": "", "Discover a function": "Upptäck en funktion", "Discover a model": "Upptäck en modell", "Discover a prompt": "Upptäck en instruktion", @@ -768,6 +767,8 @@ "Enter New Password": "Ange nytt lösenord", "Enter Number of Steps (e.g. 50)": "Ange antal steg (t.ex. 50)", "Enter Ollama Cloud API Key": "Ange Ollama Cloud API-nyckel", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Ange Perplexity API-nyckel", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Ange Playwright-timeout", @@ -898,6 +899,7 @@ "Failed to create API Key.": "Misslyckades med att skapa API-nyckel.", "Failed to delete calendar": "", "Failed to delete note": "Misslyckades med att ta bort anteckning", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "oktober", "Off": "Av", "Okay, Let's Go!": "Okej, nu kör vi!", @@ -1518,6 +1521,8 @@ "Output format": "Utdataformat", "Output Format": "Utdataformat", "Overview": "Översikt", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "sida", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Det här alternativet anger det maximala antalet tokens som modellen kan generera i sitt svar. Om du ökar den här gränsen kan modellen ge längre svar, men det kan också öka sannolikheten för att det genereras innehåll som inte är till hjälp eller irrelevant.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Detta alternativ tar bort alla befintliga filer i samlingen och ersätter dem med nyligen uppladdade filer.", "This response was generated by \"{{model}}\"": "Det här svaret genererades av \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Detta kommer att radera", "This will delete {{NAME}} and all its contents.": "Detta kommer att radera {{NAME}} och allt dess innehåll.", "This will delete all models including custom models": "Detta kommer att radera alla modeller inklusive anpassade modeller", diff --git a/src/lib/i18n/locales/ta-IN/translation.json b/src/lib/i18n/locales/ta-IN/translation.json index 646aec1471..d5ceb6080a 100644 --- a/src/lib/i18n/locales/ta-IN/translation.json +++ b/src/lib/i18n/locales/ta-IN/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "கணக்கு செயல்படுத்தல் நிலுவையில் உள்ளது", "Accurate information": "துல்லியமான தகவல்", "Action": "செயல்", - "Action not found": "நடவடிக்கை கிடைக்கவில்லை", "Action Required for Chat Log Storage": "அரட்டை பதிவு சேமிப்பகத்திற்கு நடவடிக்கை தேவை", "Actions": "செயல்கள்", "Activate": "செயல்படுத்து", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "அறிவிப்பு ஒலியை எப்போதும் இயக்கவும்", "Amazing": "அற்புதம்", "an assistant": "ஒரு உதவியாளர்", - "An error occurred while fetching the explanation": "விளக்கத்தைப் பெறும்போது பிழை ஏற்பட்டது", "Analytics": "பகுப்பாய்வு", "Analyzed": "பகுப்பாய்வு செய்யப்பட்டது", "Analyzing...": "பகுப்பாய்வு செய்கிறது...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "படத்தை பிரித்தெடுப்பதை முடக்கு", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDF இலிருந்து படத்தை பிரித்தெடுப்பதை முடக்கு. LLMஐப் பயன்படுத்துதல் இயக்கப்பட்டிருந்தால், படங்கள் தானாகவே தலைப்பிடப்படும். இயல்புநிலையிலிருந்து தவறு.", "Disabled": "முடக்கப்பட்டது", + "Disconnect OAuth": "", "Discover a function": "ஒரு செயல்பாட்டைக் கண்டறியவும்", "Discover a model": "ஒரு மாதிரியைக் கண்டறியவும்", "Discover a prompt": "ஒரு தூண்டுதலைக் கண்டறியவும்", @@ -768,6 +767,8 @@ "Enter New Password": "புதிய கடவுச்சொல்லை உள்ளிடவும்", "Enter Number of Steps (e.g. 50)": "படிகளின் எண்ணிக்கையை உள்ளிடவும் (எ.கா. 50)", "Enter Ollama Cloud API Key": "Ollama கிளவுட் API விசையை உள்ளிடவும்", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "குழப்பம் API விசையை உள்ளிடவும்", "Enter Perplexity Search API URL": "குழப்பமான தேடலை உள்ளிடவும் API URL", "Enter Playwright Timeout": "பிளேரைட் டைம்அவுட்டை உள்ளிடவும்", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API விசையை உருவாக்குவதில் தோல்வி.", "Failed to delete calendar": "", "Failed to delete note": "குறிப்பை நீக்க முடியவில்லை", + "Failed to disconnect": "", "Failed to download image": "படத்தைப் பதிவிறக்க முடியவில்லை", "Failed to extract content from the file: {{error}}": "கோப்பிலிருந்து உள்ளடக்கத்தைப் பிரித்தெடுக்க முடியவில்லை: {{error}}", "Failed to extract content from the file.": "கோப்பிலிருந்து உள்ளடக்கத்தைப் பிரித்தெடுக்க முடியவில்லை.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1 (நிலையான)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "அக்டோபர்", "Off": "ஆஃப்", "Okay, Let's Go!": "சரி, போகலாம்!", @@ -1518,6 +1521,8 @@ "Output format": "வெளியீட்டு வடிவம்", "Output Format": "வெளியீட்டு வடிவம்", "Overview": "கண்ணோட்டம்", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "பக்கம்", "Page": "பக்கம்", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "பக்க பயன்முறை ஒரு பக்கத்திற்கு ஒரு ஆவணத்தை உருவாக்குகிறது. ஒற்றைப் பயன்முறையானது அனைத்துப் பக்கங்களையும் ஒரு ஆவணமாக இணைத்து, பக்க எல்லைகளில் சிறப்பாகப் பிரிக்கிறது.", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "இந்த விருப்பம் மாதிரி அதன் பதிலில் உருவாக்கக்கூடிய அதிகபட்ச டோக்கன்களை அமைக்கிறது. இந்த வரம்பை அதிகரிப்பது மாதிரி நீண்ட பதில்களை வழங்க அனுமதிக்கிறது, ஆனால் இது உதவாத அல்லது பொருத்தமற்ற உள்ளடக்கம் உருவாக்கப்படுவதற்கான வாய்ப்பையும் அதிகரிக்கலாம்.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "இந்த விருப்பம் சேகரிப்பில் இருக்கும் எல்லா கோப்புகளையும் நீக்கி, புதிதாக பதிவேற்றப்பட்ட கோப்புகளுடன் மாற்றும்.", "This response was generated by \"{{model}}\"": "இந்த பதில் \"{{model}}\" ஆல் உருவாக்கப்பட்டது", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "இது நீக்கும்", "This will delete {{NAME}} and all its contents.": "இது {{NAME}} மற்றும் அதன் அனைத்து உள்ளடக்கங்களையும் நீக்கும்.", "This will delete all models including custom models": "இது தனிப்பயன் மாதிரிகள் உட்பட அனைத்து மாடல்களையும் நீக்கும்", diff --git a/src/lib/i18n/locales/th-TH/translation.json b/src/lib/i18n/locales/th-TH/translation.json index 17dd64ef45..6ad730ed4f 100644 --- a/src/lib/i18n/locales/th-TH/translation.json +++ b/src/lib/i18n/locales/th-TH/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "การเปิดใช้งานบัญชีกำลังดำเนินการ", "Accurate information": "ข้อมูลที่ถูกต้อง", "Action": "การดำเนินการ", - "Action not found": "ไม่พบการดำเนินการ", "Action Required for Chat Log Storage": "ต้องดำเนินการเพื่อจัดเก็บบันทึกการแชท", "Actions": "การดำเนินการ", "Activate": "เปิดใช้งาน", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "เล่นเสียงแจ้งเตือนเสมอ", "Amazing": "ยอดเยี่ยม", "an assistant": "ผู้ช่วย", - "An error occurred while fetching the explanation": "เกิดข้อผิดพลาดขณะดึงคำอธิบาย", "Analytics": "การวิเคราะห์", "Analyzed": "วิเคราะห์แล้ว", "Analyzing...": "กำลังวิเคราะห์...", @@ -578,6 +576,7 @@ "Disable Image Extraction": "ปิดใช้งานการแยกรูปภาพ", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "ปิดใช้งานการดึงรูปภาพจากไฟล์ PDF หากเปิดใช้ Use LLM รูปภาพจะถูกสร้างคำบรรยายให้โดยอัตโนมัติ ค่าเริ่มต้นคือ False", "Disabled": "ปิดใช้งาน", + "Disconnect OAuth": "", "Discover a function": "ค้นพบฟังก์ชัน", "Discover a model": "ค้นพบโมเดล", "Discover a prompt": "ค้นพบพรอมต์", @@ -767,6 +766,8 @@ "Enter New Password": "ป้อนรหัสผ่านใหม่", "Enter Number of Steps (e.g. 50)": "ใส่จำนวนขั้นตอน (เช่น 50)", "Enter Ollama Cloud API Key": "ใส่ Ollama Cloud API Key", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "ใส่ Perplexity API Key", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "ป้อนเวลา Timeout ของ Playwright", @@ -897,6 +898,7 @@ "Failed to create API Key.": "สร้าง API Key ล้มเหลว", "Failed to delete calendar": "", "Failed to delete note": "ลบบันทึกไม่สำเร็จ", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "ไม่สามารถดึงเนื้อหาจากไฟล์ได้: {{error}}", "Failed to extract content from the file.": "ไม่สามารถดึงเนื้อหาจากไฟล์ได้", @@ -1451,6 +1453,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "ตุลาคม", "Off": "ปิด", "Okay, Let's Go!": "ตกลง ไปกันเลย!", @@ -1517,6 +1520,8 @@ "Output format": "รูปแบบผลลัพธ์", "Output Format": "รูปแบบผลลัพธ์", "Overview": "ภาพรวม", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "หน้า", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2017,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "ตัวเลือกนี้ใช้กำหนดจำนวนโทเค็นสูงสุดที่โมเดลสามารถสร้างได้ในคำตอบของตน การเพิ่มขีดจำกัดนี้จะช่วยให้โมเดลตอบได้ยาวขึ้น แต่ก็อาจเพิ่มโอกาสในการสร้างเนื้อหาที่ไม่เป็นประโยชน์หรือไม่เกี่ยวข้องด้วย", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "ตัวเลือกนี้จะลบไฟล์ทั้งหมดที่มีอยู่ในคอลเลกชันและแทนที่ด้วยไฟล์ที่อัปโหลดใหม่", "This response was generated by \"{{model}}\"": "การตอบกลับนี้สร้างโดย \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "การดำเนินการนี้จะลบ", "This will delete {{NAME}} and all its contents.": "การดำเนินการนี้จะลบ {{NAME}} และเนื้อหาทั้งหมด", "This will delete all models including custom models": "การดำเนินการนี้จะลบโมเดลทั้งหมด รวมถึงโมเดลแบบกำหนดเอง", diff --git a/src/lib/i18n/locales/tk-TM/translation.json b/src/lib/i18n/locales/tk-TM/translation.json index 6783a0222a..cc5cb3f895 100644 --- a/src/lib/i18n/locales/tk-TM/translation.json +++ b/src/lib/i18n/locales/tk-TM/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "", "Accurate information": "Takyk maglumat", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Söhbet gündeligini saklamak üçin çäre zerur", "Actions": "", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "kömekçi", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Ýatyrylan", + "Disconnect OAuth": "", "Discover a function": "", "Discover a model": "", "Discover a prompt": "", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "", + "OAuth session disconnected": "", "October": "Oktýabr", "Off": "", "Okay, Let's Go!": "", @@ -1518,6 +1521,8 @@ "Output format": "", "Output Format": "", "Overview": "", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "", "This response was generated by \"{{model}}\"": "", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "", "This will delete {{NAME}} and all its contents.": "", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index 5b31954239..caf5954360 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Hesap Aktivasyonu Bekleniyor", "Accurate information": "Doğru bilgi", "Action": "Aksiyon", - "Action not found": "Aksiyon bulunamadı", "Action Required for Chat Log Storage": "Sohbet günlüğünü kaydetmek için işlem gerekli", "Actions": "Aksiyonlar", "Activate": "Aktif Et", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Her Zaman Bildirim Sesini Oynat", "Amazing": "Harika", "an assistant": "bir asistan", - "An error occurred while fetching the explanation": "Açıklama alınırken bir hata oluştu", "Analytics": "Analiz", "Analyzed": "Analiz edildi", "Analyzing...": "Analiz ediliyor...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Görsel Çıkarmayı Devre Dışı Bırak", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDF'den görsel çıkarmayı devre dışı bırakır. LLM Kullan etkinse görseller otomatik olarak altyazılanır. Varsayılan olarak False.", "Disabled": "Devre Dışı", + "Disconnect OAuth": "", "Discover a function": "Bir fonksiyon keşfedin", "Discover a model": "Bir model keşfedin", "Discover a prompt": "Bir prompt keşfedin", @@ -768,6 +767,8 @@ "Enter New Password": "Yeni Parola Girin", "Enter Number of Steps (e.g. 50)": "Adım Sayısını Girin (örn. 50)", "Enter Ollama Cloud API Key": "Ollama Cloud API Anahtarını Girin", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity API Anahtarını Girin", "Enter Perplexity Search API URL": "Perplexity Search API URL'sini Girin", "Enter Playwright Timeout": "Playwright Zaman Aşımını Girin", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API Anahtarı oluşturulamadı.", "Failed to delete calendar": "", "Failed to delete note": "Not silinemedi", + "Failed to disconnect": "", "Failed to download image": "Görsel indirilemedi", "Failed to extract content from the file: {{error}}": "Dosyadan içerik çıkarılamadı: {{error}}", "Failed to extract content from the file.": "Dosyadan içerik çıkarılamadı.", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Ekim", "Off": "Kapalı", "Okay, Let's Go!": "Tamam, Hadi Başlayalım!", @@ -1518,6 +1521,8 @@ "Output format": "Çıktı formatı", "Output Format": "", "Overview": "Genel Bakış", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "sayfa", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Bu seçenek, koleksiyondaki tüm mevcut dosyaları silecek ve bunları yeni yüklenen dosyalarla değiştirecek.", "This response was generated by \"{{model}}\"": "Bu yanıt \"{{model}}\" tarafından oluşturuldu", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Bu silinecek", "This will delete {{NAME}} and all its contents.": "{{NAME}} ve tüm içeriği silinecek.", "This will delete all models including custom models": "Bu, özel modeller dahil olmak üzere tüm modelleri silecek", diff --git a/src/lib/i18n/locales/ug-CN/translation.json b/src/lib/i18n/locales/ug-CN/translation.json index ba0727be45..c7e97e4eb3 100644 --- a/src/lib/i18n/locales/ug-CN/translation.json +++ b/src/lib/i18n/locales/ug-CN/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "ھېسابات ئاكتىپلىنىشى كۈتۈلمەكتە", "Accurate information": "توغرا ئۇچۇر", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "سۆھبەت خاتىرىسىنى ساقلاش ئۈچۈن ھەرىكەت زۆرۈر", "Actions": "ھەرىكەتلەر", "Activate": "ئاكتىپلاش", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "ئۇقتۇرۇش ئاۋازىنى ھەمىشە قوي", "Amazing": "ئاجايىپ", "an assistant": "ياردەمچى", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "تەھلىل قىلىندى", "Analyzing...": "تەھلىل قىلىنىۋاتىدۇ...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "رەسىم چىقىرىشنى چەكلە", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDF دىن رەسىم چىقىرىش چەكلىنىدۇ. LLM ئىشلىتىلسە، رەسىملەر ئاپتوماتىك تېمىغا ئىگە بولىدۇ. كۆڭۈلدىكىچە چەكلەنمەيدۇ.", "Disabled": "چەكلەنگەن", + "Disconnect OAuth": "", "Discover a function": "فۇنكسىيە تاپ", "Discover a model": "مودېل تاپ", "Discover a prompt": "تۈرتكە تاپ", @@ -768,6 +767,8 @@ "Enter New Password": "يېڭى پارول كىرگۈزۈڭ", "Enter Number of Steps (e.g. 50)": "قەدەملەر سانى كىرگۈزۈڭ (مەسىلەن: 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity API ئاچقۇچى كىرگۈزۈڭ", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Playwright ۋاقىت چەكلىمىسى كىرگۈزۈڭ", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API ئاچقۇچى قۇرۇش مەغلۇپ بولدى.", "Failed to delete calendar": "", "Failed to delete note": "خاتىرە ئۆچۈرۈش مەغلۇپ بولدى", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "ئۆكتەبىر", "Off": "تاقالغان", "Okay, Let's Go!": "ماقۇل، باشلايلى!", @@ -1518,6 +1521,8 @@ "Output format": "چىقىرىش قېلىپى", "Output Format": "چىقىرىش فورماتى", "Overview": "قىسقىچە تونۇشتۇرۇش", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "بەت", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "بۇ تاللاش مودېل ئىنكاستا ھاسىل قىلىدىغان ئەڭ كۆپ ئىم سانىنى بەلگىلەيدۇ. چەك چوڭ بولسا، ئۇزۇن ئىنكاس چىقىرىدۇ، بىراق مۇناسىۋەتسىز مەزمۇن چىقىشى ئېھتىمالى يۇقىرى.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "بۇ تاللاش بارلىق توپلامدىكى ھۆججەتلەرنى ئۆچۈرۈپ يېڭى چىقىرىلغان ھۆججەتلەر بىلەن ئالماشتۇرىدۇ.", "This response was generated by \"{{model}}\"": "بۇ ئىنكاس \"{{model}}\" ئارقىلىق ھاسىل قىلىندى", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "بۇ ئۆچۈرۈلىدۇ:", "This will delete {{NAME}} and all its contents.": "{{NAME}} ۋە بارلىق مەزمۇنى ئۆچۈرۈلىدۇ.", "This will delete all models including custom models": "بۇ بارلىق مودېللارنى ئۆچۈرۈدۇ (ئۆزلۈك مودېللارنىمۇ ئۆز ئىچىگە ئالىدۇ)", diff --git a/src/lib/i18n/locales/uk-UA/translation.json b/src/lib/i18n/locales/uk-UA/translation.json index 46de023a39..74758adace 100644 --- a/src/lib/i18n/locales/uk-UA/translation.json +++ b/src/lib/i18n/locales/uk-UA/translation.json @@ -60,7 +60,6 @@ "Account Activation Pending": "Очікування активації облікового запису", "Accurate information": "Точна інформація", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Потрібна дія для збереження журналу чату", "Actions": "Дії", "Activate": "Активувати", @@ -161,7 +160,6 @@ "Always Play Notification Sound": "", "Amazing": "Чудово", "an assistant": "асистента", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Проаналізовано", "Analyzing...": "Аналізую...", @@ -581,6 +579,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Вимкнено", + "Disconnect OAuth": "", "Discover a function": "Знайдіть функцію", "Discover a model": "Знайдіть модель", "Discover a prompt": "Знайдіть промт", @@ -770,6 +769,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Введіть кількість кроків (напр., 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Введіть ключ API для Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -900,6 +901,7 @@ "Failed to create API Key.": "Не вдалося створити API ключ.", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1454,6 +1456,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "Жовтень", "Off": "Вимк", "Okay, Let's Go!": "Гаразд, давайте почнемо!", @@ -1520,6 +1523,8 @@ "Output format": "Формат відповіді", "Output Format": "", "Overview": "Огляд", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "сторінка", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2026,6 +2031,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Ця опція встановлює максимальну кількість токенів, які модель може згенерувати у своїй відповіді. Збільшення цього ліміту дозволяє моделі надавати довші відповіді, але також може підвищити ймовірність генерації непотрібного або нерелевантного контенту.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Цей варіант видалить усі існуючі файли в колекції та замінить їх новими завантаженими файлами.", "This response was generated by \"{{model}}\"": "Цю відповідь згенеровано за допомогою \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Це призведе до видалення", "This will delete {{NAME}} and all its contents.": "Це видалить {{NAME}} та усі його вмісти.", "This will delete all models including custom models": "Це видалить усі моделі, включаючи користувацькі моделі", diff --git a/src/lib/i18n/locales/ur-PK/translation.json b/src/lib/i18n/locales/ur-PK/translation.json index 967dd471db..40f964725e 100644 --- a/src/lib/i18n/locales/ur-PK/translation.json +++ b/src/lib/i18n/locales/ur-PK/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "اکاؤنٹ فعال ہونے کا انتظار ہے", "Accurate information": "درست معلومات", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "چیٹ لاگ محفوظ کرنے کے لیے کارروائی درکار ہے", "Actions": "اعمال", "Activate": "", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "", "Amazing": "", "an assistant": "معاون", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "", "Analyzing...": "", @@ -579,6 +577,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "غیر فعال", + "Disconnect OAuth": "", "Discover a function": "ایک فنکشن دریافت کریں", "Discover a model": "ایک ماڈل دریافت کریں", "Discover a prompt": "ایک اشارہ دریافت کریں", @@ -768,6 +767,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "درج کریں مراحل کی تعداد (جیسے 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API کلید بنانے میں ناکام", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth آئی ڈی", + "OAuth session disconnected": "", "October": "اکتوبر", "Off": "بند", "Okay, Let's Go!": "ٹھیک ہے، چلیں!", @@ -1518,6 +1521,8 @@ "Output format": "آؤٹ پٹ فارمیٹ", "Output Format": "", "Overview": "جائزہ", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "صفحہ", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "اس اختیار سے مجموعہ میں موجود تمام فائلز حذف ہو جائیں گی اور ان کی جگہ نئی اپ لوڈ کردہ فائلز لی جائیں گی", "This response was generated by \"{{model}}\"": "یہ جواب \"{{model}}\" کے ذریعہ تیار کیا گیا", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "یہ حذف کر دے گا", "This will delete {{NAME}} and all its contents.": "یہ {{NAME}} اور اس کے تمام مواد کو حذف کر دے گا", "This will delete all models including custom models": "", diff --git a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json index fe4f5b1da1..ef428a85a9 100644 --- a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json +++ b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Ҳисобни фаоллаштириш кутилмоқда", "Accurate information": "Аниқ маълумот", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Чат журнали сақланиши учун амал талаб қилинади", "Actions": "Ҳаракатлар", "Activate": "Фаоллаштириш", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Ҳар доим билдиришнома овозини ижро этиш", "Amazing": "Ажойиб", "an assistant": "ёрдамчи", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Таҳлил қилинган", "Analyzing...": "Таҳлил қилинмоқда...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Расм чиқаришни ўчириб қўйинг", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDFдан тасвирни ажратиб олишни ўчириб қўйинг. Агар LLM дан фойдаланиш ёқилган бўлса, тасвирларга автоматик сарлавҳа қўйилади. Бирламчи параметрлар False.", "Disabled": "Ўчирилган", + "Disconnect OAuth": "", "Discover a function": "Функцияни кашф қилиш", "Discover a model": "Моделни кашф қилинг", "Discover a prompt": "Кўрсатмани кашф қилинг", @@ -768,6 +767,8 @@ "Enter New Password": "Янги паролни киритинг", "Enter Number of Steps (e.g. 50)": "Қадамлар сонини киритинг (масалан, 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity АПИ калитини киритинг", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -898,6 +899,7 @@ "Failed to create API Key.": "АПИ калитини яратиб бўлмади.", "Failed to delete calendar": "", "Failed to delete note": "Қайдни ўчириб бўлмади", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "ОАутҳ ИД", + "OAuth session disconnected": "", "October": "октябр", "Off": "Ўчирилган", "Okay, Let's Go!": "Майли, кетайлик!", @@ -1518,6 +1521,8 @@ "Output format": "Чиқиш формати", "Output Format": "Чиқиш формати", "Overview": "Умумий кўриниш", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "саҳифа", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Ушбу параметр модел жавобида яратиши мумкин бўлган токенларнинг максимал сонини белгилайди. Ушбу чегарани ошириш моделга узоқроқ жавобларни тақдим этиш имконини беради, бироқ у фойдасиз ёки аҳамиятсиз контент яратилиш эҳтимолини ҳам ошириши мумкин.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Ушбу параметр тўпламдаги барча мавжуд файлларни ўчиради ва уларни янги юкланган файллар билан алмаштиради.", "This response was generated by \"{{model}}\"": "Бу жавоб \"{{модел}}\" томонидан яратилган", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Бу ўчирилади", "This will delete {{NAME}} and all its contents.": "Бу <стронг>{{NAME}} ва <стронг>барча мазмунини ўчириб ташлайди.", "This will delete all models including custom models": "Бу барча моделларни, шу жумладан махсус моделларни ўчириб ташлайди", diff --git a/src/lib/i18n/locales/uz-Latn-Uz/translation.json b/src/lib/i18n/locales/uz-Latn-Uz/translation.json index 2ffada0eab..8975a1920d 100644 --- a/src/lib/i18n/locales/uz-Latn-Uz/translation.json +++ b/src/lib/i18n/locales/uz-Latn-Uz/translation.json @@ -58,7 +58,6 @@ "Account Activation Pending": "Hisobni faollashtirish kutilmoqda", "Accurate information": "Aniq ma'lumot", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Chat jurnalini saqlash uchun amal talab qilinadi", "Actions": "Harakatlar", "Activate": "Faollashtirish", @@ -159,7 +158,6 @@ "Always Play Notification Sound": "Har doim bildirishnoma ovozini ijro etish", "Amazing": "Ajoyib", "an assistant": "yordamchi", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Tahlil qilingan", "Analyzing...": "Tahlil qilinmoqda...", @@ -579,6 +577,7 @@ "Disable Image Extraction": "Rasm chiqarishni o'chirib qo'ying", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "PDF-dan tasvirni ajratib olishni o'chirib qo'ying. Agar LLM dan foydalanish yoqilgan boʻlsa, tasvirlarga avtomatik sarlavha qoʻyiladi. Birlamchi parametrlar False.", "Disabled": "O'chirilgan", + "Disconnect OAuth": "", "Discover a function": "Funktsiyani kashf qilish", "Discover a model": "Modelni kashf qiling", "Discover a prompt": "Ko'rsatmani kashf qiling", @@ -768,6 +767,8 @@ "Enter New Password": "Yangi parolni kiriting", "Enter Number of Steps (e.g. 50)": "Qadamlar sonini kiriting (masalan, 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Perplexity API kalitini kiriting", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "Dramaturg vaqtini kiriting", @@ -898,6 +899,7 @@ "Failed to create API Key.": "API kalitini yaratib bo‘lmadi.", "Failed to delete calendar": "", "Failed to delete note": "Qaydni o‘chirib bo‘lmadi", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1452,6 +1454,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "oktyabr", "Off": "Oʻchirilgan", "Okay, Let's Go!": "Mayli, ketaylik!", @@ -1518,6 +1521,8 @@ "Output format": "Chiqish formati", "Output Format": "Chiqish formati", "Overview": "Umumiy koʻrinish", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "sahifa", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2020,6 +2025,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Ushbu parametr model javobida yaratishi mumkin bo'lgan tokenlarning maksimal sonini belgilaydi. Ushbu chegarani oshirish modelga uzoqroq javoblarni taqdim etish imkonini beradi, biroq u foydasiz yoki ahamiyatsiz kontent yaratilish ehtimolini ham oshirishi mumkin.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Ushbu parametr to'plamdagi barcha mavjud fayllarni o'chiradi va ularni yangi yuklangan fayllar bilan almashtiradi.", "This response was generated by \"{{model}}\"": "Bu javob \"{{model}}\" tomonidan yaratilgan", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Bu o'chiriladi", "This will delete {{NAME}} and all its contents.": "Bu {{NAME}} va barcha mazmunini o‘chirib tashlaydi.", "This will delete all models including custom models": "Bu barcha modellarni, shu jumladan maxsus modellarni o'chirib tashlaydi", diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index 6810eb909a..ac716ec661 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "Tài khoản đang chờ kích hoạt", "Accurate information": "Thông tin chính xác", "Action": "", - "Action not found": "", "Action Required for Chat Log Storage": "Cần thao tác để lưu nhật ký trò chuyện", "Actions": "Tác vụ", "Activate": "Kích hoạt", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "", "Amazing": "Tuyệt vời", "an assistant": "trợ lý", - "An error occurred while fetching the explanation": "", "Analytics": "", "Analyzed": "Đã phân tích", "Analyzing...": "Đang phân tích...", @@ -578,6 +576,7 @@ "Disable Image Extraction": "", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "", "Disabled": "Đã tắt", + "Disconnect OAuth": "", "Discover a function": "Khám phá function", "Discover a model": "Khám phá model", "Discover a prompt": "Khám phá thêm prompt mới", @@ -767,6 +766,8 @@ "Enter New Password": "", "Enter Number of Steps (e.g. 50)": "Nhập số Steps (vd: 50)", "Enter Ollama Cloud API Key": "", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "Nhập Khóa API Perplexity", "Enter Perplexity Search API URL": "", "Enter Playwright Timeout": "", @@ -897,6 +898,7 @@ "Failed to create API Key.": "Lỗi khởi tạo API Key", "Failed to delete calendar": "", "Failed to delete note": "", + "Failed to disconnect": "", "Failed to download image": "", "Failed to extract content from the file: {{error}}": "", "Failed to extract content from the file.": "", @@ -1451,6 +1453,7 @@ "OAuth 2.1": "", "OAuth 2.1 (Static)": "", "OAuth ID": "ID OAuth", + "OAuth session disconnected": "", "October": "Tháng 10", "Off": "Tắt", "Okay, Let's Go!": "Được rồi, Bắt đầu thôi!", @@ -1517,6 +1520,8 @@ "Output format": "Định dạng đầu ra", "Output Format": "", "Overview": "Tổng quan", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "trang", "Page": "", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "", @@ -2017,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "Tùy chọn này đặt số lượng token tối đa mà mô hình có thể tạo ra trong phản hồi của nó. Tăng giới hạn này cho phép mô hình cung cấp câu trả lời dài hơn, nhưng nó cũng có thể làm tăng khả năng tạo ra nội dung không hữu ích hoặc không liên quan.", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "Tùy chọn này sẽ xóa tất cả các tệp hiện có trong bộ sưu tập và thay thế chúng bằng các tệp mới được tải lên.", "This response was generated by \"{{model}}\"": "Phản hồi này được tạo bởi \"{{model}}\"", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "Chat này sẽ bị xóa", "This will delete {{NAME}} and all its contents.": "Hành động này sẽ xóa {{NAME}}tất cả nội dung của nó.", "This will delete all models including custom models": "Hành động này sẽ xóa tất cả các mô hình bao gồm cả các mô hình tùy chỉnh", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index 9678d24eeb..e3aed8309f 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "账号待激活", "Accurate information": "信息准确", "Action": "操作", - "Action not found": "找不到对应的操作项", "Action Required for Chat Log Storage": "需要操作以保存对话记录", "Actions": "操作", "Activate": "激活", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "始终播放通知声音", "Amazing": "很棒", "an assistant": "一个助手", - "An error occurred while fetching the explanation": "获取解释时发生错误", "Analytics": "分析", "Analyzed": "已分析", "Analyzing...": "正在分析...", @@ -578,6 +576,7 @@ "Disable Image Extraction": "禁用图像提取", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "禁用从 PDF 中提取图像。若启用“使用大语言模型(LLM)”,图像将自动添加描述。默认为关闭", "Disabled": "已禁用", + "Disconnect OAuth": "", "Discover a function": "发现更多函数", "Discover a model": "发现更多模型", "Discover a prompt": "发现更多提示词", @@ -767,6 +766,8 @@ "Enter New Password": "输入新密码", "Enter Number of Steps (e.g. 50)": "输入步骤数 (Steps)(例如:50)", "Enter Ollama Cloud API Key": "输入 Ollama Cloud 接口密钥", + "Enter PaddleOCR-vl API Base URL": "输入 PaddleOCR-vl API 基础地址", + "Enter PaddleOCR-vl API Token": "输入 PaddleOCR-vl 接口密钥", "Enter Perplexity API Key": "输入 Perplexity 接口密钥", "Enter Perplexity Search API URL": "输入 Perplexity Search 接口地址", "Enter Playwright Timeout": "输入 Playwright 超时时间", @@ -774,8 +775,6 @@ "Enter prompt here.": "在此输入提示词。", "Enter proxy URL (e.g. https://user:password@host:port)": "输入代理地址(例如:https://用户名:密码@主机名:端口)", "Enter reasoning effort": "输入推理努力", - "Enter PaddleOCR-vl API Token": "输入 PaddleOCR-vl 接口密钥", - "Enter PaddleOCR-vl API Base URL": "输入 PaddleOCR-vl API 基础地址", "Enter Score": "输入评分", "Enter SearchApi API Key": "输入 SearchApi 接口密钥", "Enter SearchApi Engine": "输入 SearchApi 引擎", @@ -899,6 +898,7 @@ "Failed to create API Key.": "创建接口密钥失败", "Failed to delete calendar": "", "Failed to delete note": "删除笔记失败", + "Failed to disconnect": "", "Failed to download image": "图片下载失败", "Failed to extract content from the file: {{error}}": "文件内容提取失败:{{error}}", "Failed to extract content from the file.": "文件内容提取失败", @@ -1453,6 +1453,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1(静态)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "十月", "Off": "关闭", "Okay, Let's Go!": "确认,开始使用!", @@ -1520,6 +1521,7 @@ "Output Format": "输出格式", "Overview": "概述", "PaddleOCR-vl": "PaddleOCR-vl", + "PaddleOCR-vl API URL required.": "", "page": "页", "Page": "页模式", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "页模式将为每个页面创建一个文档;单文档模式则将所有页面合并为一个文档,以便更好地进行跨页分块。", @@ -2020,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "此项用于设置模型在其响应中可以生成的最大 Token 数。增加此限制可让模型输出更多内容,但也可能增加生成无用或不相关内容的可能性。", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "此选项将会删除文件集中所有文件,并用新上传的文件替换。", "This response was generated by \"{{model}}\"": "此回答由 “{{model}}” 生成", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "这将删除", "This will delete {{NAME}} and all its contents.": "这将删除{{NAME}}及其所有内容。", "This will delete all models including custom models": "这将删除所有模型,包括自定义模型", diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index 50d352a96f..50624307f7 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -57,7 +57,6 @@ "Account Activation Pending": "帳號待啟用", "Accurate information": "準確資訊", "Action": "操作", - "Action not found": "找不到對應的操作項目", "Action Required for Chat Log Storage": "需要操作以儲存對話紀錄", "Actions": "動作", "Activate": "啟用", @@ -158,7 +157,6 @@ "Always Play Notification Sound": "總是播放通知音效", "Amazing": "很棒", "an assistant": "助理", - "An error occurred while fetching the explanation": "取得說明時發生錯誤", "Analytics": "分析", "Analyzed": "分析完畢", "Analyzing...": "正在分析...", @@ -578,6 +576,7 @@ "Disable Image Extraction": "停用圖片擷取", "Disable image extraction from the PDF. If Use LLM is enabled, images will be automatically captioned. Defaults to False.": "停用從 PDF 擷取圖片。若啟用「使用 LLM」,圖片將自動新增說明。預設為 False。", "Disabled": "已停用", + "Disconnect OAuth": "", "Discover a function": "發掘函式", "Discover a model": "發掘模型", "Discover a prompt": "發掘提示詞", @@ -767,6 +766,8 @@ "Enter New Password": "輸入新密碼", "Enter Number of Steps (e.g. 50)": "輸入步驟數(例如:50)", "Enter Ollama Cloud API Key": "輸入 Ollama Cloud API 金鑰", + "Enter PaddleOCR-vl API Base URL": "", + "Enter PaddleOCR-vl API Token": "", "Enter Perplexity API Key": "輸入 Perplexity API 金鑰", "Enter Perplexity Search API URL": "輸入 Perplexity 搜尋 API URL", "Enter Playwright Timeout": "輸入 Playwright 逾時時間(毫秒)", @@ -897,6 +898,7 @@ "Failed to create API Key.": "建立 API 金鑰失敗。", "Failed to delete calendar": "", "Failed to delete note": "刪除筆記失敗", + "Failed to disconnect": "", "Failed to download image": "圖片下載失敗", "Failed to extract content from the file: {{error}}": "檔案內容擷取失敗:{{error}}", "Failed to extract content from the file.": "檔案內容擷取失敗", @@ -1451,6 +1453,7 @@ "OAuth 2.1": "OAuth 2.1", "OAuth 2.1 (Static)": "OAuth 2.1(靜態)", "OAuth ID": "OAuth ID", + "OAuth session disconnected": "", "October": "10 月", "Off": "關閉", "Okay, Let's Go!": "好的,我們開始吧!", @@ -1517,6 +1520,8 @@ "Output format": "輸出格式", "Output Format": "輸出格式", "Overview": "概覽", + "PaddleOCR-vl": "", + "PaddleOCR-vl API URL required.": "", "page": "頁面", "Page": "頁面模式", "Page mode creates one document per page. Single mode combines all pages into one document for better chunking across page boundaries.": "頁面模式將為每個頁面創建一個文檔;單文檔模式則將所有頁面合併為一個文檔,以便更好地進行跨頁分塊。", @@ -2017,6 +2022,7 @@ "This option sets the maximum number of tokens the model can generate in its response. Increasing this limit allows the model to provide longer answers, but it may also increase the likelihood of unhelpful or irrelevant content being generated.": "此選項設定模型在其回應中可以生成的最大 Token 數量。增加此限制允許模型提供更長的答案,但也可能增加產生無用或不相關內容的可能性。", "This option will delete all existing files in the collection and replace them with newly uploaded files.": "此選項將刪除集合中的所有現有檔案,並用新上傳的檔案取代它們。", "This response was generated by \"{{model}}\"": "此回應由「{{model}}」產生", + "This template contains multiple context placeholders ([context] or {{CONTEXT}}). Context will be injected at each occurrence.": "", "This will delete": "這將會刪除", "This will delete {{NAME}} and all its contents.": "這將會刪除 {{NAME}}其所有內容。", "This will delete all models including custom models": "這將刪除所有模型,包括自訂模型", From 4e2240aadaff191ad360d37a7145e552359162c3 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 24 Apr 2026 18:55:39 +0900 Subject: [PATCH 404/404] refac --- scripts/prepare-pyodide.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/prepare-pyodide.js b/scripts/prepare-pyodide.js index d83598343e..73ac1d8642 100644 --- a/scripts/prepare-pyodide.js +++ b/scripts/prepare-pyodide.js @@ -22,7 +22,7 @@ const packages = [ // static/pyodide/ so that the browser can install them offline via micropip. // Packages already provided by the Pyodide distribution (click, platformdirs, // typing_extensions, etc.) do NOT need to be listed here. -const pypiPackages = ['black', 'pathspec', 'mypy_extensions']; +const pypiPackages = ['black', 'pathspec', 'mypy_extensions', 'pytokens']; import { loadPyodide } from 'pyodide'; import { setGlobalDispatcher, ProxyAgent } from 'undici';