From 9824f0e33359a917ac07b60bf1f972074d5c8203 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 23 Dec 2025 10:14:54 +0400 Subject: [PATCH 001/254] enh: ENABLE_DB_MIGRATIONS --- backend/open_webui/config.py | 4 +++- backend/open_webui/env.py | 2 ++ backend/open_webui/internal/db.py | 4 +++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index c5ac40babd..9851aa37ba 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -19,6 +19,7 @@ from authlib.integrations.starlette_client import OAuth from open_webui.env import ( DATA_DIR, DATABASE_URL, + ENABLE_DB_MIGRATIONS, ENV, REDIS_URL, REDIS_KEY_PREFIX, @@ -67,7 +68,8 @@ def run_migrations(): log.exception(f"Error running migrations: {e}") -run_migrations() +if ENABLE_DB_MIGRATIONS: + run_migrations() class Config(Base): diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 1e977906c4..a5184aa4d5 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -117,6 +117,8 @@ VERSION = PACKAGE_DATA["version"] DEPLOYMENT_ID = os.environ.get("DEPLOYMENT_ID", "") INSTANCE_ID = os.environ.get("INSTANCE_ID", str(uuid4())) +ENABLE_DB_MIGRATIONS = os.environ.get("ENABLE_DB_MIGRATIONS", "True").lower() == "true" + # Function to parse each section def parse_section(section): diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index a5eecd6605..95571c2435 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -14,6 +14,7 @@ from open_webui.env import ( DATABASE_POOL_SIZE, DATABASE_POOL_TIMEOUT, DATABASE_ENABLE_SQLITE_WAL, + ENABLE_DB_MIGRATIONS, ) from peewee_migrate import Router from sqlalchemy import Dialect, create_engine, MetaData, event, types @@ -75,7 +76,8 @@ def handle_peewee_migration(DATABASE_URL): assert db.is_closed(), "Database connection is still open." -handle_peewee_migration(DATABASE_URL) +if ENABLE_DB_MIGRATIONS: + handle_peewee_migration(DATABASE_URL) SQLALCHEMY_DATABASE_URL = DATABASE_URL From 758325a203658d99c8970e7f2cb23ec9f7cc8fc9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 23 Dec 2025 10:15:05 +0400 Subject: [PATCH 002/254] infra: dockerfile base image --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 08c2de6dfa..caa1253b65 100644 --- a/Dockerfile +++ b/Dockerfile @@ -42,7 +42,7 @@ ENV APP_BUILD_HASH=${BUILD_HASH} RUN npm run build ######## WebUI backend ######## -FROM python:3.11-slim-bookworm AS base +FROM python:3.11.14-slim-bookworm AS base # Use args ARG USE_CUDA From 59957715836acb635f4b1c4ddbfb4ba7b82b3281 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 23 Dec 2025 10:42:33 +0400 Subject: [PATCH 003/254] fix: channel model mention --- backend/open_webui/routers/channels.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index a0dae72442..954be49721 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -1023,6 +1023,7 @@ async def model_response_handler(request, channel, message, user): if res: if res.get("choices", []) and len(res["choices"]) > 0: await update_message_by_id( + request, channel.id, response_message.id, MessageForm( @@ -1037,6 +1038,7 @@ async def model_response_handler(request, channel, message, user): ) elif res.get("error", None): await update_message_by_id( + request, channel.id, response_message.id, MessageForm( From 2e9e46a9f1db4808468ce9c183f5be2d6cd65133 Mon Sep 17 00:00:00 2001 From: joaoback <156559121+joaoback@users.noreply.github.com> Date: Tue, 23 Dec 2025 04:28:53 -0300 Subject: [PATCH 004/254] Update translation.json (pt-BR) (#20131) Correcting a translation that had an incomplete variable. --- src/lib/i18n/locales/pt-BR/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index 91a8250118..8d98876535 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -12,7 +12,7 @@ "{{COUNT}} Available Tools": "{{COUNT}} Ferramentas disponíveis", "{{COUNT}} characters": "{{COUNT}} caracteres", "{{COUNT}} extracted lines": "{{COUNT}} linhas extraídas", - "{{COUNT}} files": "{COUNT}} arquivos", + "{{COUNT}} files": "{{COUNT}} arquivos", "{{COUNT}} hidden lines": "{{COUNT}} linhas ocultas", "{{COUNT}} Replies": "{{COUNT}} Respostas", "{{COUNT}} Rows": "{{COUNT}} Linhas", From c0ec04935b4eea3d334bfdec2fc41278f1085a49 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 26 Dec 2025 02:05:03 +0400 Subject: [PATCH 005/254] refac: citation --- .../chat/ChatControls/Embeds.svelte | 9 +++- .../components/chat/Messages/Citations.svelte | 35 ++++++++++----- .../chat/Messages/Markdown/SourceToken.svelte | 10 +++-- src/lib/utils/marked/citation-extension.ts | 45 ++++++++++++------- 4 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/lib/components/chat/ChatControls/Embeds.svelte b/src/lib/components/chat/ChatControls/Embeds.svelte index e15c86c8bd..126124bc69 100644 --- a/src/lib/components/chat/ChatControls/Embeds.svelte +++ b/src/lib/components/chat/ChatControls/Embeds.svelte @@ -6,7 +6,7 @@ export let overlay = false; - const getSrcUrl = (url: string, chatId?: string, messageId?: string) => { + const getSrcUrl = (url: string, chatId?: string, messageId?: string, sourceId: string) => { try { const parsed = new URL(url); @@ -18,6 +18,10 @@ parsed.searchParams.set('message_id', messageId); } + if (sourceId) { + parsed.searchParams.set('source_id', sourceId); + } + return parsed.toString(); } catch { // Fallback for relative URLs or invalid input @@ -26,6 +30,7 @@ if (chatId) parts.push(`chat_id=${encodeURIComponent(chatId)}`); if (messageId) parts.push(`message_id=${encodeURIComponent(messageId)}`); + if (sourceId) parts.push(`source_id=${encodeURIComponent(sourceId)}`); if (parts.length === 0) return url; @@ -68,7 +73,7 @@ {/if} diff --git a/src/lib/components/chat/Messages/Citations.svelte b/src/lib/components/chat/Messages/Citations.svelte index 2799059b07..2db74581bd 100644 --- a/src/lib/components/chat/Messages/Citations.svelte +++ b/src/lib/components/chat/Messages/Citations.svelte @@ -23,12 +23,26 @@ let selectedCitation: any = null; - export const showSourceModal = (sourceIdx) => { - if (citations[sourceIdx]) { - console.log('Showing citation modal for:', citations[sourceIdx]); + export const showSourceModal = (sourceId) => { + let index; + let suffix = null; - if (citations[sourceIdx]?.source?.embed_url) { - const embedUrl = citations[sourceIdx].source.embed_url; + if (typeof sourceId === 'string') { + const output = sourceId.split('#'); + index = parseInt(output[0]) - 1; + + if (output.length > 1) { + suffix = output[1]; + } + } else { + index = sourceId - 1; + } + + if (citations[index]) { + console.log('Showing citation modal for:', citations[index]); + + if (citations[index]?.source?.embed_url) { + const embedUrl = citations[index].source.embed_url; if (embedUrl) { if (readOnly) { // Open in new tab if readOnly @@ -39,18 +53,19 @@ showEmbeds.set(true); embed.set({ url: embedUrl, - title: citations[sourceIdx]?.source?.name || 'Embedded Content', - source: citations[sourceIdx], + title: citations[index]?.source?.name || 'Embedded Content', + source: citations[index], chatId: chatId, - messageId: id + messageId: id, + sourceId: sourceId }); } } else { - selectedCitation = citations[sourceIdx]; + selectedCitation = citations[index]; showCitationModal = true; } } else { - selectedCitation = citations[sourceIdx]; + selectedCitation = citations[index]; showCitationModal = true; } } diff --git a/src/lib/components/chat/Messages/Markdown/SourceToken.svelte b/src/lib/components/chat/Messages/Markdown/SourceToken.svelte index 7da6d8f89f..ac2b84cdcd 100644 --- a/src/lib/components/chat/Messages/Markdown/SourceToken.svelte +++ b/src/lib/components/chat/Messages/Markdown/SourceToken.svelte @@ -41,7 +41,9 @@ {#if sourceIds} {#if (token?.ids ?? []).length == 1} - + {@const id = token.ids[0]} + {@const identifier = token.citationIdentifiers ? token.citationIdentifiers[0] : id - 1} + {:else} @@ -65,9 +67,11 @@ el={containerElement} >
- {#each token.ids as sourceId} + {#each token.citationIdentifiers ?? token.ids as identifier} + {@const id = + typeof identifier === 'string' ? parseInt(identifier.split('#')[0]) : identifier}
- +
{/each}
diff --git a/src/lib/utils/marked/citation-extension.ts b/src/lib/utils/marked/citation-extension.ts index dad266c9f0..ca8325fe11 100644 --- a/src/lib/utils/marked/citation-extension.ts +++ b/src/lib/utils/marked/citation-extension.ts @@ -4,46 +4,61 @@ export function citationExtension() { level: 'inline' as const, start(src: string) { - // Trigger on any [number] - return src.search(/\[(\d[\d,\s]*)\]/); + // Trigger on any [number] or [number#suffix] + // We check for a digit immediately after [ to avoid matching arbitrary links + return src.search(/\[\d/); }, tokenizer(src: string) { // Avoid matching footnotes if (/^\[\^/.test(src)) return; - // Match ONE OR MORE adjacent [1] or [1,2] blocks - // Example matched: "[1][2,3][4]" - const rule = /^(\[(?:\d[\d,\s]*)\])+/; + // Match ONE OR MORE adjacent [1], [1,2], or [1#foo] blocks + // Example matched: "[1][2,3][4#bar]" + // We allow: digits, commas, spaces, and # followed by non-control chars (excluding ] and ,) + const rule = /^(\[(?:\d+(?:#[^,\]\s]+)?(?:,\s*\d+(?:#[^,\]\s]+)?)*)\])+/; const match = rule.exec(src); if (!match) return; const raw = match[0]; // Extract ALL bracket groups inside the big match - const groupRegex = /\[([\d,\s]+)\]/g; + const groupRegex = /\[([^\]]+)\]/g; const ids: number[] = []; + const citationIdentifiers: string[] = []; let m: RegExpExecArray | null; while ((m = groupRegex.exec(raw))) { - const parsed = m[1] - .split(',') - .map((n) => parseInt(n.trim(), 10)) - .filter((n) => !isNaN(n)); - - ids.push(...parsed); + // m[1] is the content inside brackets, e.g. "1, 2#foo" + const parts = m[1].split(',').map((p) => p.trim()); + + parts.forEach((part) => { + // Check if it starts with digit + const match = /^(\d+)(?:#(.+))?$/.exec(part); + if (match) { + const index = parseInt(match[1], 10); + if (!isNaN(index)) { + ids.push(index); + // Store the full identifier ("1#foo" or "1") + citationIdentifiers.push(part); + } + } + }); } + + if (ids.length === 0) return; return { type: 'citation', raw, - ids // merged list + ids, // merged list of integers for legacy title lookup + citationIdentifiers // merged list of full identifiers for granular targeting }; }, renderer(token: any) { - // e.g. "1,2,3" - return token.ids.join(','); + // fallback text + return token.raw; } }; } From 4be99174be505b187812e0b48b9f9f7bf6897c52 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Thu, 25 Dec 2025 18:11:17 -0500 Subject: [PATCH 006/254] refac --- backend/open_webui/models/chats.py | 61 +++++++++- backend/open_webui/routers/chats.py | 180 +++++++++++++++++++++++++++- 2 files changed, 234 insertions(+), 7 deletions(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index d821985a4e..4082a40d15 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -210,6 +210,47 @@ class ChatUsageStatsListResponse(BaseModel): model_config = ConfigDict(extra="allow") +class MessageStats(BaseModel): + id: str + role: str + model: Optional[str] = None + content_length: int + token_count: Optional[int] = None + timestamp: Optional[int] = None + rating: Optional[int] = None # Derived from message.annotation.rating + + +class ChatHistoryStats(BaseModel): + messages: dict[str, MessageStats] + currentId: Optional[str] = None + + +class ChatBody(BaseModel): + history: ChatHistoryStats + + +class AggregateChatStats(BaseModel): + average_response_time: float + average_user_message_content_length: float + average_assistant_message_content_length: float + models: dict[str, int] + message_count: int + history_models: dict[str, int] + history_message_count: int + history_user_message_count: int + history_assistant_message_count: int + + +class ChatStatsExport(BaseModel): + id: str + user_id: str + created_at: int + updated_at: int + tags: list[str] = [] + stats: AggregateChatStats + chat: ChatBody + + class ChatTable: def _clean_null_bytes(self, obj): """Recursively remove null bytes from strings in dict/list structures.""" @@ -750,14 +791,22 @@ class ChatTable: return [ChatModel.model_validate(chat) for chat in all_chats] def get_chats_by_user_id( - self, user_id: str, skip: Optional[int] = None, limit: Optional[int] = None + self, + user_id: str, + filter: Optional[dict] = None, + skip: Optional[int] = None, + limit: Optional[int] = None, ) -> ChatListResponse: with get_db() as db: - query = ( - db.query(Chat) - .filter_by(user_id=user_id) - .order_by(Chat.updated_at.desc()) - ) + query = db.query(Chat).filter_by(user_id=user_id) + + if filter: + if filter.get("start_time"): + query = query.filter(Chat.created_at >= filter.get("start_time")) + if filter.get("end_time"): + query = query.filter(Chat.created_at <= filter.get("end_time")) + + query = query.order_by(Chat.updated_at.desc()) total = query.count() diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 8dde946a4d..ac914c63ff 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -13,6 +13,11 @@ from open_webui.models.chats import ( ChatResponse, Chats, ChatTitleIdResponse, + ChatStatsExport, + AggregateChatStats, + ChatBody, + ChatHistoryStats, + MessageStats, ) from open_webui.models.tags import TagModel, Tags from open_webui.models.folders import Folders @@ -192,11 +197,184 @@ def get_session_user_chat_usage_stats( ) + ############################ -# DeleteAllChats +# GetChatStatsExport ############################ +@router.get("/stats/export", response_model=list[ChatStatsExport]) +async def export_chat_stats( + request: Request, + start_time: Optional[int] = None, + end_time: Optional[int] = None, + page: Optional[int] = 1, + user=Depends(get_verified_user), +): + # Check if the user has permission to share/export chats + if (user.role != "admin") and ( + not request.app.state.config.ENABLE_COMMUNITY_SHARING + ): + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + + try: + # Default pagination + limit = 50 + skip = (page - 1) * limit + + # Fetch chats with date filtering + filter = {} + if start_time: + filter["start_time"] = start_time + if end_time: + filter["end_time"] = end_time + + result = Chats.get_chats_by_user_id( + user.id, + skip=skip, + limit=limit, + filter=filter, + ) + + chat_stats_export_list = [] + + for chat in result.items: + messages_map = chat.chat.get("history", {}).get("messages", {}) + message_id = chat.chat.get("history", {}).get("currentId") + + history_models = {} + history_message_count = len(messages_map) + history_user_messages = [] + history_assistant_messages = [] + + # --- Detailed Message Stats --- + export_messages = {} + for key, message in messages_map.items(): + content = message.get("content", "") + if isinstance(content, str): + content_length = len(content) + else: + content_length = 0 # Handle cases where content might be None or not string + + # Extract rating safely + rating = message.get("annotation", {}).get("rating") + + export_messages[key] = MessageStats( + id=message.get("id"), + role=message.get("role"), + model=message.get("model"), + timestamp=message.get("timestamp"), + content_length=content_length, + token_count=None, # Populate if available, e.g. message.get("info", {}).get("token_count") + rating=rating, + ) + + # --- Aggregation Logic (copied/adapted from usage stats) --- + role = message.get("role", "") + if role == "user": + history_user_messages.append(message) + elif role == "assistant": + history_assistant_messages.append(message) + model = message.get("model") + if model: + if model not in history_models: + history_models[model] = 0 + history_models[model] += 1 + + # Calculate Averages + average_user_message_content_length = ( + sum( + len(m.get("content", "")) + for m in history_user_messages + if isinstance(m.get("content"), str) + ) + / len(history_user_messages) + if history_user_messages + else 0 + ) + + average_assistant_message_content_length = ( + sum( + len(m.get("content", "")) + for m in history_assistant_messages + if isinstance(m.get("content"), str) + ) + / len(history_assistant_messages) + if history_assistant_messages + else 0 + ) + + # Response Times + response_times = [] + for message in history_assistant_messages: + user_message_id = message.get("parentId", None) + if user_message_id and user_message_id in messages_map: + user_message = messages_map[user_message_id] + # Ensure timestamps exist + t1 = message.get("timestamp") + t0 = user_message.get("timestamp") + if t1 and t0: + response_times.append(t1 - t0) + + average_response_time = ( + sum(response_times) / len(response_times) if response_times else 0 + ) + + # Current Message List Logic (Main path) + message_list = get_message_list(messages_map, message_id) + message_count = len(message_list) + models = {} + for message in reversed(message_list): + if message.get("role") == "assistant": + model = message.get("model") + if model: + if model not in models: + models[model] = 0 + models[model] += 1 + + # Construct Aggregate Stats + stats = AggregateChatStats( + average_response_time=average_response_time, + average_user_message_content_length=average_user_message_content_length, + average_assistant_message_content_length=average_assistant_message_content_length, + models=models, + message_count=message_count, + history_models=history_models, + history_message_count=history_message_count, + history_user_message_count=len(history_user_messages), + history_assistant_message_count=len(history_assistant_messages), + ) + + # Construct Chat Body + chat_body = ChatBody( + history=ChatHistoryStats(messages=export_messages, currentId=message_id) + ) + + chat_stats_export_list.append( + ChatStatsExport( + id=chat.id, + user_id=chat.user_id, + created_at=chat.created_at, + updated_at=chat.updated_at, + tags=chat.meta.get("tags", []), + stats=stats, + chat=chat_body, + ) + ) + + return chat_stats_export_list + + except Exception as e: + log.exception(e) + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT() + ) + + + @router.delete("/", response_model=bool) async def delete_all_user_chats(request: Request, user=Depends(get_verified_user)): From df106099a159f8cf7910a89c50338ec045a78e61 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Thu, 25 Dec 2025 18:32:13 -0500 Subject: [PATCH 007/254] refac --- backend/open_webui/models/chats.py | 15 ++++++++++++++- backend/open_webui/routers/chats.py | 9 ++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 4082a40d15..797878afae 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -806,7 +806,20 @@ class ChatTable: if filter.get("end_time"): query = query.filter(Chat.created_at <= filter.get("end_time")) - query = query.order_by(Chat.updated_at.desc()) + order_by = filter.get("order_by") + direction = filter.get("direction") + + if order_by and direction: + if hasattr(Chat, order_by): + if direction.lower() == "asc": + query = query.order_by(getattr(Chat, order_by).asc()) + elif direction.lower() == "desc": + query = query.order_by(getattr(Chat, order_by).desc()) + else: + query = query.order_by(Chat.updated_at.desc()) + + else: + query = query.order_by(Chat.updated_at.desc()) total = query.count() diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index ac914c63ff..bbeb19f83d 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -206,6 +206,7 @@ def get_session_user_chat_usage_stats( @router.get("/stats/export", response_model=list[ChatStatsExport]) async def export_chat_stats( request: Request, + chat_id: Optional[str] = None, start_time: Optional[int] = None, end_time: Optional[int] = None, page: Optional[int] = 1, @@ -226,7 +227,13 @@ async def export_chat_stats( skip = (page - 1) * limit # Fetch chats with date filtering - filter = {} + filter = {"order_by": "created_at", "direction": "asc"} + + if chat_id: + chat = Chats.get_chat_by_id(chat_id) + if chat: + filter["start_time"] = chat.created_at + if start_time: filter["start_time"] = start_time if end_time: From 9c61e95ecba071f5a99d93d1b1c5d17b80159329 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 26 Dec 2025 14:05:16 +0400 Subject: [PATCH 008/254] refac --- backend/open_webui/routers/chats.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index bbeb19f83d..0cfe96c29b 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -197,13 +197,19 @@ def get_session_user_chat_usage_stats( ) - ############################ # GetChatStatsExport ############################ -@router.get("/stats/export", response_model=list[ChatStatsExport]) +class ChatStatsExportList(BaseModel): + type: str = "chats" + items: list[ChatStatsExport] + total: int + page: int + + +@router.get("/stats/export", response_model=ChatStatsExportList) async def export_chat_stats( request: Request, chat_id: Optional[str] = None, @@ -264,7 +270,9 @@ async def export_chat_stats( if isinstance(content, str): content_length = len(content) else: - content_length = 0 # Handle cases where content might be None or not string + content_length = ( + 0 # Handle cases where content might be None or not string + ) # Extract rating safely rating = message.get("annotation", {}).get("rating") @@ -372,7 +380,9 @@ async def export_chat_stats( ) ) - return chat_stats_export_list + return ChatStatsExportList( + items=chat_stats_export_list, total=result.total, page=page + ) except Exception as e: log.exception(e) @@ -381,7 +391,6 @@ async def export_chat_stats( ) - @router.delete("/", response_model=bool) async def delete_all_user_chats(request: Request, user=Depends(get_verified_user)): From 85bbed3ec539dc958d306117f97d6be977b7253b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 26 Dec 2025 15:13:50 +0400 Subject: [PATCH 009/254] enh: sync stats --- backend/open_webui/routers/chats.py | 219 +++++++++--------- src/lib/apis/chats/index.ts | 41 ++++ .../chat/Settings/SyncStatsModal.svelte | 174 ++++++++++++++ src/routes/+layout.svelte | 34 +++ 4 files changed, 362 insertions(+), 106 deletions(-) create mode 100644 src/lib/components/chat/Settings/SyncStatsModal.svelte diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 0cfe96c29b..3465205338 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -228,8 +228,7 @@ async def export_chat_stats( ) try: - # Default pagination - limit = 50 + limit = 100 skip = (page - 1) * limit # Fetch chats with date filtering @@ -255,121 +254,125 @@ async def export_chat_stats( chat_stats_export_list = [] for chat in result.items: - messages_map = chat.chat.get("history", {}).get("messages", {}) - message_id = chat.chat.get("history", {}).get("currentId") + try: + messages_map = chat.chat.get("history", {}).get("messages", {}) + message_id = chat.chat.get("history", {}).get("currentId") - history_models = {} - history_message_count = len(messages_map) - history_user_messages = [] - history_assistant_messages = [] + history_models = {} + history_message_count = len(messages_map) + history_user_messages = [] + history_assistant_messages = [] - # --- Detailed Message Stats --- - export_messages = {} - for key, message in messages_map.items(): - content = message.get("content", "") - if isinstance(content, str): - content_length = len(content) - else: - content_length = ( - 0 # Handle cases where content might be None or not string + export_messages = {} + for key, message in messages_map.items(): + try: + content = message.get("content", "") + if isinstance(content, str): + content_length = len(content) + else: + content_length = 0 # Handle cases where content might be None or not string + + # Extract rating safely + rating = message.get("annotation", {}).get("rating") + message_stat = MessageStats( + id=message.get("id"), + role=message.get("role"), + model=message.get("model"), + timestamp=message.get("timestamp"), + content_length=content_length, + token_count=None, # Populate if available, e.g. message.get("info", {}).get("token_count") + rating=rating, + ) + + export_messages[key] = message_stat + + # --- Aggregation Logic (copied/adapted from usage stats) --- + role = message.get("role", "") + if role == "user": + history_user_messages.append(message) + elif role == "assistant": + history_assistant_messages.append(message) + model = message.get("model") + if model: + if model not in history_models: + history_models[model] = 0 + history_models[model] += 1 + except Exception as e: + log.debug(f"Error processing message {key}: {e}") + continue + + # Calculate Averages + average_user_message_content_length = ( + sum( + len(m.get("content", "")) + for m in history_user_messages + if isinstance(m.get("content"), str) ) - - # Extract rating safely - rating = message.get("annotation", {}).get("rating") - - export_messages[key] = MessageStats( - id=message.get("id"), - role=message.get("role"), - model=message.get("model"), - timestamp=message.get("timestamp"), - content_length=content_length, - token_count=None, # Populate if available, e.g. message.get("info", {}).get("token_count") - rating=rating, + / len(history_user_messages) + if history_user_messages + else 0 ) - # --- Aggregation Logic (copied/adapted from usage stats) --- - role = message.get("role", "") - if role == "user": - history_user_messages.append(message) - elif role == "assistant": - history_assistant_messages.append(message) - model = message.get("model") - if model: - if model not in history_models: - history_models[model] = 0 - history_models[model] += 1 - - # Calculate Averages - average_user_message_content_length = ( - sum( - len(m.get("content", "")) - for m in history_user_messages - if isinstance(m.get("content"), str) + average_assistant_message_content_length = ( + sum( + len(m.get("content", "")) + for m in history_assistant_messages + if isinstance(m.get("content"), str) + ) + / len(history_assistant_messages) + if history_assistant_messages + else 0 ) - / len(history_user_messages) - if history_user_messages - else 0 - ) - average_assistant_message_content_length = ( - sum( - len(m.get("content", "")) - for m in history_assistant_messages - if isinstance(m.get("content"), str) + # Response Times + response_times = [] + for message in history_assistant_messages: + user_message_id = message.get("parentId", None) + if user_message_id and user_message_id in messages_map: + user_message = messages_map[user_message_id] + # Ensure timestamps exist + t1 = message.get("timestamp") + t0 = user_message.get("timestamp") + if t1 and t0: + response_times.append(t1 - t0) + + average_response_time = ( + sum(response_times) / len(response_times) if response_times else 0 ) - / len(history_assistant_messages) - if history_assistant_messages - else 0 - ) - # Response Times - response_times = [] - for message in history_assistant_messages: - user_message_id = message.get("parentId", None) - if user_message_id and user_message_id in messages_map: - user_message = messages_map[user_message_id] - # Ensure timestamps exist - t1 = message.get("timestamp") - t0 = user_message.get("timestamp") - if t1 and t0: - response_times.append(t1 - t0) + # Current Message List Logic (Main path) + message_list = get_message_list(messages_map, message_id) + message_count = len(message_list) + models = {} + for message in reversed(message_list): + if message.get("role") == "assistant": + model = message.get("model") + if model: + if model not in models: + models[model] = 0 + models[model] += 1 - average_response_time = ( - sum(response_times) / len(response_times) if response_times else 0 - ) + # Construct Aggregate Stats + stats = AggregateChatStats( + average_response_time=average_response_time, + average_user_message_content_length=average_user_message_content_length, + average_assistant_message_content_length=average_assistant_message_content_length, + models=models, + message_count=message_count, + history_models=history_models, + history_message_count=history_message_count, + history_user_message_count=len(history_user_messages), + history_assistant_message_count=len(history_assistant_messages), + ) - # Current Message List Logic (Main path) - message_list = get_message_list(messages_map, message_id) - message_count = len(message_list) - models = {} - for message in reversed(message_list): - if message.get("role") == "assistant": - model = message.get("model") - if model: - if model not in models: - models[model] = 0 - models[model] += 1 + # Construct Chat Body + chat_body = ChatBody( + history=ChatHistoryStats( + messages=export_messages, currentId=message_id + ) + ) - # Construct Aggregate Stats - stats = AggregateChatStats( - average_response_time=average_response_time, - average_user_message_content_length=average_user_message_content_length, - average_assistant_message_content_length=average_assistant_message_content_length, - models=models, - message_count=message_count, - history_models=history_models, - history_message_count=history_message_count, - history_user_message_count=len(history_user_messages), - history_assistant_message_count=len(history_assistant_messages), - ) - - # Construct Chat Body - chat_body = ChatBody( - history=ChatHistoryStats(messages=export_messages, currentId=message_id) - ) - - chat_stats_export_list.append( - ChatStatsExport( + chat_stat = ChatStatsExport( id=chat.id, user_id=chat.user_id, created_at=chat.created_at, @@ -378,7 +381,11 @@ async def export_chat_stats( stats=stats, chat=chat_body, ) - ) + + chat_stats_export_list.append(chat_stat) + except Exception as e: + log.debug(f"Error exporting stats for chat {chat.id}: {e}") + continue return ChatStatsExportList( items=chat_stats_export_list, total=result.total, page=page diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts index 010c80a56f..435ffda800 100644 --- a/src/lib/apis/chats/index.ts +++ b/src/lib/apis/chats/index.ts @@ -1166,3 +1166,44 @@ export const archiveAllChats = async (token: string) => { return res; }; +export const exportChatStats = async (token: string, page: number = 1, params: object = {}) => { + let error = null; + + const searchParams = new URLSearchParams(); + searchParams.append('page', `${page}`); + + if (params) { + for (const [key, value] of Object.entries(params)) { + searchParams.append(key, `${value}`); + } + } + + const res = await fetch(`${WEBUI_API_BASE_URL}/chats/stats/export?${searchParams.toString()}`, { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + } + }) + .then(async (res) => { + if (!res.ok) throw await res.json(); + return res.json(); + }) + .then((json) => { + return json; + }) + .catch((err) => { + error = err; + console.error(err); + return null; + }); + + if (error) { + throw error; + } + + return res; +}; + + diff --git a/src/lib/components/chat/Settings/SyncStatsModal.svelte b/src/lib/components/chat/Settings/SyncStatsModal.svelte new file mode 100644 index 0000000000..c90da41031 --- /dev/null +++ b/src/lib/components/chat/Settings/SyncStatsModal.svelte @@ -0,0 +1,174 @@ + + + +
+ {#if completed} +
+ + +
+ +
+ +
+ {$i18n.t('Sync Complete!')} +
+ +
+ {$i18n.t('Your usage stats have been successfully synced with the Open WebUI Community.')} +
+ + +
+ {:else} +
+
{$i18n.t('Sync Usage Stats')}
+ +
+ +
+
+ {$i18n.t('Do you want to sync your usage stats with Open WebUI Community?')} +
+ +
+ {$i18n.t( + '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.' + )} +
+ +
+
+ {$i18n.t('What is shared:')} +
+
    +
  • {$i18n.t('Model usage counts and preferences')}
  • +
  • {$i18n.t('Message counts and response timestamps')}
  • +
  • {$i18n.t('Content lengths (character counts only)')}
  • +
  • {$i18n.t('User ratings (thumbs up/down)')}
  • +
+ +
+ {$i18n.t('What is NOT shared:')} +
+
    +
  • {$i18n.t('Your message text or inputs')}
  • +
  • {$i18n.t('Model responses or outputs')}
  • +
  • {$i18n.t('Uploaded files or images')}
  • +
+
+ + {#if loading} +
+
+
{$i18n.t('Syncing stats...')}
+
{Math.round((processedItemsCount / total) * 100) || 0}%
+
+
+
+
+
+ {/if} + +
+ + +
+
+ {/if} +
+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 288a0668a2..e91d136574 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -54,6 +54,7 @@ import NotificationToast from '$lib/components/NotificationToast.svelte'; import AppSidebar from '$lib/components/app/AppSidebar.svelte'; + import SyncStatsModal from '$lib/components/chat/Settings/SyncStatsModal.svelte'; import Spinner from '$lib/components/common/Spinner.svelte'; import { getUserSettings } from '$lib/apis/users'; import dayjs from 'dayjs'; @@ -89,6 +90,8 @@ let tokenTimer = null; let showRefresh = false; + let showSyncStatsModal = false; + let syncStatsParams = {}; let heartbeatInterval = null; @@ -600,7 +603,24 @@ } }; + const windowMessageEventHandler = async (event) => { + if ( + !['https://openwebui.com', 'https://www.openwebui.com', 'http://localhost:9999'].includes( + event.origin + ) + ) { + return; + } + + if (event.data === 'export:stats' || event.data?.type === 'export:stats') { + syncStatsParams = event.data?.searchParams ?? {}; + showSyncStatsModal = true; + } + }; + onMount(async () => { + window.addEventListener('message', windowMessageEventHandler); + let touchstartY = 0; function isNavOrDescendant(el) { @@ -814,10 +834,20 @@ loaded = true; } + // Notify opener window that the app has loaded + if (window.opener ?? false) { + window.opener.postMessage('loaded', '*'); + } + return () => { window.removeEventListener('resize', onResize); }; }); + + onDestroy(() => { + window.removeEventListener('message', windowMessageEventHandler); + bc.close(); + }); @@ -855,6 +885,10 @@ {/if} {/if} +{#if $config?.features.enable_community_sharing} + +{/if} + Date: Fri, 26 Dec 2025 15:36:56 +0400 Subject: [PATCH 010/254] refac --- .../chat/Settings/SyncStatsModal.svelte | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/lib/components/chat/Settings/SyncStatsModal.svelte b/src/lib/components/chat/Settings/SyncStatsModal.svelte index c90da41031..837e1ef829 100644 --- a/src/lib/components/chat/Settings/SyncStatsModal.svelte +++ b/src/lib/components/chat/Settings/SyncStatsModal.svelte @@ -1,9 +1,12 @@ @@ -127,7 +236,7 @@ on:click={() => { show = false; }} - disabled={loading} + disabled={syncing} > @@ -166,10 +275,12 @@ - {#if loading} -
+ {#if syncing} +
-
{$i18n.t('Syncing stats...')}
+
+ {downloading ? $i18n.t('Downloading stats...') : $i18n.t('Syncing stats...')} +
{Math.round((processedItemsCount / total) * 100) || 0}%
@@ -181,23 +292,51 @@
{/if} -
+
+
+ +
+ -
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index c7bb8c5c50..ee2e5c16e1 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -91,7 +91,7 @@ let showRefresh = false; - let showSyncStatsModal = false; + let showSyncStatsModal = true; let syncStatsEventData = null; let heartbeatInterval = null; From 7b6f8b49e093eff97c9629846715ed710509ef46 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 27 Dec 2025 22:16:24 +0400 Subject: [PATCH 027/254] 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 ee2e5c16e1..c7bb8c5c50 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -91,7 +91,7 @@ let showRefresh = false; - let showSyncStatsModal = true; + let showSyncStatsModal = false; let syncStatsEventData = null; let heartbeatInterval = null; From d4de26bd05193597497ed8032c2154e6cc9872e6 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 27 Dec 2025 22:31:18 +0400 Subject: [PATCH 028/254] refac --- .../components/chat/Settings/SyncStatsModal.svelte | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib/components/chat/Settings/SyncStatsModal.svelte b/src/lib/components/chat/Settings/SyncStatsModal.svelte index 1a05cb8ebb..1776d3eda8 100644 --- a/src/lib/components/chat/Settings/SyncStatsModal.svelte +++ b/src/lib/components/chat/Settings/SyncStatsModal.svelte @@ -110,17 +110,19 @@ cancelDownload(); return; } + downloading = true; + syncing = true; // Get total count first - const _res = await exportChatStats(localStorage.token, 1, eventData?.searchParams ?? {}).catch(() => { - return null; - }); + const _res = await exportChatStats(localStorage.token, 1, eventData?.searchParams ?? {}).catch( + () => { + return null; + } + ); if (_res) { total = _res.total; } - downloading = true; - syncing = true; processedItemsCount = 0; const resVersion = await getVersion(localStorage.token).catch(() => { return null; From 2041ab483e21b3a757baa25c47dc2fa29018674f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 28 Dec 2025 22:00:44 +0400 Subject: [PATCH 029/254] refac/enh: db session sharing --- backend/open_webui/internal/db.py | 10 ++ backend/open_webui/models/auths.py | 38 ++-- backend/open_webui/models/channels.py | 23 ++- backend/open_webui/models/chats.py | 186 ++++++++++---------- backend/open_webui/models/feedbacks.py | 55 +++--- backend/open_webui/models/files.py | 52 +++--- backend/open_webui/models/folders.py | 56 +++--- backend/open_webui/models/functions.py | 77 ++++---- backend/open_webui/models/groups.py | 83 ++++----- backend/open_webui/models/knowledge.py | 99 ++++++----- backend/open_webui/models/memories.py | 33 ++-- backend/open_webui/models/messages.py | 85 ++++----- backend/open_webui/models/models.py | 61 +++---- backend/open_webui/models/notes.py | 43 +++-- backend/open_webui/models/oauth_sessions.py | 38 ++-- backend/open_webui/models/prompts.py | 32 ++-- backend/open_webui/models/tags.py | 23 +-- backend/open_webui/models/tools.py | 51 +++--- backend/open_webui/models/users.py | 115 ++++++------ backend/open_webui/routers/notes.py | 2 +- 20 files changed, 600 insertions(+), 562 deletions(-) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index 95571c2435..e84dfe9aa7 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -160,3 +160,13 @@ def get_session(): get_db = contextmanager(get_session) + + +@contextmanager +def get_db_context(db: Optional[Session] = None): + if db: + yield db + else: + with get_db() as session: + yield session + diff --git a/backend/open_webui/models/auths.py b/backend/open_webui/models/auths.py index cb6c057c88..bb74fb7ded 100644 --- a/backend/open_webui/models/auths.py +++ b/backend/open_webui/models/auths.py @@ -2,7 +2,8 @@ import logging import uuid from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.users import UserModel, UserProfileImageResponse, Users from pydantic import BaseModel from sqlalchemy import Boolean, Column, String, Text @@ -87,8 +88,9 @@ class AuthsTable: profile_image_url: str = "/user.png", role: str = "pending", oauth: Optional[dict] = None, + db: Optional[Session] = None, ) -> Optional[UserModel]: - with get_db() as db: + with get_db_context(db) as db: log.info("insert_new_auth") id = str(uuid.uuid4()) @@ -100,7 +102,7 @@ class AuthsTable: db.add(result) user = Users.insert_new_user( - id, name, email, profile_image_url, role, oauth=oauth + id, name, email, profile_image_url, role, oauth=oauth, db=db ) db.commit() @@ -112,16 +114,16 @@ class AuthsTable: return None def authenticate_user( - self, email: str, verify_password: callable + self, email: str, verify_password: callable, db: Optional[Session] = None ) -> Optional[UserModel]: log.info(f"authenticate_user: {email}") - user = Users.get_user_by_email(email) + user = Users.get_user_by_email(email, db=db) if not user: return None try: - with get_db() as db: + with get_db_context(db) as db: auth = db.query(Auth).filter_by(id=user.id, active=True).first() if auth: if verify_password(auth.password): @@ -133,32 +135,32 @@ class AuthsTable: except Exception: return None - def authenticate_user_by_api_key(self, api_key: str) -> Optional[UserModel]: + def authenticate_user_by_api_key(self, api_key: str, db: Optional[Session] = None) -> Optional[UserModel]: log.info(f"authenticate_user_by_api_key: {api_key}") # if no api_key, return None if not api_key: return None try: - user = Users.get_user_by_api_key(api_key) + user = Users.get_user_by_api_key(api_key, db=db) return user if user else None except Exception: return False - def authenticate_user_by_email(self, email: str) -> Optional[UserModel]: + def authenticate_user_by_email(self, email: str, db: Optional[Session] = None) -> Optional[UserModel]: log.info(f"authenticate_user_by_email: {email}") try: - with get_db() as db: + with get_db_context(db) as db: auth = db.query(Auth).filter_by(email=email, active=True).first() if auth: - user = Users.get_user_by_id(auth.id) + user = Users.get_user_by_id(auth.id, db=db) return user except Exception: return None - def update_user_password_by_id(self, id: str, new_password: str) -> bool: + def update_user_password_by_id(self, id: str, new_password: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: result = ( db.query(Auth).filter_by(id=id).update({"password": new_password}) ) @@ -167,20 +169,20 @@ class AuthsTable: except Exception: return False - def update_email_by_id(self, id: str, email: str) -> bool: + def update_email_by_id(self, id: str, email: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: result = db.query(Auth).filter_by(id=id).update({"email": email}) db.commit() return True if result == 1 else False except Exception: return False - def delete_auth_by_id(self, id: str) -> bool: + def delete_auth_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: # Delete User - result = Users.delete_user_by_id(id) + result = Users.delete_user_by_id(id, db=db) if result: db.query(Auth).filter_by(id=id).delete() diff --git a/backend/open_webui/models/channels.py b/backend/open_webui/models/channels.py index 362222a284..3aba302ff0 100644 --- a/backend/open_webui/models/channels.py +++ b/backend/open_webui/models/channels.py @@ -1,9 +1,11 @@ + import json import time import uuid from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.groups import Groups from pydantic import BaseModel, ConfigDict @@ -337,8 +339,8 @@ class ChannelTable: db.commit() return channel - def get_channels(self) -> list[ChannelModel]: - with get_db() as db: + def get_channels(self, db: Optional[Session] = None) -> list[ChannelModel]: + with get_db_context(db) as db: channels = db.query(Channel).all() return [ChannelModel.model_validate(channel) for channel in channels] @@ -384,8 +386,8 @@ class ChannelTable: return query - def get_channels_by_user_id(self, user_id: str) -> list[ChannelModel]: - with get_db() as db: + def get_channels_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[ChannelModel]: + with get_db_context(db) as db: user_group_ids = [ group.id for group in Groups.get_groups_by_member_id(user_id) ] @@ -683,10 +685,13 @@ class ChannelTable: ) return membership is not None - def get_channel_by_id(self, id: str) -> Optional[ChannelModel]: - with get_db() as db: - channel = db.query(Channel).filter(Channel.id == id).first() - return ChannelModel.model_validate(channel) if channel else None + def get_channel_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChannelModel]: + try: + with get_db_context(db) as db: + channel = db.query(Channel).filter(Channel.id == id).first() + return ChannelModel.model_validate(channel) if channel else None + except Exception: + return None def get_channels_by_file_id(self, file_id: str) -> list[ChannelModel]: with get_db() as db: diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index d7153a2330..a8e3d27b99 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -4,7 +4,8 @@ import time import uuid from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.tags import TagModel, Tag, Tags from open_webui.models.folders import Folders from open_webui.utils.misc import sanitize_data_for_db, sanitize_text_for_db @@ -280,8 +281,8 @@ class ChatTable: return changed - def insert_new_chat(self, user_id: str, form_data: ChatForm) -> Optional[ChatModel]: - with get_db() as db: + def insert_new_chat(self, user_id: str, form_data: ChatForm, db: Optional[Session] = None) -> Optional[ChatModel]: + with get_db_context(db) as db: id = str(uuid.uuid4()) chat = ChatModel( **{ @@ -331,9 +332,9 @@ class ChatTable: return chat def import_chats( - self, user_id: str, chat_import_forms: list[ChatImportForm] + self, user_id: str, chat_import_forms: list[ChatImportForm], db: Optional[Session] = None ) -> list[ChatModel]: - with get_db() as db: + with get_db_context(db) as db: chats = [] for form_data in chat_import_forms: @@ -344,9 +345,9 @@ class ChatTable: db.commit() return [ChatModel.model_validate(chat) for chat in chats] - def update_chat_by_id(self, id: str, chat: dict) -> Optional[ChatModel]: + def update_chat_by_id(self, id: str, chat: dict, db: Optional[Session] = None) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat_item = db.get(Chat, id) chat_item.chat = self._clean_null_bytes(chat) chat_item.title = ( @@ -483,13 +484,13 @@ class ChatTable: self.update_chat_by_id(id, chat) return message_files - def insert_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: - with get_db() as db: + def insert_shared_chat_by_chat_id(self, chat_id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + with get_db_context(db) as db: # Get the existing chat to share chat = db.get(Chat, chat_id) # Check if the chat is already shared if chat.share_id: - return self.get_chat_by_id_and_user_id(chat.share_id, "shared") + return self.get_chat_by_id_and_user_id(chat.share_id, "shared", db=db) # Create a new chat with the same data, but with a new ID shared_chat = ChatModel( **{ @@ -518,16 +519,16 @@ class ChatTable: db.commit() return shared_chat if (shared_result and result) else None - def update_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: + def update_shared_chat_by_chat_id(self, chat_id: str, db: Optional[Session] = None) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, chat_id) shared_chat = ( db.query(Chat).filter_by(user_id=f"shared-{chat_id}").first() ) if shared_chat is None: - return self.insert_shared_chat_by_chat_id(chat_id) + return self.insert_shared_chat_by_chat_id(chat_id, db=db) shared_chat.title = chat.title shared_chat.chat = chat.chat @@ -542,9 +543,9 @@ class ChatTable: except Exception: return None - def delete_shared_chat_by_chat_id(self, chat_id: str) -> bool: + def delete_shared_chat_by_chat_id(self, chat_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Chat).filter_by(user_id=f"shared-{chat_id}").delete() db.commit() @@ -552,9 +553,9 @@ class ChatTable: except Exception: return False - def unarchive_all_chats_by_user_id(self, user_id: str) -> bool: + def unarchive_all_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Chat).filter_by(user_id=user_id).update({"archived": False}) db.commit() return True @@ -562,10 +563,10 @@ class ChatTable: return False def update_chat_share_id_by_id( - self, id: str, share_id: Optional[str] + self, id: str, share_id: Optional[str], db: Optional[Session] = None ) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, id) chat.share_id = share_id db.commit() @@ -574,9 +575,9 @@ class ChatTable: except Exception: return None - def toggle_chat_pinned_by_id(self, id: str) -> Optional[ChatModel]: + def toggle_chat_pinned_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, id) chat.pinned = not chat.pinned chat.updated_at = int(time.time()) @@ -586,9 +587,9 @@ class ChatTable: except Exception: return None - def toggle_chat_archive_by_id(self, id: str) -> Optional[ChatModel]: + def toggle_chat_archive_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, id) chat.archived = not chat.archived chat.folder_id = None @@ -599,9 +600,9 @@ class ChatTable: except Exception: return None - def archive_all_chats_by_user_id(self, user_id: str) -> bool: + def archive_all_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Chat).filter_by(user_id=user_id).update({"archived": True}) db.commit() return True @@ -614,9 +615,10 @@ class ChatTable: filter: Optional[dict] = None, skip: int = 0, limit: int = 50, + db: Optional[Session] = None, ) -> list[ChatModel]: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id, archived=True) if filter: @@ -655,8 +657,9 @@ class ChatTable: filter: Optional[dict] = None, skip: int = 0, limit: int = 50, + db: Optional[Session] = None, ) -> list[ChatModel]: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id) if not include_archived: query = query.filter_by(archived=False) @@ -695,8 +698,9 @@ class ChatTable: include_pinned: bool = False, skip: Optional[int] = None, limit: Optional[int] = None, + db: Optional[Session] = None, ) -> list[ChatTitleIdResponse]: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id) if not include_folders: @@ -733,9 +737,9 @@ class ChatTable: ] def get_chat_list_by_chat_ids( - self, chat_ids: list[str], skip: int = 0, limit: int = 50 + self, chat_ids: list[str], skip: int = 0, limit: int = 50, db: Optional[Session] = None ) -> list[ChatModel]: - with get_db() as db: + with get_db_context(db) as db: all_chats = ( db.query(Chat) .filter(Chat.id.in_(chat_ids)) @@ -745,9 +749,9 @@ class ChatTable: ) return [ChatModel.model_validate(chat) for chat in all_chats] - def get_chat_by_id(self, id: str) -> Optional[ChatModel]: + def get_chat_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat_item = db.get(Chat, id) if chat_item is None: return None @@ -760,30 +764,30 @@ class ChatTable: except Exception: return None - def get_chat_by_share_id(self, id: str) -> Optional[ChatModel]: + def get_chat_by_share_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: # it is possible that the shared link was deleted. hence, # we check if the chat is still shared by checking if a chat with the share_id exists chat = db.query(Chat).filter_by(share_id=id).first() if chat: - return self.get_chat_by_id(id) + return self.get_chat_by_id(id, db=db) else: return None except Exception: return None - def get_chat_by_id_and_user_id(self, id: str, user_id: str) -> Optional[ChatModel]: + def get_chat_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.query(Chat).filter_by(id=id, user_id=user_id).first() return ChatModel.model_validate(chat) except Exception: return None - def get_chats(self, skip: int = 0, limit: int = 50) -> list[ChatModel]: - with get_db() as db: + def get_chats(self, skip: int = 0, limit: int = 50, db: Optional[Session] = None) -> list[ChatModel]: + with get_db_context(db) as db: all_chats = ( db.query(Chat) # .limit(limit).offset(skip) @@ -797,8 +801,9 @@ class ChatTable: filter: Optional[dict] = None, skip: Optional[int] = None, limit: Optional[int] = None, + db: Optional[Session] = None, ) -> ChatListResponse: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id) if filter: @@ -838,8 +843,8 @@ class ChatTable: } ) - def get_pinned_chats_by_user_id(self, user_id: str) -> list[ChatModel]: - with get_db() as db: + def get_pinned_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[ChatModel]: + with get_db_context(db) as db: all_chats = ( db.query(Chat) .filter_by(user_id=user_id, pinned=True, archived=False) @@ -847,8 +852,8 @@ class ChatTable: ) return [ChatModel.model_validate(chat) for chat in all_chats] - def get_archived_chats_by_user_id(self, user_id: str) -> list[ChatModel]: - with get_db() as db: + def get_archived_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[ChatModel]: + with get_db_context(db) as db: all_chats = ( db.query(Chat) .filter_by(user_id=user_id, archived=True) @@ -863,6 +868,7 @@ class ChatTable: include_archived: bool = False, skip: int = 0, limit: int = 60, + db: Optional[Session] = None, ) -> list[ChatModel]: """ Filters chats based on a search query using Python, allowing pagination using skip and limit. @@ -871,7 +877,7 @@ class ChatTable: if not search_text: return self.get_chat_list_by_user_id( - user_id, include_archived, filter={}, skip=skip, limit=limit + user_id, include_archived, filter={}, skip=skip, limit=limit, db=db ) search_text_words = search_text.split(" ") @@ -926,7 +932,7 @@ class ChatTable: search_text = " ".join(search_text_words) - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter(Chat.user_id == user_id) if is_archived is not None: @@ -1067,9 +1073,9 @@ class ChatTable: return [ChatModel.model_validate(chat) for chat in all_chats] def get_chats_by_folder_id_and_user_id( - self, folder_id: str, user_id: str, skip: int = 0, limit: int = 60 + self, folder_id: str, user_id: str, skip: int = 0, limit: int = 60, db: Optional[Session] = None ) -> list[ChatModel]: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter_by(folder_id=folder_id, user_id=user_id) query = query.filter(or_(Chat.pinned == False, Chat.pinned == None)) query = query.filter_by(archived=False) @@ -1085,9 +1091,9 @@ class ChatTable: return [ChatModel.model_validate(chat) for chat in all_chats] def get_chats_by_folder_ids_and_user_id( - self, folder_ids: list[str], user_id: str + self, folder_ids: list[str], user_id: str, db: Optional[Session] = None ) -> list[ChatModel]: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter( Chat.folder_id.in_(folder_ids), Chat.user_id == user_id ) @@ -1100,10 +1106,10 @@ class ChatTable: return [ChatModel.model_validate(chat) for chat in all_chats] def update_chat_folder_id_by_id_and_user_id( - self, id: str, user_id: str, folder_id: str + self, id: str, user_id: str, folder_id: str, db: Optional[Session] = None ) -> Optional[ChatModel]: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, id) chat.folder_id = folder_id chat.updated_at = int(time.time()) @@ -1114,16 +1120,16 @@ class ChatTable: except Exception: return None - def get_chat_tags_by_id_and_user_id(self, id: str, user_id: str) -> list[TagModel]: - with get_db() as db: + def get_chat_tags_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> list[TagModel]: + with get_db_context(db) as db: chat = db.get(Chat, id) tags = chat.meta.get("tags", []) return [Tags.get_tag_by_name_and_user_id(tag, user_id) for tag in tags] def get_chat_list_by_user_id_and_tag_name( - self, user_id: str, tag_name: str, skip: int = 0, limit: int = 50 + self, user_id: str, tag_name: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None ) -> list[ChatModel]: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id) tag_id = tag_name.replace(" ", "_").lower() @@ -1152,13 +1158,13 @@ class ChatTable: return [ChatModel.model_validate(chat) for chat in all_chats] def add_chat_tag_by_id_and_user_id_and_tag_name( - self, id: str, user_id: str, tag_name: str + self, id: str, user_id: str, tag_name: str, db: Optional[Session] = None ) -> Optional[ChatModel]: tag = Tags.get_tag_by_name_and_user_id(tag_name, user_id) if tag is None: tag = Tags.insert_new_tag(tag_name, user_id) try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, id) tag_id = tag.id @@ -1174,8 +1180,8 @@ class ChatTable: except Exception: return None - def count_chats_by_tag_name_and_user_id(self, tag_name: str, user_id: str) -> int: - with get_db() as db: # Assuming `get_db()` returns a session object + def count_chats_by_tag_name_and_user_id(self, tag_name: str, user_id: str, db: Optional[Session] = None) -> int: + with get_db_context(db) as db: # Assuming `get_db()` returns a session object query = db.query(Chat).filter_by(user_id=user_id, archived=False) # Normalize the tag_name for consistency @@ -1210,8 +1216,8 @@ class ChatTable: return count - def count_chats_by_folder_id_and_user_id(self, folder_id: str, user_id: str) -> int: - with get_db() as db: + def count_chats_by_folder_id_and_user_id(self, folder_id: str, user_id: str, db: Optional[Session] = None) -> int: + with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id) query = query.filter_by(folder_id=folder_id) @@ -1221,10 +1227,10 @@ class ChatTable: return count def delete_tag_by_id_and_user_id_and_tag_name( - self, id: str, user_id: str, tag_name: str + self, id: str, user_id: str, tag_name: str, db: Optional[Session] = None ) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, id) tags = chat.meta.get("tags", []) tag_id = tag_name.replace(" ", "_").lower() @@ -1239,9 +1245,9 @@ class ChatTable: except Exception: return False - def delete_all_tags_by_id_and_user_id(self, id: str, user_id: str) -> bool: + def delete_all_tags_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: chat = db.get(Chat, id) chat.meta = { **chat.meta, @@ -1253,30 +1259,30 @@ class ChatTable: except Exception: return False - def delete_chat_by_id(self, id: str) -> bool: + def delete_chat_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Chat).filter_by(id=id).delete() db.commit() - return True and self.delete_shared_chat_by_chat_id(id) + return True and self.delete_shared_chat_by_chat_id(id, db=db) except Exception: return False - def delete_chat_by_id_and_user_id(self, id: str, user_id: str) -> bool: + def delete_chat_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Chat).filter_by(id=id, user_id=user_id).delete() db.commit() - return True and self.delete_shared_chat_by_chat_id(id) + return True and self.delete_shared_chat_by_chat_id(id, db=db) except Exception: return False - def delete_chats_by_user_id(self, user_id: str) -> bool: + def delete_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: - self.delete_shared_chats_by_user_id(user_id) + with get_db_context(db) as db: + self.delete_shared_chats_by_user_id(user_id, db=db) db.query(Chat).filter_by(user_id=user_id).delete() db.commit() @@ -1286,10 +1292,10 @@ class ChatTable: return False def delete_chats_by_user_id_and_folder_id( - self, user_id: str, folder_id: str + self, user_id: str, folder_id: str, db: Optional[Session] = None ) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Chat).filter_by(user_id=user_id, folder_id=folder_id).delete() db.commit() @@ -1298,10 +1304,10 @@ class ChatTable: return False def move_chats_by_user_id_and_folder_id( - self, user_id: str, folder_id: str, new_folder_id: Optional[str] + self, user_id: str, folder_id: str, new_folder_id: Optional[str], db: Optional[Session] = None ) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Chat).filter_by(user_id=user_id, folder_id=folder_id).update( {"folder_id": new_folder_id} ) @@ -1311,9 +1317,9 @@ class ChatTable: except Exception: return False - def delete_shared_chats_by_user_id(self, user_id: str) -> bool: + def delete_shared_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: chats_by_user = db.query(Chat).filter_by(user_id=user_id).all() shared_chat_ids = [f"shared-{chat.id}" for chat in chats_by_user] @@ -1325,7 +1331,7 @@ class ChatTable: return False def insert_chat_files( - self, chat_id: str, message_id: str, file_ids: list[str], user_id: str + self, chat_id: str, message_id: str, file_ids: list[str], user_id: str, db: Optional[Session] = None ) -> Optional[list[ChatFileModel]]: if not file_ids: return None @@ -1333,7 +1339,7 @@ class ChatTable: chat_message_file_ids = [ item.id for item in self.get_chat_files_by_chat_id_and_message_id( - chat_id, message_id + chat_id, message_id, db=db ) ] # Remove duplicates and existing file_ids @@ -1350,7 +1356,7 @@ class ChatTable: return None try: - with get_db() as db: + with get_db_context(db) as db: now = int(time.time()) chat_files = [ @@ -1378,9 +1384,9 @@ class ChatTable: return None def get_chat_files_by_chat_id_and_message_id( - self, chat_id: str, message_id: str + self, chat_id: str, message_id: str, db: Optional[Session] = None ) -> list[ChatFileModel]: - with get_db() as db: + with get_db_context(db) as db: all_chat_files = ( db.query(ChatFile) .filter_by(chat_id=chat_id, message_id=message_id) @@ -1391,17 +1397,17 @@ class ChatTable: ChatFileModel.model_validate(chat_file) for chat_file in all_chat_files ] - def delete_chat_file(self, chat_id: str, file_id: str) -> bool: + def delete_chat_file(self, chat_id: str, file_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(ChatFile).filter_by(chat_id=chat_id, file_id=file_id).delete() db.commit() return True except Exception: return False - def get_shared_chats_by_file_id(self, file_id: str) -> list[ChatModel]: - with get_db() as db: + def get_shared_chats_by_file_id(self, file_id: str, db: Optional[Session] = None) -> list[ChatModel]: + with get_db_context(db) as db: # Join Chat and ChatFile tables to get shared chats associated with the file_id all_chats = ( db.query(Chat) diff --git a/backend/open_webui/models/feedbacks.py b/backend/open_webui/models/feedbacks.py index 39e22ff2d9..fa2629a684 100644 --- a/backend/open_webui/models/feedbacks.py +++ b/backend/open_webui/models/feedbacks.py @@ -3,7 +3,8 @@ import time import uuid from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.users import User from pydantic import BaseModel, ConfigDict @@ -121,9 +122,9 @@ class FeedbackListResponse(BaseModel): class FeedbackTable: def insert_new_feedback( - self, user_id: str, form_data: FeedbackForm + self, user_id: str, form_data: FeedbackForm, db: Optional[Session] = None ) -> Optional[FeedbackModel]: - with get_db() as db: + with get_db_context(db) as db: id = str(uuid.uuid4()) feedback = FeedbackModel( **{ @@ -148,9 +149,9 @@ class FeedbackTable: log.exception(f"Error creating a new feedback: {e}") return None - def get_feedback_by_id(self, id: str) -> Optional[FeedbackModel]: + def get_feedback_by_id(self, id: str, db: Optional[Session] = None) -> Optional[FeedbackModel]: try: - with get_db() as db: + with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id).first() if not feedback: return None @@ -159,10 +160,10 @@ class FeedbackTable: return None def get_feedback_by_id_and_user_id( - self, id: str, user_id: str + self, id: str, user_id: str, db: Optional[Session] = None ) -> Optional[FeedbackModel]: try: - with get_db() as db: + with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id, user_id=user_id).first() if not feedback: return None @@ -171,9 +172,9 @@ class FeedbackTable: return None def get_feedback_items( - self, filter: dict = {}, skip: int = 0, limit: int = 30 + self, filter: dict = {}, skip: int = 0, limit: int = 30, db: Optional[Session] = None ) -> FeedbackListResponse: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Feedback, User).join(User, Feedback.user_id == User.id) if filter: @@ -234,8 +235,8 @@ class FeedbackTable: return FeedbackListResponse(items=feedbacks, total=total) - def get_all_feedbacks(self) -> list[FeedbackModel]: - with get_db() as db: + def get_all_feedbacks(self, db: Optional[Session] = None) -> list[FeedbackModel]: + with get_db_context(db) as db: return [ FeedbackModel.model_validate(feedback) for feedback in db.query(Feedback) @@ -243,8 +244,8 @@ class FeedbackTable: .all() ] - def get_feedbacks_by_type(self, type: str) -> list[FeedbackModel]: - with get_db() as db: + def get_feedbacks_by_type(self, type: str, db: Optional[Session] = None) -> list[FeedbackModel]: + with get_db_context(db) as db: return [ FeedbackModel.model_validate(feedback) for feedback in db.query(Feedback) @@ -253,8 +254,8 @@ class FeedbackTable: .all() ] - def get_feedbacks_by_user_id(self, user_id: str) -> list[FeedbackModel]: - with get_db() as db: + def get_feedbacks_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[FeedbackModel]: + with get_db_context(db) as db: return [ FeedbackModel.model_validate(feedback) for feedback in db.query(Feedback) @@ -264,9 +265,9 @@ class FeedbackTable: ] def update_feedback_by_id( - self, id: str, form_data: FeedbackForm + self, id: str, form_data: FeedbackForm, db: Optional[Session] = None ) -> Optional[FeedbackModel]: - with get_db() as db: + with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id).first() if not feedback: return None @@ -284,9 +285,9 @@ class FeedbackTable: return FeedbackModel.model_validate(feedback) def update_feedback_by_id_and_user_id( - self, id: str, user_id: str, form_data: FeedbackForm + self, id: str, user_id: str, form_data: FeedbackForm, db: Optional[Session] = None ) -> Optional[FeedbackModel]: - with get_db() as db: + with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id, user_id=user_id).first() if not feedback: return None @@ -303,8 +304,8 @@ class FeedbackTable: db.commit() return FeedbackModel.model_validate(feedback) - def delete_feedback_by_id(self, id: str) -> bool: - with get_db() as db: + def delete_feedback_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id).first() if not feedback: return False @@ -312,8 +313,8 @@ class FeedbackTable: db.commit() return True - def delete_feedback_by_id_and_user_id(self, id: str, user_id: str) -> bool: - with get_db() as db: + def delete_feedback_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id, user_id=user_id).first() if not feedback: return False @@ -321,8 +322,8 @@ class FeedbackTable: db.commit() return True - def delete_feedbacks_by_user_id(self, user_id: str) -> bool: - with get_db() as db: + def delete_feedbacks_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: feedbacks = db.query(Feedback).filter_by(user_id=user_id).all() if not feedbacks: return False @@ -331,8 +332,8 @@ class FeedbackTable: db.commit() return True - def delete_all_feedbacks(self) -> bool: - with get_db() as db: + def delete_all_feedbacks(self, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: feedbacks = db.query(Feedback).all() if not feedbacks: return False diff --git a/backend/open_webui/models/files.py b/backend/open_webui/models/files.py index 9d4e8fb054..387dd5b28c 100644 --- a/backend/open_webui/models/files.py +++ b/backend/open_webui/models/files.py @@ -2,7 +2,8 @@ import logging import time from typing import Optional -from open_webui.internal.db import Base, JSONField, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from pydantic import BaseModel, ConfigDict from sqlalchemy import BigInteger, Column, String, Text, JSON @@ -108,8 +109,10 @@ class FileListResponse(BaseModel): class FilesTable: - def insert_new_file(self, user_id: str, form_data: FileForm) -> Optional[FileModel]: - with get_db() as db: + def insert_new_file( + self, user_id: str, form_data: FileForm, db: Optional[Session] = None + ) -> Optional[FileModel]: + with get_db_context(db) as db: file = FileModel( **{ **form_data.model_dump(), @@ -132,13 +135,16 @@ class FilesTable: log.exception(f"Error inserting a new file: {e}") return None - def get_file_by_id(self, id: str) -> Optional[FileModel]: - with get_db() as db: - try: - file = db.get(File, id) - return FileModel.model_validate(file) - except Exception: - return None + def get_file_by_id(self, id: str, db: Optional[Session] = None) -> Optional[FileModel]: + try: + with get_db_context(db) as db: + try: + file = db.get(File, id) + return FileModel.model_validate(file) + except Exception: + return None + except Exception: + return None def get_file_by_id_and_user_id(self, id: str, user_id: str) -> Optional[FileModel]: with get_db() as db: @@ -165,8 +171,8 @@ class FilesTable: except Exception: return None - def get_files(self) -> list[FileModel]: - with get_db() as db: + def get_files(self, db: Optional[Session] = None) -> list[FileModel]: + with get_db_context(db) as db: return [FileModel.model_validate(file) for file in db.query(File).all()] def check_access_by_user_id(self, id, user_id, permission="write") -> bool: @@ -206,8 +212,8 @@ class FilesTable: .all() ] - def get_files_by_user_id(self, user_id: str) -> list[FileModel]: - with get_db() as db: + def get_files_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[FileModel]: + with get_db_context(db) as db: return [ FileModel.model_validate(file) for file in db.query(File).filter_by(user_id=user_id).all() @@ -271,24 +277,6 @@ class FilesTable: except Exception: return None - def delete_file_by_id(self, id: str) -> bool: - with get_db() as db: - try: - db.query(File).filter_by(id=id).delete() - db.commit() - - return True - except Exception: - return False - - def delete_all_files(self) -> bool: - with get_db() as db: - try: - db.query(File).delete() - db.commit() - - return True - except Exception: return False diff --git a/backend/open_webui/models/folders.py b/backend/open_webui/models/folders.py index 0043dd3644..1744c29454 100644 --- a/backend/open_webui/models/folders.py +++ b/backend/open_webui/models/folders.py @@ -7,8 +7,9 @@ import re from pydantic import BaseModel, ConfigDict from sqlalchemy import BigInteger, Column, Text, JSON, Boolean, func +from sqlalchemy.orm import Session -from open_webui.internal.db import Base, get_db +from open_webui.internal.db import Base, JSONField, get_db, get_db_context log = logging.getLogger(__name__) @@ -83,9 +84,9 @@ class FolderUpdateForm(BaseModel): class FolderTable: def insert_new_folder( - self, user_id: str, form_data: FolderForm, parent_id: Optional[str] = None + self, user_id: str, form_data: FolderForm, parent_id: Optional[str] = None, db: Optional[Session] = None ) -> Optional[FolderModel]: - with get_db() as db: + with get_db_context(db) as db: id = str(uuid.uuid4()) folder = FolderModel( **{ @@ -111,10 +112,10 @@ class FolderTable: return None def get_folder_by_id_and_user_id( - self, id: str, user_id: str + self, id: str, user_id: str, db: Optional[Session] = None ) -> Optional[FolderModel]: try: - with get_db() as db: + with get_db_context(db) as db: folder = db.query(Folder).filter_by(id=id, user_id=user_id).first() if not folder: @@ -125,15 +126,15 @@ class FolderTable: return None def get_children_folders_by_id_and_user_id( - self, id: str, user_id: str + self, id: str, user_id: str, db: Optional[Session] = None ) -> Optional[list[FolderModel]]: try: - with get_db() as db: + with get_db_context(db) as db: folders = [] def get_children(folder): children = self.get_folders_by_parent_id_and_user_id( - folder.id, user_id + folder.id, user_id, db=db ) for child in children: get_children(child) @@ -148,18 +149,18 @@ class FolderTable: except Exception: return None - def get_folders_by_user_id(self, user_id: str) -> list[FolderModel]: - with get_db() as db: + def get_folders_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[FolderModel]: + with get_db_context(db) as db: return [ FolderModel.model_validate(folder) for folder in db.query(Folder).filter_by(user_id=user_id).all() ] def get_folder_by_parent_id_and_user_id_and_name( - self, parent_id: Optional[str], user_id: str, name: str + self, parent_id: Optional[str], user_id: str, name: str, db: Optional[Session] = None ) -> Optional[FolderModel]: try: - with get_db() as db: + with get_db_context(db) as db: # Check if folder exists folder = ( db.query(Folder) @@ -177,9 +178,9 @@ class FolderTable: return None def get_folders_by_parent_id_and_user_id( - self, parent_id: Optional[str], user_id: str + self, parent_id: Optional[str], user_id: str, db: Optional[Session] = None ) -> list[FolderModel]: - with get_db() as db: + with get_db_context(db) as db: return [ FolderModel.model_validate(folder) for folder in db.query(Folder) @@ -192,9 +193,10 @@ class FolderTable: id: str, user_id: str, parent_id: str, + db: Optional[Session] = None, ) -> Optional[FolderModel]: try: - with get_db() as db: + with get_db_context(db) as db: folder = db.query(Folder).filter_by(id=id, user_id=user_id).first() if not folder: @@ -211,10 +213,10 @@ class FolderTable: return def update_folder_by_id_and_user_id( - self, id: str, user_id: str, form_data: FolderUpdateForm + self, id: str, user_id: str, form_data: FolderUpdateForm, db: Optional[Session] = None ) -> Optional[FolderModel]: try: - with get_db() as db: + with get_db_context(db) as db: folder = db.query(Folder).filter_by(id=id, user_id=user_id).first() if not folder: @@ -257,10 +259,10 @@ class FolderTable: return def update_folder_is_expanded_by_id_and_user_id( - self, id: str, user_id: str, is_expanded: bool + self, id: str, user_id: str, is_expanded: bool, db: Optional[Session] = None ) -> Optional[FolderModel]: try: - with get_db() as db: + with get_db_context(db) as db: folder = db.query(Folder).filter_by(id=id, user_id=user_id).first() if not folder: @@ -276,10 +278,10 @@ class FolderTable: log.error(f"update_folder: {e}") return - def delete_folder_by_id_and_user_id(self, id: str, user_id: str) -> list[str]: + def delete_folder_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> list[str]: try: folder_ids = [] - with get_db() as db: + with get_db_context(db) as db: folder = db.query(Folder).filter_by(id=id, user_id=user_id).first() if not folder: return folder_ids @@ -289,7 +291,7 @@ class FolderTable: # Delete all children folders def delete_children(folder): folder_children = self.get_folders_by_parent_id_and_user_id( - folder.id, user_id + folder.id, user_id, db=db ) for folder_child in folder_children: @@ -314,7 +316,7 @@ class FolderTable: return name.strip().lower() def search_folders_by_names( - self, user_id: str, queries: list[str] + self, user_id: str, queries: list[str], db: Optional[Session] = None ) -> list[FolderModel]: """ Search for folders for a user where the name matches any of the queries, treating _ and space as equivalent, case-insensitive. @@ -324,7 +326,7 @@ class FolderTable: return [] results = {} - with get_db() as db: + with get_db_context(db) as db: folders = db.query(Folder).filter_by(user_id=user_id).all() for folder in folders: if self.normalize_folder_name(folder.name) in normalized_queries: @@ -332,7 +334,7 @@ class FolderTable: # get children folders children = self.get_children_folders_by_id_and_user_id( - folder.id, user_id + folder.id, user_id, db=db ) for child in children: results[child.id] = child @@ -345,14 +347,14 @@ class FolderTable: return results def search_folders_by_name_contains( - self, user_id: str, query: str + self, user_id: str, query: str, db: Optional[Session] = None ) -> list[FolderModel]: """ Partial match: normalized name contains (as substring) the normalized query. """ normalized_query = self.normalize_folder_name(query) results = [] - with get_db() as db: + with get_db_context(db) as db: folders = db.query(Folder).filter_by(user_id=user_id).all() for folder in folders: norm_name = self.normalize_folder_name(folder.name) diff --git a/backend/open_webui/models/functions.py b/backend/open_webui/models/functions.py index 19ad985d0c..f6d2aa3375 100644 --- a/backend/open_webui/models/functions.py +++ b/backend/open_webui/models/functions.py @@ -2,7 +2,8 @@ import logging import time from typing import Optional -from open_webui.internal.db import Base, JSONField, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.users import Users, UserModel from pydantic import BaseModel, ConfigDict from sqlalchemy import BigInteger, Boolean, Column, String, Text, Index @@ -103,7 +104,7 @@ class FunctionValves(BaseModel): class FunctionsTable: def insert_new_function( - self, user_id: str, type: str, form_data: FunctionForm + self, user_id: str, type: str, form_data: FunctionForm, db: Optional[Session] = None ) -> Optional[FunctionModel]: function = FunctionModel( **{ @@ -116,7 +117,7 @@ class FunctionsTable: ) try: - with get_db() as db: + with get_db_context(db) as db: result = Function(**function.model_dump()) db.add(result) db.commit() @@ -130,11 +131,11 @@ class FunctionsTable: return None def sync_functions( - self, user_id: str, functions: list[FunctionWithValvesModel] + self, user_id: str, functions: list[FunctionWithValvesModel], db: Optional[Session] = None ) -> list[FunctionWithValvesModel]: # Synchronize functions for a user by updating existing ones, inserting new ones, and removing those that are no longer present. try: - with get_db() as db: + with get_db_context(db) as db: # Get existing functions existing_functions = db.query(Function).all() existing_ids = {func.id for func in existing_functions} @@ -177,18 +178,18 @@ class FunctionsTable: log.exception(f"Error syncing functions for user {user_id}: {e}") return [] - def get_function_by_id(self, id: str) -> Optional[FunctionModel]: + def get_function_by_id(self, id: str, db: Optional[Session] = None) -> Optional[FunctionModel]: try: - with get_db() as db: + with get_db_context(db) as db: function = db.get(Function, id) return FunctionModel.model_validate(function) except Exception: return None def get_functions( - self, active_only=False, include_valves=False + self, active_only=False, include_valves=False, db: Optional[Session] = None ) -> list[FunctionModel | FunctionWithValvesModel]: - with get_db() as db: + with get_db_context(db) as db: if active_only: functions = db.query(Function).filter_by(is_active=True).all() @@ -205,12 +206,12 @@ class FunctionsTable: FunctionModel.model_validate(function) for function in functions ] - def get_function_list(self) -> list[FunctionUserResponse]: - with get_db() as db: + def get_function_list(self, db: Optional[Session] = None) -> list[FunctionUserResponse]: + with get_db_context(db) as db: functions = db.query(Function).order_by(Function.updated_at.desc()).all() user_ids = list(set(func.user_id for func in functions)) - users = Users.get_users_by_user_ids(user_ids) if user_ids else [] + users = Users.get_users_by_user_ids(user_ids, db=db) if user_ids else [] users_dict = {user.id: user for user in users} return [ @@ -228,9 +229,9 @@ class FunctionsTable: ] def get_functions_by_type( - self, type: str, active_only=False + self, type: str, active_only=False, db: Optional[Session] = None ) -> list[FunctionModel]: - with get_db() as db: + with get_db_context(db) as db: if active_only: return [ FunctionModel.model_validate(function) @@ -244,8 +245,8 @@ class FunctionsTable: for function in db.query(Function).filter_by(type=type).all() ] - def get_global_filter_functions(self) -> list[FunctionModel]: - with get_db() as db: + def get_global_filter_functions(self, db: Optional[Session] = None) -> list[FunctionModel]: + with get_db_context(db) as db: return [ FunctionModel.model_validate(function) for function in db.query(Function) @@ -253,8 +254,8 @@ class FunctionsTable: .all() ] - def get_global_action_functions(self) -> list[FunctionModel]: - with get_db() as db: + def get_global_action_functions(self, db: Optional[Session] = None) -> list[FunctionModel]: + with get_db_context(db) as db: return [ FunctionModel.model_validate(function) for function in db.query(Function) @@ -262,8 +263,8 @@ class FunctionsTable: .all() ] - def get_function_valves_by_id(self, id: str) -> Optional[dict]: - with get_db() as db: + def get_function_valves_by_id(self, id: str, db: Optional[Session] = None) -> Optional[dict]: + with get_db_context(db) as db: try: function = db.get(Function, id) return function.valves if function.valves else {} @@ -272,23 +273,23 @@ class FunctionsTable: return None def update_function_valves_by_id( - self, id: str, valves: dict + self, id: str, valves: dict, db: Optional[Session] = None ) -> Optional[FunctionValves]: - with get_db() as db: + with get_db_context(db) as db: try: function = db.get(Function, id) function.valves = valves function.updated_at = int(time.time()) db.commit() db.refresh(function) - return self.get_function_by_id(id) + return self.get_function_by_id(id, db=db) except Exception: return None def update_function_metadata_by_id( - self, id: str, metadata: dict + self, id: str, metadata: dict, db: Optional[Session] = None ) -> Optional[FunctionModel]: - with get_db() as db: + with get_db_context(db) as db: try: function = db.get(Function, id) @@ -301,7 +302,7 @@ class FunctionsTable: function.updated_at = int(time.time()) db.commit() db.refresh(function) - return self.get_function_by_id(id) + return self.get_function_by_id(id, db=db) else: return None except Exception as e: @@ -309,10 +310,10 @@ class FunctionsTable: return None def get_user_valves_by_id_and_user_id( - self, id: str, user_id: str + self, id: str, user_id: str, db: Optional[Session] = None ) -> Optional[dict]: try: - user = Users.get_user_by_id(user_id) + user = Users.get_user_by_id(user_id, db=db) user_settings = user.settings.model_dump() if user.settings else {} # Check if user has "functions" and "valves" settings @@ -327,10 +328,10 @@ class FunctionsTable: return None def update_user_valves_by_id_and_user_id( - self, id: str, user_id: str, valves: dict + self, id: str, user_id: str, valves: dict, db: Optional[Session] = None ) -> Optional[dict]: try: - user = Users.get_user_by_id(user_id) + user = Users.get_user_by_id(user_id, db=db) user_settings = user.settings.model_dump() if user.settings else {} # Check if user has "functions" and "valves" settings @@ -342,7 +343,7 @@ class FunctionsTable: user_settings["functions"]["valves"][id] = valves # Update the user settings in the database - Users.update_user_by_id(user_id, {"settings": user_settings}) + Users.update_user_by_id(user_id, {"settings": user_settings}, db=db) return user_settings["functions"]["valves"][id] except Exception as e: @@ -351,8 +352,8 @@ class FunctionsTable: ) return None - def update_function_by_id(self, id: str, updated: dict) -> Optional[FunctionModel]: - with get_db() as db: + def update_function_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[FunctionModel]: + with get_db_context(db) as db: try: db.query(Function).filter_by(id=id).update( { @@ -361,12 +362,12 @@ class FunctionsTable: } ) db.commit() - return self.get_function_by_id(id) + return self.get_function_by_id(id, db=db) except Exception: return None - def deactivate_all_functions(self) -> Optional[bool]: - with get_db() as db: + def deactivate_all_functions(self, db: Optional[Session] = None) -> Optional[bool]: + with get_db_context(db) as db: try: db.query(Function).update( { @@ -379,8 +380,8 @@ class FunctionsTable: except Exception: return None - def delete_function_by_id(self, id: str) -> bool: - with get_db() as db: + def delete_function_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: db.query(Function).filter_by(id=id).delete() db.commit() diff --git a/backend/open_webui/models/groups.py b/backend/open_webui/models/groups.py index da94287111..1ceb8f1ec0 100644 --- a/backend/open_webui/models/groups.py +++ b/backend/open_webui/models/groups.py @@ -4,7 +4,8 @@ import time from typing import Optional import uuid -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.files import FileMetadataResponse @@ -120,9 +121,9 @@ class GroupListResponse(BaseModel): class GroupTable: def insert_new_group( - self, user_id: str, form_data: GroupForm + self, user_id: str, form_data: GroupForm, db: Optional[Session] = None ) -> Optional[GroupModel]: - with get_db() as db: + with get_db_context(db) as db: group = GroupModel( **{ **form_data.model_dump(exclude_none=True), @@ -146,13 +147,13 @@ class GroupTable: except Exception: return None - def get_all_groups(self) -> list[GroupModel]: - with get_db() as db: + def get_all_groups(self, db: Optional[Session] = None) -> list[GroupModel]: + with get_db_context(db) as db: groups = db.query(Group).order_by(Group.updated_at.desc()).all() return [GroupModel.model_validate(group) for group in groups] - def get_groups(self, filter) -> list[GroupResponse]: - with get_db() as db: + def get_groups(self, filter, db: Optional[Session] = None) -> list[GroupResponse]: + with get_db_context(db) as db: query = db.query(Group) if filter: @@ -184,16 +185,16 @@ class GroupTable: GroupResponse.model_validate( { **GroupModel.model_validate(group).model_dump(), - "member_count": self.get_group_member_count_by_id(group.id), + "member_count": self.get_group_member_count_by_id(group.id, db=db), } ) for group in groups ] def search_groups( - self, filter: Optional[dict] = None, skip: int = 0, limit: int = 30 + self, filter: Optional[dict] = None, skip: int = 0, limit: int = 30, db: Optional[Session] = None ) -> GroupListResponse: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Group) if filter: @@ -220,15 +221,15 @@ class GroupTable: "items": [ GroupResponse.model_validate( **GroupModel.model_validate(group).model_dump(), - member_count=self.get_group_member_count_by_id(group.id), + member_count=self.get_group_member_count_by_id(group.id, db=db), ) for group in groups ], "total": total, } - def get_groups_by_member_id(self, user_id: str) -> list[GroupModel]: - with get_db() as db: + def get_groups_by_member_id(self, user_id: str, db: Optional[Session] = None) -> list[GroupModel]: + with get_db_context(db) as db: return [ GroupModel.model_validate(group) for group in db.query(Group) @@ -238,16 +239,16 @@ class GroupTable: .all() ] - def get_group_by_id(self, id: str) -> Optional[GroupModel]: + def get_group_by_id(self, id: str, db: Optional[Session] = None) -> Optional[GroupModel]: try: - with get_db() as db: + with get_db_context(db) as db: group = db.query(Group).filter_by(id=id).first() return GroupModel.model_validate(group) if group else None except Exception: return None - def get_group_user_ids_by_id(self, id: str) -> Optional[list[str]]: - with get_db() as db: + def get_group_user_ids_by_id(self, id: str, db: Optional[Session] = None) -> Optional[list[str]]: + with get_db_context(db) as db: members = ( db.query(GroupMember.user_id).filter(GroupMember.group_id == id).all() ) @@ -257,8 +258,8 @@ class GroupTable: return [m[0] for m in members] - def get_group_user_ids_by_ids(self, group_ids: list[str]) -> dict[str, list[str]]: - with get_db() as db: + def get_group_user_ids_by_ids(self, group_ids: list[str], db: Optional[Session] = None) -> dict[str, list[str]]: + with get_db_context(db) as db: members = ( db.query(GroupMember.group_id, GroupMember.user_id) .filter(GroupMember.group_id.in_(group_ids)) @@ -274,8 +275,8 @@ class GroupTable: return group_user_ids - def set_group_user_ids_by_id(self, group_id: str, user_ids: list[str]) -> None: - with get_db() as db: + def set_group_user_ids_by_id(self, group_id: str, user_ids: list[str], db: Optional[Session] = None) -> None: + with get_db_context(db) as db: # Delete existing members db.query(GroupMember).filter(GroupMember.group_id == group_id).delete() @@ -295,8 +296,8 @@ class GroupTable: db.add_all(new_members) db.commit() - def get_group_member_count_by_id(self, id: str) -> int: - with get_db() as db: + def get_group_member_count_by_id(self, id: str, db: Optional[Session] = None) -> int: + with get_db_context(db) as db: count = ( db.query(func.count(GroupMember.user_id)) .filter(GroupMember.group_id == id) @@ -305,10 +306,10 @@ class GroupTable: return count if count else 0 def update_group_by_id( - self, id: str, form_data: GroupUpdateForm, overwrite: bool = False + self, id: str, form_data: GroupUpdateForm, overwrite: bool = False, db: Optional[Session] = None ) -> Optional[GroupModel]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Group).filter_by(id=id).update( { **form_data.model_dump(exclude_none=True), @@ -316,22 +317,22 @@ class GroupTable: } ) db.commit() - return self.get_group_by_id(id=id) + return self.get_group_by_id(id=id, db=db) except Exception as e: log.exception(e) return None - def delete_group_by_id(self, id: str) -> bool: + def delete_group_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Group).filter_by(id=id).delete() db.commit() return True except Exception: return False - def delete_all_groups(self) -> bool: - with get_db() as db: + def delete_all_groups(self, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: db.query(Group).delete() db.commit() @@ -340,8 +341,8 @@ class GroupTable: except Exception: return False - def remove_user_from_all_groups(self, user_id: str) -> bool: - with get_db() as db: + def remove_user_from_all_groups(self, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: # Find all groups the user belongs to groups = ( @@ -369,16 +370,16 @@ class GroupTable: return False def create_groups_by_group_names( - self, user_id: str, group_names: list[str] + self, user_id: str, group_names: list[str], db: Optional[Session] = None ) -> list[GroupModel]: # check for existing groups - existing_groups = self.get_all_groups() + existing_groups = self.get_all_groups(db=db) existing_group_names = {group.name for group in existing_groups} new_groups = [] - with get_db() as db: + with get_db_context(db) as db: for group_name in group_names: if group_name not in existing_group_names: new_group = GroupModel( @@ -400,8 +401,8 @@ class GroupTable: continue return new_groups - def sync_groups_by_group_names(self, user_id: str, group_names: list[str]) -> bool: - with get_db() as db: + def sync_groups_by_group_names(self, user_id: str, group_names: list[str], db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: now = int(time.time()) @@ -461,10 +462,10 @@ class GroupTable: return False def add_users_to_group( - self, id: str, user_ids: Optional[list[str]] = None + self, id: str, user_ids: Optional[list[str]] = None, db: Optional[Session] = None ) -> Optional[GroupModel]: try: - with get_db() as db: + with get_db_context(db) as db: group = db.query(Group).filter_by(id=id).first() if not group: return None @@ -499,10 +500,10 @@ class GroupTable: return None def remove_users_from_group( - self, id: str, user_ids: Optional[list[str]] = None + self, id: str, user_ids: Optional[list[str]] = None, db: Optional[Session] = None ) -> Optional[GroupModel]: try: - with get_db() as db: + with get_db_context(db) as db: group = db.query(Group).filter_by(id=id).first() if not group: return None diff --git a/backend/open_webui/models/knowledge.py b/backend/open_webui/models/knowledge.py index d8af004338..348f0de64b 100644 --- a/backend/open_webui/models/knowledge.py +++ b/backend/open_webui/models/knowledge.py @@ -1,10 +1,12 @@ + import json import logging import time from typing import Optional import uuid -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.files import ( File, @@ -157,9 +159,9 @@ class KnowledgeFileListResponse(BaseModel): class KnowledgeTable: def insert_new_knowledge( - self, user_id: str, form_data: KnowledgeForm + self, user_id: str, form_data: KnowledgeForm, db: Optional[Session] = None ) -> Optional[KnowledgeModel]: - with get_db() as db: + with get_db_context(db) as db: knowledge = KnowledgeModel( **{ **form_data.model_dump(), @@ -183,15 +185,15 @@ class KnowledgeTable: return None def get_knowledge_bases( - self, skip: int = 0, limit: int = 30 + self, skip: int = 0, limit: int = 30, db: Optional[Session] = None ) -> list[KnowledgeUserModel]: - with get_db() as db: + with get_db_context(db) as db: all_knowledge = ( db.query(Knowledge).order_by(Knowledge.updated_at.desc()).all() ) user_ids = list(set(knowledge.user_id for knowledge in all_knowledge)) - users = Users.get_users_by_user_ids(user_ids) if user_ids else [] + users = Users.get_users_by_user_ids(user_ids, db=db) if user_ids else [] users_dict = {user.id: user for user in users} knowledge_bases = [] @@ -208,10 +210,10 @@ class KnowledgeTable: return knowledge_bases def search_knowledge_bases( - self, user_id: str, filter: dict, skip: int = 0, limit: int = 30 + self, user_id: str, filter: dict, skip: int = 0, limit: int = 30, db: Optional[Session] = None ) -> KnowledgeListResponse: try: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Knowledge, User).outerjoin( User, User.id == Knowledge.user_id ) @@ -267,14 +269,14 @@ class KnowledgeTable: return KnowledgeListResponse(items=[], total=0) def search_knowledge_files( - self, filter: dict, skip: int = 0, limit: int = 30 + self, filter: dict, skip: int = 0, limit: int = 30, db: Optional[Session] = None ) -> KnowledgeFileListResponse: """ Scalable version: search files across all knowledge bases the user has READ access to, without loading all KBs or using large IN() lists. """ try: - with get_db() as db: + with get_db_context(db) as db: # Base query: join Knowledge → KnowledgeFile → File query = ( db.query(File, User) @@ -327,20 +329,20 @@ class KnowledgeTable: print("search_knowledge_files error:", e) return KnowledgeFileListResponse(items=[], total=0) - def check_access_by_user_id(self, id, user_id, permission="write") -> bool: - knowledge = self.get_knowledge_by_id(id) + def check_access_by_user_id(self, id, user_id, permission="write", db: Optional[Session] = None) -> bool: + knowledge = self.get_knowledge_by_id(id, db=db) if not knowledge: return False if knowledge.user_id == user_id: return True - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)} + user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} return has_access(user_id, permission, knowledge.access_control, user_group_ids) def get_knowledge_bases_by_user_id( - self, user_id: str, permission: str = "write" + self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[KnowledgeUserModel]: - knowledge_bases = self.get_knowledge_bases() - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)} + knowledge_bases = self.get_knowledge_bases(db=db) + user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} return [ knowledge_base for knowledge_base in knowledge_bases @@ -350,32 +352,32 @@ class KnowledgeTable: ) ] - def get_knowledge_by_id(self, id: str) -> Optional[KnowledgeModel]: + def get_knowledge_by_id(self, id: str, db: Optional[Session] = None) -> Optional[KnowledgeModel]: try: - with get_db() as db: + with get_db_context(db) as db: knowledge = db.query(Knowledge).filter_by(id=id).first() return KnowledgeModel.model_validate(knowledge) if knowledge else None except Exception: return None def get_knowledge_by_id_and_user_id( - self, id: str, user_id: str + self, id: str, user_id: str, db: Optional[Session] = None ) -> Optional[KnowledgeModel]: - knowledge = self.get_knowledge_by_id(id) + knowledge = self.get_knowledge_by_id(id, db=db) if not knowledge: return None if knowledge.user_id == user_id: return knowledge - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)} + user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} if has_access(user_id, "write", knowledge.access_control, user_group_ids): return knowledge return None - def get_knowledges_by_file_id(self, file_id: str) -> list[KnowledgeModel]: + def get_knowledges_by_file_id(self, file_id: str, db: Optional[Session] = None) -> list[KnowledgeModel]: try: - with get_db() as db: + with get_db_context(db) as db: knowledges = ( db.query(Knowledge) .join(KnowledgeFile, Knowledge.id == KnowledgeFile.knowledge_id) @@ -395,9 +397,10 @@ class KnowledgeTable: filter: dict, skip: int = 0, limit: int = 30, + db: Optional[Session] = None, ) -> KnowledgeFileListResponse: try: - with get_db() as db: + with get_db_context(db) as db: query = ( db.query(File, User) .join(KnowledgeFile, File.id == KnowledgeFile.file_id) @@ -470,9 +473,9 @@ class KnowledgeTable: print(e) return KnowledgeFileListResponse(items=[], total=0) - def get_files_by_id(self, knowledge_id: str) -> list[FileModel]: + def get_files_by_id(self, knowledge_id: str, db: Optional[Session] = None) -> list[FileModel]: try: - with get_db() as db: + with get_db_context(db) as db: files = ( db.query(File) .join(KnowledgeFile, File.id == KnowledgeFile.file_id) @@ -483,18 +486,18 @@ class KnowledgeTable: except Exception: return [] - def get_file_metadatas_by_id(self, knowledge_id: str) -> list[FileMetadataResponse]: + def get_file_metadatas_by_id(self, knowledge_id: str, db: Optional[Session] = None) -> list[FileMetadataResponse]: try: - with get_db() as db: - files = self.get_files_by_id(knowledge_id) + with get_db_context(db) as db: + files = self.get_files_by_id(knowledge_id, db=db) return [FileMetadataResponse(**file.model_dump()) for file in files] except Exception: return [] def add_file_to_knowledge_by_id( - self, knowledge_id: str, file_id: str, user_id: str + self, knowledge_id: str, file_id: str, user_id: str, db: Optional[Session] = None ) -> Optional[KnowledgeFileModel]: - with get_db() as db: + with get_db_context(db) as db: knowledge_file = KnowledgeFileModel( **{ "id": str(uuid.uuid4()), @@ -518,9 +521,9 @@ class KnowledgeTable: except Exception: return None - def remove_file_from_knowledge_by_id(self, knowledge_id: str, file_id: str) -> bool: + def remove_file_from_knowledge_by_id(self, knowledge_id: str, file_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(KnowledgeFile).filter_by( knowledge_id=knowledge_id, file_id=file_id ).delete() @@ -529,9 +532,9 @@ class KnowledgeTable: except Exception: return False - def reset_knowledge_by_id(self, id: str) -> Optional[KnowledgeModel]: + def reset_knowledge_by_id(self, id: str, db: Optional[Session] = None) -> Optional[KnowledgeModel]: try: - with get_db() as db: + with get_db_context(db) as db: # Delete all knowledge_file entries for this knowledge_id db.query(KnowledgeFile).filter_by(knowledge_id=id).delete() db.commit() @@ -544,17 +547,17 @@ class KnowledgeTable: ) db.commit() - return self.get_knowledge_by_id(id=id) + return self.get_knowledge_by_id(id=id, db=db) except Exception as e: log.exception(e) return None def update_knowledge_by_id( - self, id: str, form_data: KnowledgeForm, overwrite: bool = False + self, id: str, form_data: KnowledgeForm, overwrite: bool = False, db: Optional[Session] = None ) -> Optional[KnowledgeModel]: try: - with get_db() as db: - knowledge = self.get_knowledge_by_id(id=id) + with get_db_context(db) as db: + knowledge = self.get_knowledge_by_id(id=id, db=db) db.query(Knowledge).filter_by(id=id).update( { **form_data.model_dump(), @@ -562,17 +565,17 @@ class KnowledgeTable: } ) db.commit() - return self.get_knowledge_by_id(id=id) + return self.get_knowledge_by_id(id=id, db=db) except Exception as e: log.exception(e) return None def update_knowledge_data_by_id( - self, id: str, data: dict + self, id: str, data: dict, db: Optional[Session] = None ) -> Optional[KnowledgeModel]: try: - with get_db() as db: - knowledge = self.get_knowledge_by_id(id=id) + with get_db_context(db) as db: + knowledge = self.get_knowledge_by_id(id=id, db=db) db.query(Knowledge).filter_by(id=id).update( { "data": data, @@ -580,22 +583,22 @@ class KnowledgeTable: } ) db.commit() - return self.get_knowledge_by_id(id=id) + return self.get_knowledge_by_id(id=id, db=db) except Exception as e: log.exception(e) return None - def delete_knowledge_by_id(self, id: str) -> bool: + def delete_knowledge_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Knowledge).filter_by(id=id).delete() db.commit() return True except Exception: return False - def delete_all_knowledge(self) -> bool: - with get_db() as db: + def delete_all_knowledge(self, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: db.query(Knowledge).delete() db.commit() diff --git a/backend/open_webui/models/memories.py b/backend/open_webui/models/memories.py index f5f2492b99..c0faed2c62 100644 --- a/backend/open_webui/models/memories.py +++ b/backend/open_webui/models/memories.py @@ -2,7 +2,8 @@ import time import uuid from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, get_db, get_db_context from pydantic import BaseModel, ConfigDict from sqlalchemy import BigInteger, Column, String, Text @@ -41,8 +42,9 @@ class MemoriesTable: self, user_id: str, content: str, + db: Optional[Session] = None, ) -> Optional[MemoryModel]: - with get_db() as db: + with get_db_context(db) as db: id = str(uuid.uuid4()) memory = MemoryModel( @@ -68,8 +70,9 @@ class MemoriesTable: id: str, user_id: str, content: str, + db: Optional[Session] = None, ) -> Optional[MemoryModel]: - with get_db() as db: + with get_db_context(db) as db: try: memory = db.get(Memory, id) if not memory or memory.user_id != user_id: @@ -83,32 +86,32 @@ class MemoriesTable: except Exception: return None - def get_memories(self) -> list[MemoryModel]: - with get_db() as db: + def get_memories(self, db: Optional[Session] = None) -> list[MemoryModel]: + with get_db_context(db) as db: try: memories = db.query(Memory).all() return [MemoryModel.model_validate(memory) for memory in memories] except Exception: return None - def get_memories_by_user_id(self, user_id: str) -> list[MemoryModel]: - with get_db() as db: + def get_memories_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[MemoryModel]: + with get_db_context(db) as db: try: memories = db.query(Memory).filter_by(user_id=user_id).all() return [MemoryModel.model_validate(memory) for memory in memories] except Exception: return None - def get_memory_by_id(self, id: str) -> Optional[MemoryModel]: - with get_db() as db: + def get_memory_by_id(self, id: str, db: Optional[Session] = None) -> Optional[MemoryModel]: + with get_db_context(db) as db: try: memory = db.get(Memory, id) return MemoryModel.model_validate(memory) except Exception: return None - def delete_memory_by_id(self, id: str) -> bool: - with get_db() as db: + def delete_memory_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: db.query(Memory).filter_by(id=id).delete() db.commit() @@ -118,8 +121,8 @@ class MemoriesTable: except Exception: return False - def delete_memories_by_user_id(self, user_id: str) -> bool: - with get_db() as db: + def delete_memories_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: db.query(Memory).filter_by(user_id=user_id).delete() db.commit() @@ -128,8 +131,8 @@ class MemoriesTable: except Exception: return False - def delete_memory_by_id_and_user_id(self, id: str, user_id: str) -> bool: - with get_db() as db: + def delete_memory_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: try: memory = db.get(Memory, id) if not memory or memory.user_id != user_id: diff --git a/backend/open_webui/models/messages.py b/backend/open_webui/models/messages.py index 5b068b6449..8fe37e58ea 100644 --- a/backend/open_webui/models/messages.py +++ b/backend/open_webui/models/messages.py @@ -3,7 +3,8 @@ import time import uuid from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.tags import TagModel, Tag, Tags from open_webui.models.users import Users, User, UserNameResponse from open_webui.models.channels import Channels, ChannelMember @@ -137,9 +138,9 @@ class MessageResponse(MessageReplyToResponse): class MessageTable: def insert_new_message( - self, form_data: MessageForm, channel_id: str, user_id: str + self, form_data: MessageForm, channel_id: str, user_id: str, db: Optional[Session] = None ) -> Optional[MessageModel]: - with get_db() as db: + with get_db_context(db) as db: channel_member = Channels.join_channel(channel_id, user_id) id = str(uuid.uuid4()) @@ -169,22 +170,22 @@ class MessageTable: db.refresh(result) return MessageModel.model_validate(result) if result else None - def get_message_by_id(self, id: str) -> Optional[MessageResponse]: - with get_db() as db: + def get_message_by_id(self, id: str, db: Optional[Session] = None) -> Optional[MessageResponse]: + with get_db_context(db) as db: message = db.get(Message, id) if not message: return None reply_to_message = ( - self.get_message_by_id(message.reply_to_id) + self.get_message_by_id(message.reply_to_id, db=db) if message.reply_to_id else None ) - reactions = self.get_reactions_by_message_id(id) - thread_replies = self.get_thread_replies_by_message_id(id) + reactions = self.get_reactions_by_message_id(id, db=db) + thread_replies = self.get_thread_replies_by_message_id(id, db=db) - user = Users.get_user_by_id(message.user_id) + user = Users.get_user_by_id(message.user_id, db=db) return MessageResponse.model_validate( { **MessageModel.model_validate(message).model_dump(), @@ -200,8 +201,8 @@ class MessageTable: } ) - def get_thread_replies_by_message_id(self, id: str) -> list[MessageReplyToResponse]: - with get_db() as db: + def get_thread_replies_by_message_id(self, id: str, db: Optional[Session] = None) -> list[MessageReplyToResponse]: + with get_db_context(db) as db: all_messages = ( db.query(Message) .filter_by(parent_id=id) @@ -212,7 +213,7 @@ class MessageTable: messages = [] for message in all_messages: reply_to_message = ( - self.get_message_by_id(message.reply_to_id) + self.get_message_by_id(message.reply_to_id, db=db) if message.reply_to_id else None ) @@ -230,17 +231,17 @@ class MessageTable: ) return messages - def get_reply_user_ids_by_message_id(self, id: str) -> list[str]: - with get_db() as db: + def get_reply_user_ids_by_message_id(self, id: str, db: Optional[Session] = None) -> list[str]: + with get_db_context(db) as db: return [ message.user_id for message in db.query(Message).filter_by(parent_id=id).all() ] def get_messages_by_channel_id( - self, channel_id: str, skip: int = 0, limit: int = 50 + self, channel_id: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None ) -> list[MessageReplyToResponse]: - with get_db() as db: + with get_db_context(db) as db: all_messages = ( db.query(Message) .filter_by(channel_id=channel_id, parent_id=None) @@ -253,7 +254,7 @@ class MessageTable: messages = [] for message in all_messages: reply_to_message = ( - self.get_message_by_id(message.reply_to_id) + self.get_message_by_id(message.reply_to_id, db=db) if message.reply_to_id else None ) @@ -272,9 +273,9 @@ class MessageTable: return messages def get_messages_by_parent_id( - self, channel_id: str, parent_id: str, skip: int = 0, limit: int = 50 + self, channel_id: str, parent_id: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None ) -> list[MessageReplyToResponse]: - with get_db() as db: + with get_db_context(db) as db: message = db.get(Message, parent_id) if not message: @@ -296,7 +297,7 @@ class MessageTable: messages = [] for message in all_messages: reply_to_message = ( - self.get_message_by_id(message.reply_to_id) + self.get_message_by_id(message.reply_to_id, db=db) if message.reply_to_id else None ) @@ -314,8 +315,8 @@ class MessageTable: ) return messages - def get_last_message_by_channel_id(self, channel_id: str) -> Optional[MessageModel]: - with get_db() as db: + def get_last_message_by_channel_id(self, channel_id: str, db: Optional[Session] = None) -> Optional[MessageModel]: + with get_db_context(db) as db: message = ( db.query(Message) .filter_by(channel_id=channel_id) @@ -325,9 +326,9 @@ class MessageTable: return MessageModel.model_validate(message) if message else None def get_pinned_messages_by_channel_id( - self, channel_id: str, skip: int = 0, limit: int = 50 + self, channel_id: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None ) -> list[MessageModel]: - with get_db() as db: + with get_db_context(db) as db: all_messages = ( db.query(Message) .filter_by(channel_id=channel_id, is_pinned=True) @@ -339,9 +340,9 @@ class MessageTable: return [MessageModel.model_validate(message) for message in all_messages] def update_message_by_id( - self, id: str, form_data: MessageForm + self, id: str, form_data: MessageForm, db: Optional[Session] = None ) -> Optional[MessageModel]: - with get_db() as db: + with get_db_context(db) as db: message = db.get(Message, id) message.content = form_data.content message.data = { @@ -358,9 +359,9 @@ class MessageTable: return MessageModel.model_validate(message) if message else None def update_is_pinned_by_id( - self, id: str, is_pinned: bool, pinned_by: Optional[str] = None + self, id: str, is_pinned: bool, pinned_by: Optional[str] = None, db: Optional[Session] = None ) -> Optional[MessageModel]: - with get_db() as db: + with get_db_context(db) as db: message = db.get(Message, id) message.is_pinned = is_pinned message.pinned_at = int(time.time_ns()) if is_pinned else None @@ -370,9 +371,9 @@ class MessageTable: return MessageModel.model_validate(message) if message else None def get_unread_message_count( - self, channel_id: str, user_id: str, last_read_at: Optional[int] = None + self, channel_id: str, user_id: str, last_read_at: Optional[int] = None, db: Optional[Session] = None ) -> int: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Message).filter( Message.channel_id == channel_id, Message.parent_id == None, # only count top-level messages @@ -383,9 +384,9 @@ class MessageTable: return query.count() def add_reaction_to_message( - self, id: str, user_id: str, name: str + self, id: str, user_id: str, name: str, db: Optional[Session] = None ) -> Optional[MessageReactionModel]: - with get_db() as db: + with get_db_context(db) as db: # check for existing reaction existing_reaction = ( db.query(MessageReaction) @@ -409,8 +410,8 @@ class MessageTable: db.refresh(result) return MessageReactionModel.model_validate(result) if result else None - def get_reactions_by_message_id(self, id: str) -> list[Reactions]: - with get_db() as db: + def get_reactions_by_message_id(self, id: str, db: Optional[Session] = None) -> list[Reactions]: + with get_db_context(db) as db: # JOIN User so all user info is fetched in one query results = ( db.query(MessageReaction, User) @@ -440,29 +441,29 @@ class MessageTable: return [Reactions(**reaction) for reaction in reactions.values()] def remove_reaction_by_id_and_user_id_and_name( - self, id: str, user_id: str, name: str + self, id: str, user_id: str, name: str, db: Optional[Session] = None ) -> bool: - with get_db() as db: + with get_db_context(db) as db: db.query(MessageReaction).filter_by( message_id=id, user_id=user_id, name=name ).delete() db.commit() return True - def delete_reactions_by_id(self, id: str) -> bool: - with get_db() as db: + def delete_reactions_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: db.query(MessageReaction).filter_by(message_id=id).delete() db.commit() return True - def delete_replies_by_id(self, id: str) -> bool: - with get_db() as db: + def delete_replies_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: db.query(Message).filter_by(parent_id=id).delete() db.commit() return True - def delete_message_by_id(self, id: str) -> bool: - with get_db() as db: + def delete_message_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: db.query(Message).filter_by(id=id).delete() # Delete all reactions to this message diff --git a/backend/open_webui/models/models.py b/backend/open_webui/models/models.py index 08dcfe87a1..adb82755d5 100755 --- a/backend/open_webui/models/models.py +++ b/backend/open_webui/models/models.py @@ -2,7 +2,8 @@ import logging import time from typing import Optional -from open_webui.internal.db import Base, JSONField, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.groups import Groups from open_webui.models.users import User, UserModel, Users, UserResponse @@ -150,7 +151,7 @@ class ModelForm(BaseModel): class ModelsTable: def insert_new_model( - self, form_data: ModelForm, user_id: str + self, form_data: ModelForm, user_id: str, db: Optional[Session] = None ) -> Optional[ModelModel]: model = ModelModel( **{ @@ -161,7 +162,7 @@ class ModelsTable: } ) try: - with get_db() as db: + with get_db_context(db) as db: result = Model(**model.model_dump()) db.add(result) db.commit() @@ -175,17 +176,17 @@ class ModelsTable: log.exception(f"Failed to insert a new model: {e}") return None - def get_all_models(self) -> list[ModelModel]: - with get_db() as db: + def get_all_models(self, db: Optional[Session] = None) -> list[ModelModel]: + with get_db_context(db) as db: return [ModelModel.model_validate(model) for model in db.query(Model).all()] - def get_models(self) -> list[ModelUserResponse]: - with get_db() as db: + def get_models(self, db: Optional[Session] = None) -> list[ModelUserResponse]: + with get_db_context(db) as db: all_models = db.query(Model).filter(Model.base_model_id != None).all() user_ids = list(set(model.user_id for model in all_models)) - users = Users.get_users_by_user_ids(user_ids) if user_ids else [] + users = Users.get_users_by_user_ids(user_ids, db=db) if user_ids else [] users_dict = {user.id: user for user in users} models = [] @@ -201,18 +202,18 @@ class ModelsTable: ) return models - def get_base_models(self) -> list[ModelModel]: - with get_db() as db: + def get_base_models(self, db: Optional[Session] = None) -> list[ModelModel]: + with get_db_context(db) as db: return [ ModelModel.model_validate(model) for model in db.query(Model).filter(Model.base_model_id == None).all() ] def get_models_by_user_id( - self, user_id: str, permission: str = "write" + self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[ModelUserResponse]: - models = self.get_models() - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)} + models = self.get_models(db=db) + user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} return [ model for model in models @@ -263,9 +264,9 @@ class ModelsTable: return query def search_models( - self, user_id: str, filter: dict = {}, skip: int = 0, limit: int = 30 + self, user_id: str, filter: dict = {}, skip: int = 0, limit: int = 30, db: Optional[Session] = None ) -> ModelListResponse: - with get_db() as db: + with get_db_context(db) as db: # Join GroupMember so we can order by group_id when requested query = db.query(Model, User).outerjoin(User, User.id == Model.user_id) query = query.filter(Model.base_model_id != None) @@ -349,24 +350,24 @@ class ModelsTable: return ModelListResponse(items=models, total=total) - def get_model_by_id(self, id: str) -> Optional[ModelModel]: + def get_model_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ModelModel]: try: - with get_db() as db: + with get_db_context(db) as db: model = db.get(Model, id) return ModelModel.model_validate(model) except Exception: return None - def get_models_by_ids(self, ids: list[str]) -> list[ModelModel]: + def get_models_by_ids(self, ids: list[str], db: Optional[Session] = None) -> list[ModelModel]: try: - with get_db() as db: + with get_db_context(db) as db: models = db.query(Model).filter(Model.id.in_(ids)).all() return [ModelModel.model_validate(model) for model in models] except Exception: return [] - def toggle_model_by_id(self, id: str) -> Optional[ModelModel]: - with get_db() as db: + def toggle_model_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ModelModel]: + with get_db_context(db) as db: try: is_active = db.query(Model).filter_by(id=id).first().is_active @@ -378,13 +379,13 @@ class ModelsTable: ) db.commit() - return self.get_model_by_id(id) + return self.get_model_by_id(id, db=db) except Exception: return None - def update_model_by_id(self, id: str, model: ModelForm) -> Optional[ModelModel]: + def update_model_by_id(self, id: str, model: ModelForm, db: Optional[Session] = None) -> Optional[ModelModel]: try: - with get_db() as db: + with get_db_context(db) as db: # update only the fields that are present in the model data = model.model_dump(exclude={"id"}) result = db.query(Model).filter_by(id=id).update(data) @@ -398,9 +399,9 @@ class ModelsTable: log.exception(f"Failed to update the model by id {id}: {e}") return None - def delete_model_by_id(self, id: str) -> bool: + def delete_model_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Model).filter_by(id=id).delete() db.commit() @@ -408,9 +409,9 @@ class ModelsTable: except Exception: return False - def delete_all_models(self) -> bool: + def delete_all_models(self, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Model).delete() db.commit() @@ -418,9 +419,9 @@ class ModelsTable: except Exception: return False - def sync_models(self, user_id: str, models: list[ModelModel]) -> list[ModelModel]: + def sync_models(self, user_id: str, models: list[ModelModel], db: Optional[Session] = None) -> list[ModelModel]: try: - with get_db() as db: + with get_db_context(db) as db: # Get existing models existing_models = db.query(Model).all() existing_ids = {model.id for model in existing_models} diff --git a/backend/open_webui/models/notes.py b/backend/open_webui/models/notes.py index cfeddf4a8c..fef9db7bf4 100644 --- a/backend/open_webui/models/notes.py +++ b/backend/open_webui/models/notes.py @@ -4,7 +4,8 @@ import uuid from typing import Optional from functools import lru_cache -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, get_db, get_db_context from open_webui.models.groups import Groups from open_webui.utils.access_control import has_access from open_webui.models.users import User, UserModel, Users, UserResponse @@ -211,11 +212,9 @@ class NoteTable: return query def insert_new_note( - self, - form_data: NoteForm, - user_id: str, + self, user_id: str, form_data: NoteForm, db: Optional[Session] = None ) -> Optional[NoteModel]: - with get_db() as db: + with get_db_context(db) as db: note = NoteModel( **{ "id": str(uuid.uuid4()), @@ -233,9 +232,9 @@ class NoteTable: return note def get_notes( - self, skip: Optional[int] = None, limit: Optional[int] = None + self, skip: int = 0, limit: int = 50, db: Optional[Session] = None ) -> list[NoteModel]: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Note).order_by(Note.updated_at.desc()) if skip is not None: query = query.offset(skip) @@ -333,10 +332,11 @@ class NoteTable: self, user_id: str, permission: str = "read", - skip: Optional[int] = None, - limit: Optional[int] = None, + skip: int = 0, + limit: int = 50, + db: Optional[Session] = None, ) -> list[NoteModel]: - with get_db() as db: + with get_db_context(db) as db: user_group_ids = [ group.id for group in Groups.get_groups_by_member_id(user_id) ] @@ -354,15 +354,17 @@ class NoteTable: notes = query.all() return [NoteModel.model_validate(note) for note in notes] - def get_note_by_id(self, id: str) -> Optional[NoteModel]: - with get_db() as db: + def get_note_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[NoteModel]: + with get_db_context(db) as db: note = db.query(Note).filter(Note.id == id).first() return NoteModel.model_validate(note) if note else None def update_note_by_id( - self, id: str, form_data: NoteUpdateForm + self, id: str, form_data: NoteUpdateForm, db: Optional[Session] = None ) -> Optional[NoteModel]: - with get_db() as db: + with get_db_context(db) as db: note = db.query(Note).filter(Note.id == id).first() if not note: return None @@ -384,11 +386,14 @@ class NoteTable: db.commit() return NoteModel.model_validate(note) if note else None - def delete_note_by_id(self, id: str): - with get_db() as db: - db.query(Note).filter(Note.id == id).delete() - db.commit() - return True + def delete_note_by_id(self, id: str, db: Optional[Session] = None) -> bool: + try: + with get_db_context(db) as db: + db.query(Note).filter(Note.id == id).delete() + db.commit() + return True + except Exception: + return False Notes = NoteTable() diff --git a/backend/open_webui/models/oauth_sessions.py b/backend/open_webui/models/oauth_sessions.py index 8b0334ed19..4221987faa 100644 --- a/backend/open_webui/models/oauth_sessions.py +++ b/backend/open_webui/models/oauth_sessions.py @@ -8,7 +8,8 @@ import json from cryptography.fernet import Fernet -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, get_db, get_db_context from open_webui.env import OAUTH_SESSION_TOKEN_ENCRYPTION_KEY from pydantic import BaseModel, ConfigDict @@ -109,10 +110,11 @@ class OAuthSessionTable: user_id: str, provider: str, token: dict, + db: Optional[Session] = None, ) -> Optional[OAuthSessionModel]: """Create a new OAuth session""" try: - with get_db() as db: + with get_db_context(db) as db: current_time = int(time.time()) id = str(uuid.uuid4()) @@ -141,10 +143,10 @@ class OAuthSessionTable: log.error(f"Error creating OAuth session: {e}") return None - def get_session_by_id(self, session_id: str) -> Optional[OAuthSessionModel]: + def get_session_by_id(self, session_id: str, db: Optional[Session] = None) -> Optional[OAuthSessionModel]: """Get OAuth session by ID""" try: - with get_db() as db: + with get_db_context(db) as db: session = db.query(OAuthSession).filter_by(id=session_id).first() if session: session.token = self._decrypt_token(session.token) @@ -156,11 +158,11 @@ class OAuthSessionTable: return None def get_session_by_id_and_user_id( - self, session_id: str, user_id: str + self, session_id: str, user_id: str, db: Optional[Session] = None ) -> Optional[OAuthSessionModel]: """Get OAuth session by ID and user ID""" try: - with get_db() as db: + with get_db_context(db) as db: session = ( db.query(OAuthSession) .filter_by(id=session_id, user_id=user_id) @@ -176,11 +178,11 @@ class OAuthSessionTable: return None def get_session_by_provider_and_user_id( - self, provider: str, user_id: str + self, provider: str, user_id: str, db: Optional[Session] = None ) -> Optional[OAuthSessionModel]: """Get OAuth session by provider and user ID""" try: - with get_db() as db: + with get_db_context(db) as db: session = ( db.query(OAuthSession) .filter_by(provider=provider, user_id=user_id) @@ -195,10 +197,10 @@ class OAuthSessionTable: log.error(f"Error getting OAuth session by provider and user ID: {e}") return None - def get_sessions_by_user_id(self, user_id: str) -> List[OAuthSessionModel]: + def get_sessions_by_user_id(self, user_id: str, db: Optional[Session] = None) -> List[OAuthSessionModel]: """Get all OAuth sessions for a user""" try: - with get_db() as db: + with get_db_context(db) as db: sessions = db.query(OAuthSession).filter_by(user_id=user_id).all() results = [] @@ -213,11 +215,11 @@ class OAuthSessionTable: return [] def update_session_by_id( - self, session_id: str, token: dict + self, session_id: str, token: dict, db: Optional[Session] = None ) -> Optional[OAuthSessionModel]: """Update OAuth session tokens""" try: - with get_db() as db: + with get_db_context(db) as db: current_time = int(time.time()) db.query(OAuthSession).filter_by(id=session_id).update( @@ -239,10 +241,10 @@ class OAuthSessionTable: log.error(f"Error updating OAuth session tokens: {e}") return None - def delete_session_by_id(self, session_id: str) -> bool: + def delete_session_by_id(self, session_id: str, db: Optional[Session] = None) -> bool: """Delete an OAuth session""" try: - with get_db() as db: + with get_db_context(db) as db: result = db.query(OAuthSession).filter_by(id=session_id).delete() db.commit() return result > 0 @@ -250,10 +252,10 @@ class OAuthSessionTable: log.error(f"Error deleting OAuth session: {e}") return False - def delete_sessions_by_user_id(self, user_id: str) -> bool: + def delete_sessions_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: """Delete all OAuth sessions for a user""" try: - with get_db() as db: + with get_db_context(db) as db: result = db.query(OAuthSession).filter_by(user_id=user_id).delete() db.commit() return True @@ -261,10 +263,10 @@ class OAuthSessionTable: log.error(f"Error deleting OAuth sessions by user ID: {e}") return False - def delete_sessions_by_provider(self, provider: str) -> bool: + def delete_sessions_by_provider(self, provider: str, db: Optional[Session] = None) -> bool: """Delete all OAuth sessions for a provider""" try: - with get_db() as db: + with get_db_context(db) as db: db.query(OAuthSession).filter_by(provider=provider).delete() db.commit() return True diff --git a/backend/open_webui/models/prompts.py b/backend/open_webui/models/prompts.py index 7502f34ccd..eefb74de53 100644 --- a/backend/open_webui/models/prompts.py +++ b/backend/open_webui/models/prompts.py @@ -1,7 +1,9 @@ + import time from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.groups import Groups from open_webui.models.users import Users, UserResponse @@ -71,7 +73,7 @@ class PromptForm(BaseModel): class PromptsTable: def insert_new_prompt( - self, user_id: str, form_data: PromptForm + self, user_id: str, form_data: PromptForm, db: Optional[Session] = None ) -> Optional[PromptModel]: prompt = PromptModel( **{ @@ -82,7 +84,7 @@ class PromptsTable: ) try: - with get_db() as db: + with get_db_context(db) as db: result = Prompt(**prompt.model_dump()) db.add(result) db.commit() @@ -94,21 +96,21 @@ class PromptsTable: except Exception: return None - def get_prompt_by_command(self, command: str) -> Optional[PromptModel]: + def get_prompt_by_command(self, command: str, db: Optional[Session] = None) -> Optional[PromptModel]: try: - with get_db() as db: + with get_db_context(db) as db: prompt = db.query(Prompt).filter_by(command=command).first() return PromptModel.model_validate(prompt) except Exception: return None - def get_prompts(self) -> list[PromptUserResponse]: - with get_db() as db: + def get_prompts(self, db: Optional[Session] = None) -> list[PromptUserResponse]: + with get_db_context(db) as db: all_prompts = db.query(Prompt).order_by(Prompt.timestamp.desc()).all() user_ids = list(set(prompt.user_id for prompt in all_prompts)) - users = Users.get_users_by_user_ids(user_ids) if user_ids else [] + users = Users.get_users_by_user_ids(user_ids, db=db) if user_ids else [] users_dict = {user.id: user for user in users} prompts = [] @@ -126,10 +128,10 @@ class PromptsTable: return prompts def get_prompts_by_user_id( - self, user_id: str, permission: str = "write" + self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[PromptUserResponse]: - prompts = self.get_prompts() - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)} + prompts = self.get_prompts(db=db) + user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} return [ prompt @@ -139,10 +141,10 @@ class PromptsTable: ] def update_prompt_by_command( - self, command: str, form_data: PromptForm + self, command: str, form_data: PromptForm, db: Optional[Session] = None ) -> Optional[PromptModel]: try: - with get_db() as db: + with get_db_context(db) as db: prompt = db.query(Prompt).filter_by(command=command).first() prompt.title = form_data.title prompt.content = form_data.content @@ -153,9 +155,9 @@ class PromptsTable: except Exception: return None - def delete_prompt_by_command(self, command: str) -> bool: + def delete_prompt_by_command(self, command: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Prompt).filter_by(command=command).delete() db.commit() diff --git a/backend/open_webui/models/tags.py b/backend/open_webui/models/tags.py index 499f3859dc..950c475ba3 100644 --- a/backend/open_webui/models/tags.py +++ b/backend/open_webui/models/tags.py @@ -3,7 +3,8 @@ import time import uuid from typing import Optional -from open_webui.internal.db import Base, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from pydantic import BaseModel, ConfigDict @@ -50,8 +51,8 @@ class TagChatIdForm(BaseModel): class TagTable: - def insert_new_tag(self, name: str, user_id: str) -> Optional[TagModel]: - with get_db() as db: + def insert_new_tag(self, name: str, user_id: str, db: Optional[Session] = None) -> Optional[TagModel]: + with get_db_context(db) as db: id = name.replace(" ", "_").lower() tag = TagModel(**{"id": id, "user_id": user_id, "name": name}) try: @@ -68,27 +69,27 @@ class TagTable: return None def get_tag_by_name_and_user_id( - self, name: str, user_id: str + self, name: str, user_id: str, db: Optional[Session] = None ) -> Optional[TagModel]: try: id = name.replace(" ", "_").lower() - with get_db() as db: + with get_db_context(db) as db: tag = db.query(Tag).filter_by(id=id, user_id=user_id).first() return TagModel.model_validate(tag) except Exception: return None - def get_tags_by_user_id(self, user_id: str) -> list[TagModel]: - with get_db() as db: + def get_tags_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[TagModel]: + with get_db_context(db) as db: return [ TagModel.model_validate(tag) for tag in (db.query(Tag).filter_by(user_id=user_id).all()) ] def get_tags_by_ids_and_user_id( - self, ids: list[str], user_id: str + self, ids: list[str], user_id: str, db: Optional[Session] = None ) -> list[TagModel]: - with get_db() as db: + with get_db_context(db) as db: return [ TagModel.model_validate(tag) for tag in ( @@ -96,9 +97,9 @@ class TagTable: ) ] - def delete_tag_by_name_and_user_id(self, name: str, user_id: str) -> bool: + def delete_tag_by_name_and_user_id(self, name: str, user_id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: id = name.replace(" ", "_").lower() res = db.query(Tag).filter_by(id=id, user_id=user_id).delete() log.debug(f"res: {res}") diff --git a/backend/open_webui/models/tools.py b/backend/open_webui/models/tools.py index fff53a7e94..cbd17cf5a7 100644 --- a/backend/open_webui/models/tools.py +++ b/backend/open_webui/models/tools.py @@ -2,7 +2,8 @@ import logging import time from typing import Optional -from open_webui.internal.db import Base, JSONField, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.models.users import Users, UserResponse from open_webui.models.groups import Groups @@ -110,9 +111,9 @@ class ToolValves(BaseModel): class ToolsTable: def insert_new_tool( - self, user_id: str, form_data: ToolForm, specs: list[dict] + self, user_id: str, form_data: ToolForm, specs: list[dict], db: Optional[Session] = None ) -> Optional[ToolModel]: - with get_db() as db: + with get_db_context(db) as db: tool = ToolModel( **{ **form_data.model_dump(), @@ -136,21 +137,21 @@ class ToolsTable: log.exception(f"Error creating a new tool: {e}") return None - def get_tool_by_id(self, id: str) -> Optional[ToolModel]: + def get_tool_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ToolModel]: try: - with get_db() as db: + with get_db_context(db) as db: tool = db.get(Tool, id) return ToolModel.model_validate(tool) except Exception: return None - def get_tools(self) -> list[ToolUserModel]: - with get_db() as db: + def get_tools(self, db: Optional[Session] = None) -> list[ToolUserModel]: + with get_db_context(db) as db: all_tools = db.query(Tool).order_by(Tool.updated_at.desc()).all() user_ids = list(set(tool.user_id for tool in all_tools)) - users = Users.get_users_by_user_ids(user_ids) if user_ids else [] + users = Users.get_users_by_user_ids(user_ids, db=db) if user_ids else [] users_dict = {user.id: user for user in users} tools = [] @@ -167,10 +168,10 @@ class ToolsTable: return tools def get_tools_by_user_id( - self, user_id: str, permission: str = "write" + self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[ToolUserModel]: - tools = self.get_tools() - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id)} + tools = self.get_tools(db=db) + user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} return [ tool @@ -179,31 +180,31 @@ class ToolsTable: or has_access(user_id, permission, tool.access_control, user_group_ids) ] - def get_tool_valves_by_id(self, id: str) -> Optional[dict]: + def get_tool_valves_by_id(self, id: str, db: Optional[Session] = None) -> Optional[dict]: try: - with get_db() as db: + with get_db_context(db) as db: tool = db.get(Tool, id) return tool.valves if tool.valves else {} except Exception as e: log.exception(f"Error getting tool valves by id {id}") return None - def update_tool_valves_by_id(self, id: str, valves: dict) -> Optional[ToolValves]: + def update_tool_valves_by_id(self, id: str, valves: dict, db: Optional[Session] = None) -> Optional[ToolValves]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Tool).filter_by(id=id).update( {"valves": valves, "updated_at": int(time.time())} ) db.commit() - return self.get_tool_by_id(id) + return self.get_tool_by_id(id, db=db) except Exception: return None def get_user_valves_by_id_and_user_id( - self, id: str, user_id: str + self, id: str, user_id: str, db: Optional[Session] = None ) -> Optional[dict]: try: - user = Users.get_user_by_id(user_id) + user = Users.get_user_by_id(user_id, db=db) user_settings = user.settings.model_dump() if user.settings else {} # Check if user has "tools" and "valves" settings @@ -220,10 +221,10 @@ class ToolsTable: return None def update_user_valves_by_id_and_user_id( - self, id: str, user_id: str, valves: dict + self, id: str, user_id: str, valves: dict, db: Optional[Session] = None ) -> Optional[dict]: try: - user = Users.get_user_by_id(user_id) + user = Users.get_user_by_id(user_id, db=db) user_settings = user.settings.model_dump() if user.settings else {} # Check if user has "tools" and "valves" settings @@ -235,7 +236,7 @@ class ToolsTable: user_settings["tools"]["valves"][id] = valves # Update the user settings in the database - Users.update_user_by_id(user_id, {"settings": user_settings}) + Users.update_user_by_id(user_id, {"settings": user_settings}, db=db) return user_settings["tools"]["valves"][id] except Exception as e: @@ -244,9 +245,9 @@ class ToolsTable: ) return None - def update_tool_by_id(self, id: str, updated: dict) -> Optional[ToolModel]: + def update_tool_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[ToolModel]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Tool).filter_by(id=id).update( {**updated, "updated_at": int(time.time())} ) @@ -258,9 +259,9 @@ class ToolsTable: except Exception: return None - def delete_tool_by_id(self, id: str) -> bool: + def delete_tool_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(Tool).filter_by(id=id).delete() db.commit() diff --git a/backend/open_webui/models/users.py b/backend/open_webui/models/users.py index 5807603a89..b48e7931ba 100644 --- a/backend/open_webui/models/users.py +++ b/backend/open_webui/models/users.py @@ -1,7 +1,8 @@ import time from typing import Optional -from open_webui.internal.db import Base, JSONField, get_db +from sqlalchemy.orm import Session +from open_webui.internal.db import Base, JSONField, get_db, get_db_context from open_webui.env import DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL @@ -243,8 +244,9 @@ class UsersTable: profile_image_url: str = "/user.png", role: str = "pending", oauth: Optional[dict] = None, + db: Optional[Session] = None, ) -> Optional[UserModel]: - with get_db() as db: + with get_db_context(db) as db: user = UserModel( **{ "id": id, @@ -267,17 +269,17 @@ class UsersTable: else: return None - def get_user_by_id(self, id: str) -> Optional[UserModel]: + def get_user_by_id(self, id: str, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: user = db.query(User).filter_by(id=id).first() return UserModel.model_validate(user) except Exception: return None - def get_user_by_api_key(self, api_key: str) -> Optional[UserModel]: + def get_user_by_api_key(self, api_key: str, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: user = ( db.query(User) .join(ApiKey, User.id == ApiKey.user_id) @@ -288,17 +290,17 @@ class UsersTable: except Exception: return None - def get_user_by_email(self, email: str) -> Optional[UserModel]: + def get_user_by_email(self, email: str, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: user = db.query(User).filter_by(email=email).first() return UserModel.model_validate(user) except Exception: return None - def get_user_by_oauth_sub(self, provider: str, sub: str) -> Optional[UserModel]: + def get_user_by_oauth_sub(self, provider: str, sub: str, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: # type: Session + with get_db_context(db) as db: # type: Session dialect_name = db.bind.dialect.name query = db.query(User) @@ -320,8 +322,9 @@ class UsersTable: filter: Optional[dict] = None, skip: Optional[int] = None, limit: Optional[int] = None, + db: Optional[Session] = None, ) -> dict: - with get_db() as db: + with get_db_context(db) as db: # Join GroupMember so we can order by group_id when requested query = db.query(User) @@ -452,8 +455,8 @@ class UsersTable: "total": total, } - def get_users_by_group_id(self, group_id: str) -> list[UserModel]: - with get_db() as db: + def get_users_by_group_id(self, group_id: str, db: Optional[Session] = None) -> list[UserModel]: + with get_db_context(db) as db: users = ( db.query(User) .join(GroupMember, User.id == GroupMember.user_id) @@ -462,30 +465,30 @@ class UsersTable: ) return [UserModel.model_validate(user) for user in users] - def get_users_by_user_ids(self, user_ids: list[str]) -> list[UserStatusModel]: - with get_db() as db: + def get_users_by_user_ids(self, user_ids: list[str], db: Optional[Session] = None) -> list[UserStatusModel]: + with get_db_context(db) as db: users = db.query(User).filter(User.id.in_(user_ids)).all() return [UserModel.model_validate(user) for user in users] - def get_num_users(self) -> Optional[int]: - with get_db() as db: + def get_num_users(self, db: Optional[Session] = None) -> Optional[int]: + with get_db_context(db) as db: return db.query(User).count() - def has_users(self) -> bool: - with get_db() as db: + def has_users(self, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: return db.query(db.query(User).exists()).scalar() - def get_first_user(self) -> UserModel: + def get_first_user(self, db: Optional[Session] = None) -> UserModel: try: - with get_db() as db: + with get_db_context(db) as db: user = db.query(User).order_by(User.created_at).first() return UserModel.model_validate(user) except Exception: return None - def get_user_webhook_url_by_id(self, id: str) -> Optional[str]: + def get_user_webhook_url_by_id(self, id: str, db: Optional[Session] = None) -> Optional[str]: try: - with get_db() as db: + with get_db_context(db) as db: user = db.query(User).filter_by(id=id).first() if user.settings is None: @@ -499,8 +502,8 @@ class UsersTable: except Exception: return None - def get_num_users_active_today(self) -> Optional[int]: - with get_db() as db: + def get_num_users_active_today(self, db: Optional[Session] = None) -> Optional[int]: + with get_db_context(db) as db: current_timestamp = int(datetime.datetime.now().timestamp()) today_midnight_timestamp = current_timestamp - (current_timestamp % 86400) query = db.query(User).filter( @@ -508,9 +511,9 @@ class UsersTable: ) return query.count() - def update_user_role_by_id(self, id: str, role: str) -> Optional[UserModel]: + def update_user_role_by_id(self, id: str, role: str, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(User).filter_by(id=id).update({"role": role}) db.commit() user = db.query(User).filter_by(id=id).first() @@ -519,10 +522,10 @@ class UsersTable: return None def update_user_status_by_id( - self, id: str, form_data: UserStatus + self, id: str, form_data: UserStatus, db: Optional[Session] = None ) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(User).filter_by(id=id).update( {**form_data.model_dump(exclude_none=True)} ) @@ -534,10 +537,10 @@ class UsersTable: return None def update_user_profile_image_url_by_id( - self, id: str, profile_image_url: str + self, id: str, profile_image_url: str, db: Optional[Session] = None ) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(User).filter_by(id=id).update( {"profile_image_url": profile_image_url} ) @@ -549,9 +552,9 @@ class UsersTable: return None @throttle(DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL) - def update_last_active_by_id(self, id: str) -> Optional[UserModel]: + def update_last_active_by_id(self, id: str, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(User).filter_by(id=id).update( {"last_active_at": int(time.time())} ) @@ -563,7 +566,7 @@ class UsersTable: return None def update_user_oauth_by_id( - self, id: str, provider: str, sub: str + self, id: str, provider: str, sub: str, db: Optional[Session] = None ) -> Optional[UserModel]: """ Update or insert an OAuth provider/sub pair into the user's oauth JSON field. @@ -574,7 +577,7 @@ class UsersTable: } """ try: - with get_db() as db: + with get_db_context(db) as db: user = db.query(User).filter_by(id=id).first() if not user: return None @@ -594,9 +597,9 @@ class UsersTable: except Exception: return None - def update_user_by_id(self, id: str, updated: dict) -> Optional[UserModel]: + def update_user_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: db.query(User).filter_by(id=id).update(updated) db.commit() @@ -607,9 +610,9 @@ class UsersTable: print(e) return None - def update_user_settings_by_id(self, id: str, updated: dict) -> Optional[UserModel]: + def update_user_settings_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[UserModel]: try: - with get_db() as db: + with get_db_context(db) as db: user_settings = db.query(User).filter_by(id=id).first().settings if user_settings is None: @@ -625,15 +628,15 @@ class UsersTable: except Exception: return None - def delete_user_by_id(self, id: str) -> bool: + def delete_user_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: # Remove User from Groups Groups.remove_user_from_all_groups(id) # Delete User Chats - result = Chats.delete_chats_by_user_id(id) + result = Chats.delete_chats_by_user_id(id, db=db) if result: - with get_db() as db: + with get_db_context(db) as db: # Delete User db.query(User).filter_by(id=id).delete() db.commit() @@ -644,17 +647,17 @@ class UsersTable: except Exception: return False - def get_user_api_key_by_id(self, id: str) -> Optional[str]: + def get_user_api_key_by_id(self, id: str, db: Optional[Session] = None) -> Optional[str]: try: - with get_db() as db: + with get_db_context(db) as db: api_key = db.query(ApiKey).filter_by(user_id=id).first() return api_key.key if api_key else None except Exception: return None - def update_user_api_key_by_id(self, id: str, api_key: str) -> bool: + def update_user_api_key_by_id(self, id: str, api_key: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(ApiKey).filter_by(user_id=id).delete() db.commit() @@ -674,30 +677,30 @@ class UsersTable: except Exception: return False - def delete_user_api_key_by_id(self, id: str) -> bool: + def delete_user_api_key_by_id(self, id: str, db: Optional[Session] = None) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(ApiKey).filter_by(user_id=id).delete() db.commit() return True except Exception: return False - def get_valid_user_ids(self, user_ids: list[str]) -> list[str]: - with get_db() as db: + def get_valid_user_ids(self, user_ids: list[str], db: Optional[Session] = None) -> list[str]: + with get_db_context(db) as db: users = db.query(User).filter(User.id.in_(user_ids)).all() return [user.id for user in users] - def get_super_admin_user(self) -> Optional[UserModel]: - with get_db() as db: + def get_super_admin_user(self, db: Optional[Session] = None) -> Optional[UserModel]: + with get_db_context(db) as db: user = db.query(User).filter_by(role="admin").first() if user: return UserModel.model_validate(user) else: return None - def get_active_user_count(self) -> int: - with get_db() as db: + def get_active_user_count(self, db: Optional[Session] = None) -> int: + with get_db_context(db) as db: # Consider user active if last_active_at within the last 3 minutes three_minutes_ago = int(time.time()) - 180 count = ( @@ -705,8 +708,8 @@ class UsersTable: ) return count - def is_user_active(self, user_id: str) -> bool: - with get_db() as db: + def is_user_active(self, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: user = db.query(User).filter_by(id=user_id).first() if user and user.last_active_at: # Consider user active if last_active_at within the last 3 minutes diff --git a/backend/open_webui/routers/notes.py b/backend/open_webui/routers/notes.py index ee0e46da29..853e7848cc 100644 --- a/backend/open_webui/routers/notes.py +++ b/backend/open_webui/routers/notes.py @@ -142,7 +142,7 @@ async def create_new_note( ) try: - note = Notes.insert_new_note(form_data, user.id) + note = Notes.insert_new_note(user.id, form_data) return note except Exception as e: log.exception(e) From 145c7516f227ce56fd52373cee86217fadf16181 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 28 Dec 2025 22:26:35 +0400 Subject: [PATCH 030/254] refac --- backend/open_webui/models/channels.py | 66 +++++++++++----------- backend/open_webui/models/files.py | 80 ++++++++++++++++++++------- 2 files changed, 94 insertions(+), 52 deletions(-) diff --git a/backend/open_webui/models/channels.py b/backend/open_webui/models/channels.py index 3aba302ff0..5f665146ae 100644 --- a/backend/open_webui/models/channels.py +++ b/backend/open_webui/models/channels.py @@ -306,9 +306,9 @@ class ChannelTable: return memberships def insert_new_channel( - self, form_data: CreateChannelForm, user_id: str + self, form_data: CreateChannelForm, user_id: str, db: Optional[Session] = None ) -> Optional[ChannelModel]: - with get_db() as db: + with get_db_context(db) as db: channel = ChannelModel( **{ **form_data.model_dump(), @@ -389,7 +389,7 @@ class ChannelTable: def get_channels_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[ChannelModel]: with get_db_context(db) as db: user_group_ids = [ - group.id for group in Groups.get_groups_by_member_id(user_id) + group.id for group in Groups.get_groups_by_member_id(user_id, db=db) ] membership_channels = ( @@ -423,8 +423,8 @@ class ChannelTable: all_channels = membership_channels + standard_channels return [ChannelModel.model_validate(c) for c in all_channels] - def get_dm_channel_by_user_ids(self, user_ids: list[str]) -> Optional[ChannelModel]: - with get_db() as db: + def get_dm_channel_by_user_ids(self, user_ids: list[str], db: Optional[Session] = None) -> Optional[ChannelModel]: + with get_db_context(db) as db: # Ensure uniqueness in case a list with duplicates is passed unique_user_ids = list(set(user_ids)) @@ -462,8 +462,9 @@ class ChannelTable: invited_by: str, user_ids: Optional[list[str]] = None, group_ids: Optional[list[str]] = None, + db: Optional[Session] = None, ) -> list[ChannelMemberModel]: - with get_db() as db: + with get_db_context(db) as db: # 1. Collect all user_ids including groups + inviter requested_users = self._collect_unique_user_ids( invited_by, user_ids, group_ids @@ -496,8 +497,9 @@ class ChannelTable: self, channel_id: str, user_ids: list[str], + db: Optional[Session] = None, ) -> int: - with get_db() as db: + with get_db_context(db) as db: result = ( db.query(ChannelMember) .filter( @@ -509,8 +511,8 @@ class ChannelTable: db.commit() return result # number of rows deleted - def is_user_channel_manager(self, channel_id: str, user_id: str) -> bool: - with get_db() as db: + def is_user_channel_manager(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: # Check if the user is the creator of the channel # or has a 'manager' role in ChannelMember channel = db.query(Channel).filter(Channel.id == channel_id).first() @@ -529,9 +531,9 @@ class ChannelTable: return membership is not None def join_channel( - self, channel_id: str, user_id: str + self, channel_id: str, user_id: str, db: Optional[Session] = None ) -> Optional[ChannelMemberModel]: - with get_db() as db: + with get_db_context(db) as db: # Check if the membership already exists existing_membership = ( db.query(ChannelMember) @@ -567,8 +569,8 @@ class ChannelTable: db.commit() return channel_member - def leave_channel(self, channel_id: str, user_id: str) -> bool: - with get_db() as db: + def leave_channel(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: membership = ( db.query(ChannelMember) .filter( @@ -589,9 +591,9 @@ class ChannelTable: return True def get_member_by_channel_and_user_id( - self, channel_id: str, user_id: str + self, channel_id: str, user_id: str, db: Optional[Session] = None ) -> Optional[ChannelMemberModel]: - with get_db() as db: + with get_db_context(db) as db: membership = ( db.query(ChannelMember) .filter( @@ -602,8 +604,8 @@ class ChannelTable: ) return ChannelMemberModel.model_validate(membership) if membership else None - def get_members_by_channel_id(self, channel_id: str) -> list[ChannelMemberModel]: - with get_db() as db: + def get_members_by_channel_id(self, channel_id: str, db: Optional[Session] = None) -> list[ChannelMemberModel]: + with get_db_context(db) as db: memberships = ( db.query(ChannelMember) .filter(ChannelMember.channel_id == channel_id) @@ -614,8 +616,8 @@ class ChannelTable: for membership in memberships ] - def pin_channel(self, channel_id: str, user_id: str, is_pinned: bool) -> bool: - with get_db() as db: + def pin_channel(self, channel_id: str, user_id: str, is_pinned: bool, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: membership = ( db.query(ChannelMember) .filter( @@ -633,8 +635,8 @@ class ChannelTable: db.commit() return True - def update_member_last_read_at(self, channel_id: str, user_id: str) -> bool: - with get_db() as db: + def update_member_last_read_at(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: membership = ( db.query(ChannelMember) .filter( @@ -653,9 +655,9 @@ class ChannelTable: return True def update_member_active_status( - self, channel_id: str, user_id: str, is_active: bool + self, channel_id: str, user_id: str, is_active: bool, db: Optional[Session] = None ) -> bool: - with get_db() as db: + with get_db_context(db) as db: membership = ( db.query(ChannelMember) .filter( @@ -673,8 +675,8 @@ class ChannelTable: db.commit() return True - def is_user_channel_member(self, channel_id: str, user_id: str) -> bool: - with get_db() as db: + def is_user_channel_member(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: membership = ( db.query(ChannelMember) .filter( @@ -693,8 +695,8 @@ class ChannelTable: except Exception: return None - def get_channels_by_file_id(self, file_id: str) -> list[ChannelModel]: - with get_db() as db: + def get_channels_by_file_id(self, file_id: str, db: Optional[Session] = None) -> list[ChannelModel]: + with get_db_context(db) as db: channel_files = ( db.query(ChannelFile).filter(ChannelFile.file_id == file_id).all() ) @@ -703,9 +705,9 @@ class ChannelTable: return [ChannelModel.model_validate(channel) for channel in channels] def get_channels_by_file_id_and_user_id( - self, file_id: str, user_id: str + self, file_id: str, user_id: str, db: Optional[Session] = None ) -> list[ChannelModel]: - with get_db() as db: + with get_db_context(db) as db: # 1. Determine which channels have this file channel_file_rows = ( db.query(ChannelFile).filter(ChannelFile.file_id == file_id).all() @@ -729,7 +731,7 @@ class ChannelTable: return [] # Preload user's group membership - user_group_ids = [g.id for g in Groups.get_groups_by_member_id(user_id)] + user_group_ids = [g.id for g in Groups.get_groups_by_member_id(user_id, db=db)] allowed_channels = [] @@ -766,9 +768,9 @@ class ChannelTable: return allowed_channels def get_channel_by_id_and_user_id( - self, id: str, user_id: str + self, id: str, user_id: str, db: Optional[Session] = None ) -> Optional[ChannelModel]: - with get_db() as db: + with get_db_context(db) as db: # Fetch the channel channel: Channel = ( db.query(Channel) diff --git a/backend/open_webui/models/files.py b/backend/open_webui/models/files.py index 387dd5b28c..f734ea62d7 100644 --- a/backend/open_webui/models/files.py +++ b/backend/open_webui/models/files.py @@ -135,7 +135,9 @@ class FilesTable: log.exception(f"Error inserting a new file: {e}") return None - def get_file_by_id(self, id: str, db: Optional[Session] = None) -> Optional[FileModel]: + def get_file_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[FileModel]: try: with get_db_context(db) as db: try: @@ -146,8 +148,10 @@ class FilesTable: except Exception: return None - def get_file_by_id_and_user_id(self, id: str, user_id: str) -> Optional[FileModel]: - with get_db() as db: + def get_file_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> Optional[FileModel]: + with get_db_context(db) as db: try: file = db.query(File).filter_by(id=id, user_id=user_id).first() if file: @@ -157,8 +161,10 @@ class FilesTable: except Exception: return None - def get_file_metadata_by_id(self, id: str) -> Optional[FileMetadataResponse]: - with get_db() as db: + def get_file_metadata_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[FileMetadataResponse]: + with get_db_context(db) as db: try: file = db.get(File, id) return FileMetadataResponse( @@ -175,8 +181,10 @@ class FilesTable: with get_db_context(db) as db: return [FileModel.model_validate(file) for file in db.query(File).all()] - def check_access_by_user_id(self, id, user_id, permission="write") -> bool: - file = self.get_file_by_id(id) + def check_access_by_user_id( + self, id, user_id, permission="write", db: Optional[Session] = None + ) -> bool: + file = self.get_file_by_id(id, db=db) if not file: return False if file.user_id == user_id: @@ -184,8 +192,10 @@ class FilesTable: # Implement additional access control logic here as needed return False - def get_files_by_ids(self, ids: list[str]) -> list[FileModel]: - with get_db() as db: + def get_files_by_ids( + self, ids: list[str], db: Optional[Session] = None + ) -> list[FileModel]: + with get_db_context(db) as db: return [ FileModel.model_validate(file) for file in db.query(File) @@ -194,8 +204,10 @@ class FilesTable: .all() ] - def get_file_metadatas_by_ids(self, ids: list[str]) -> list[FileMetadataResponse]: - with get_db() as db: + def get_file_metadatas_by_ids( + self, ids: list[str], db: Optional[Session] = None + ) -> list[FileMetadataResponse]: + with get_db_context(db) as db: return [ FileMetadataResponse( id=file.id, @@ -212,7 +224,9 @@ class FilesTable: .all() ] - def get_files_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[FileModel]: + def get_files_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[FileModel]: with get_db_context(db) as db: return [ FileModel.model_validate(file) @@ -220,9 +234,9 @@ class FilesTable: ] def update_file_by_id( - self, id: str, form_data: FileUpdateForm + self, id: str, form_data: FileUpdateForm, db: Optional[Session] = None ) -> Optional[FileModel]: - with get_db() as db: + with get_db_context(db) as db: try: file = db.query(File).filter_by(id=id).first() @@ -242,8 +256,10 @@ class FilesTable: log.exception(f"Error updating file completely by id: {e}") return None - def update_file_hash_by_id(self, id: str, hash: str) -> Optional[FileModel]: - with get_db() as db: + def update_file_hash_by_id( + self, id: str, hash: str, db: Optional[Session] = None + ) -> Optional[FileModel]: + with get_db_context(db) as db: try: file = db.query(File).filter_by(id=id).first() file.hash = hash @@ -254,8 +270,10 @@ class FilesTable: except Exception: return None - def update_file_data_by_id(self, id: str, data: dict) -> Optional[FileModel]: - with get_db() as db: + def update_file_data_by_id( + self, id: str, data: dict, db: Optional[Session] = None + ) -> Optional[FileModel]: + with get_db_context(db) as db: try: file = db.query(File).filter_by(id=id).first() file.data = {**(file.data if file.data else {}), **data} @@ -266,8 +284,10 @@ class FilesTable: return None - def update_file_metadata_by_id(self, id: str, meta: dict) -> Optional[FileModel]: - with get_db() as db: + def update_file_metadata_by_id( + self, id: str, meta: dict, db: Optional[Session] = None + ) -> Optional[FileModel]: + with get_db_context(db) as db: try: file = db.query(File).filter_by(id=id).first() file.meta = {**(file.meta if file.meta else {}), **meta} @@ -279,5 +299,25 @@ class FilesTable: return False + def delete_file_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: + try: + db.query(File).filter_by(id=id).delete() + db.commit() + + return True + except Exception: + return False + + def delete_all_files(self, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: + try: + db.query(File).delete() + db.commit() + + return True + except Exception: + return False + Files = FilesTable() From c79fb7db749732c983b7cbf9238957ce70acb92f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 28 Dec 2025 22:40:28 +0400 Subject: [PATCH 031/254] refac --- backend/open_webui/test/util/mock_user.py | 45 ----------------------- 1 file changed, 45 deletions(-) delete mode 100644 backend/open_webui/test/util/mock_user.py diff --git a/backend/open_webui/test/util/mock_user.py b/backend/open_webui/test/util/mock_user.py deleted file mode 100644 index 7ce64dffa9..0000000000 --- a/backend/open_webui/test/util/mock_user.py +++ /dev/null @@ -1,45 +0,0 @@ -from contextlib import contextmanager - -from fastapi import FastAPI - - -@contextmanager -def mock_webui_user(**kwargs): - from open_webui.routers.webui import app - - with mock_user(app, **kwargs): - yield - - -@contextmanager -def mock_user(app: FastAPI, **kwargs): - from open_webui.utils.auth import ( - get_current_user, - get_verified_user, - get_admin_user, - get_current_user_by_api_key, - ) - from open_webui.models.users import User - - def create_user(): - user_parameters = { - "id": "1", - "name": "John Doe", - "email": "john.doe@openwebui.com", - "role": "user", - "profile_image_url": "/user.png", - "last_active_at": 1627351200, - "updated_at": 1627351200, - "created_at": 162735120, - **kwargs, - } - return User(**user_parameters) - - app.dependency_overrides = { - get_current_user: create_user, - get_verified_user: create_user, - get_admin_user: create_user, - get_current_user_by_api_key: create_user, - } - yield - app.dependency_overrides = {} From eb4b085b86120387cb863223afecc583c17094e5 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 28 Dec 2025 23:23:56 +0400 Subject: [PATCH 032/254] refac --- backend/open_webui/models/notes.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/models/notes.py b/backend/open_webui/models/notes.py index fef9db7bf4..ee376f41b5 100644 --- a/backend/open_webui/models/notes.py +++ b/backend/open_webui/models/notes.py @@ -244,9 +244,14 @@ class NoteTable: return [NoteModel.model_validate(note) for note in notes] def search_notes( - self, user_id: str, filter: dict = {}, skip: int = 0, limit: int = 30 + self, + user_id: str, + filter: dict = {}, + skip: int = 0, + limit: int = 30, + db: Optional[Session] = None, ) -> NoteListResponse: - with get_db() as db: + with get_db_context(db) as db: query = db.query(Note, User).outerjoin(User, User.id == Note.user_id) if filter: query_key = filter.get("query") From 6dd0f99b90c2ec8363514d090e1c3208a14e8bb3 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 28 Dec 2025 23:35:09 +0400 Subject: [PATCH 033/254] rm: outdated tests --- .../test/apps/webui/routers/test_chats.py | 236 ------------------ .../test/util/abstract_integration_test.py | 161 ------------ 2 files changed, 397 deletions(-) delete mode 100644 backend/open_webui/test/apps/webui/routers/test_chats.py delete mode 100644 backend/open_webui/test/util/abstract_integration_test.py diff --git a/backend/open_webui/test/apps/webui/routers/test_chats.py b/backend/open_webui/test/apps/webui/routers/test_chats.py deleted file mode 100644 index a36a01fb14..0000000000 --- a/backend/open_webui/test/apps/webui/routers/test_chats.py +++ /dev/null @@ -1,236 +0,0 @@ -import uuid - -from test.util.abstract_integration_test import AbstractPostgresTest -from test.util.mock_user import mock_webui_user - - -class TestChats(AbstractPostgresTest): - BASE_PATH = "/api/v1/chats" - - def setup_class(cls): - super().setup_class() - - def setup_method(self): - super().setup_method() - from open_webui.models.chats import ChatForm, Chats - - self.chats = Chats - self.chats.insert_new_chat( - "2", - ChatForm( - **{ - "chat": { - "name": "chat1", - "description": "chat1 description", - "tags": ["tag1", "tag2"], - "history": {"currentId": "1", "messages": []}, - } - } - ), - ) - - def test_get_session_user_chat_list(self): - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url("/")) - assert response.status_code == 200 - first_chat = response.json()[0] - assert first_chat["id"] is not None - assert first_chat["title"] == "New Chat" - assert first_chat["created_at"] is not None - assert first_chat["updated_at"] is not None - - def test_delete_all_user_chats(self): - with mock_webui_user(id="2"): - response = self.fast_api_client.delete(self.create_url("/")) - assert response.status_code == 200 - assert len(self.chats.get_chats()) == 0 - - def test_get_user_chat_list_by_user_id(self): - with mock_webui_user(id="3"): - response = self.fast_api_client.get(self.create_url("/list/user/2")) - assert response.status_code == 200 - first_chat = response.json()[0] - assert first_chat["id"] is not None - assert first_chat["title"] == "New Chat" - assert first_chat["created_at"] is not None - assert first_chat["updated_at"] is not None - - def test_create_new_chat(self): - with mock_webui_user(id="2"): - response = self.fast_api_client.post( - self.create_url("/new"), - json={ - "chat": { - "name": "chat2", - "description": "chat2 description", - "tags": ["tag1", "tag2"], - } - }, - ) - assert response.status_code == 200 - data = response.json() - assert data["archived"] is False - assert data["chat"] == { - "name": "chat2", - "description": "chat2 description", - "tags": ["tag1", "tag2"], - } - assert data["user_id"] == "2" - assert data["id"] is not None - assert data["share_id"] is None - assert data["title"] == "New Chat" - assert data["updated_at"] is not None - assert data["created_at"] is not None - assert len(self.chats.get_chats()) == 2 - - def test_get_user_chats(self): - self.test_get_session_user_chat_list() - - def test_get_user_archived_chats(self): - self.chats.archive_all_chats_by_user_id("2") - from open_webui.internal.db import Session - - Session.commit() - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url("/all/archived")) - assert response.status_code == 200 - first_chat = response.json()[0] - assert first_chat["id"] is not None - assert first_chat["title"] == "New Chat" - assert first_chat["created_at"] is not None - assert first_chat["updated_at"] is not None - - def test_get_all_user_chats_in_db(self): - with mock_webui_user(id="4"): - response = self.fast_api_client.get(self.create_url("/all/db")) - assert response.status_code == 200 - assert len(response.json()) == 1 - - def test_get_archived_session_user_chat_list(self): - self.test_get_user_archived_chats() - - def test_archive_all_chats(self): - with mock_webui_user(id="2"): - response = self.fast_api_client.post(self.create_url("/archive/all")) - assert response.status_code == 200 - assert len(self.chats.get_archived_chats_by_user_id("2")) == 1 - - def test_get_shared_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - self.chats.update_chat_share_id_by_id(chat_id, chat_id) - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url(f"/share/{chat_id}")) - assert response.status_code == 200 - data = response.json() - assert data["id"] == chat_id - assert data["chat"] == { - "name": "chat1", - "description": "chat1 description", - "tags": ["tag1", "tag2"], - "history": {"currentId": "1", "messages": []}, - } - assert data["id"] == chat_id - assert data["share_id"] == chat_id - assert data["title"] == "New Chat" - - def test_get_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url(f"/{chat_id}")) - assert response.status_code == 200 - data = response.json() - assert data["id"] == chat_id - assert data["chat"] == { - "name": "chat1", - "description": "chat1 description", - "tags": ["tag1", "tag2"], - "history": {"currentId": "1", "messages": []}, - } - assert data["share_id"] is None - assert data["title"] == "New Chat" - assert data["user_id"] == "2" - - def test_update_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - with mock_webui_user(id="2"): - response = self.fast_api_client.post( - self.create_url(f"/{chat_id}"), - json={ - "chat": { - "name": "chat2", - "description": "chat2 description", - "tags": ["tag2", "tag4"], - "title": "Just another title", - } - }, - ) - assert response.status_code == 200 - data = response.json() - assert data["id"] == chat_id - assert data["chat"] == { - "name": "chat2", - "title": "Just another title", - "description": "chat2 description", - "tags": ["tag2", "tag4"], - "history": {"currentId": "1", "messages": []}, - } - assert data["share_id"] is None - assert data["title"] == "Just another title" - assert data["user_id"] == "2" - - def test_delete_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - with mock_webui_user(id="2"): - response = self.fast_api_client.delete(self.create_url(f"/{chat_id}")) - assert response.status_code == 200 - assert response.json() is True - - def test_clone_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url(f"/{chat_id}/clone")) - - assert response.status_code == 200 - data = response.json() - assert data["id"] != chat_id - assert data["chat"] == { - "branchPointMessageId": "1", - "description": "chat1 description", - "history": {"currentId": "1", "messages": []}, - "name": "chat1", - "originalChatId": chat_id, - "tags": ["tag1", "tag2"], - "title": "Clone of New Chat", - } - assert data["share_id"] is None - assert data["title"] == "Clone of New Chat" - assert data["user_id"] == "2" - - def test_archive_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - with mock_webui_user(id="2"): - response = self.fast_api_client.get(self.create_url(f"/{chat_id}/archive")) - assert response.status_code == 200 - - chat = self.chats.get_chat_by_id(chat_id) - assert chat.archived is True - - def test_share_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - with mock_webui_user(id="2"): - response = self.fast_api_client.post(self.create_url(f"/{chat_id}/share")) - assert response.status_code == 200 - - chat = self.chats.get_chat_by_id(chat_id) - assert chat.share_id is not None - - def test_delete_shared_chat_by_id(self): - chat_id = self.chats.get_chats()[0].id - share_id = str(uuid.uuid4()) - self.chats.update_chat_share_id_by_id(chat_id, share_id) - with mock_webui_user(id="2"): - response = self.fast_api_client.delete(self.create_url(f"/{chat_id}/share")) - assert response.status_code - - chat = self.chats.get_chat_by_id(chat_id) - assert chat.share_id is None diff --git a/backend/open_webui/test/util/abstract_integration_test.py b/backend/open_webui/test/util/abstract_integration_test.py deleted file mode 100644 index e8492befb6..0000000000 --- a/backend/open_webui/test/util/abstract_integration_test.py +++ /dev/null @@ -1,161 +0,0 @@ -import logging -import os -import time - -import docker -import pytest -from docker import DockerClient -from pytest_docker.plugin import get_docker_ip -from fastapi.testclient import TestClient -from sqlalchemy import text, create_engine - - -log = logging.getLogger(__name__) - - -def get_fast_api_client(): - from main import app - - with TestClient(app) as c: - return c - - -class AbstractIntegrationTest: - BASE_PATH = None - - def create_url(self, path="", query_params=None): - if self.BASE_PATH is None: - raise Exception("BASE_PATH is not set") - parts = self.BASE_PATH.split("/") - parts = [part.strip() for part in parts if part.strip() != ""] - path_parts = path.split("/") - path_parts = [part.strip() for part in path_parts if part.strip() != ""] - query_parts = "" - if query_params: - query_parts = "&".join( - [f"{key}={value}" for key, value in query_params.items()] - ) - query_parts = f"?{query_parts}" - return "/".join(parts + path_parts) + query_parts - - @classmethod - def setup_class(cls): - pass - - def setup_method(self): - pass - - @classmethod - def teardown_class(cls): - pass - - def teardown_method(self): - pass - - -class AbstractPostgresTest(AbstractIntegrationTest): - DOCKER_CONTAINER_NAME = "postgres-test-container-will-get-deleted" - docker_client: DockerClient - - @classmethod - def _create_db_url(cls, env_vars_postgres: dict) -> str: - host = get_docker_ip() - user = env_vars_postgres["POSTGRES_USER"] - pw = env_vars_postgres["POSTGRES_PASSWORD"] - port = 8081 - db = env_vars_postgres["POSTGRES_DB"] - return f"postgresql://{user}:{pw}@{host}:{port}/{db}" - - @classmethod - def setup_class(cls): - super().setup_class() - try: - env_vars_postgres = { - "POSTGRES_USER": "user", - "POSTGRES_PASSWORD": "example", - "POSTGRES_DB": "openwebui", - } - cls.docker_client = docker.from_env() - cls.docker_client.containers.run( - "postgres:16.2", - detach=True, - environment=env_vars_postgres, - name=cls.DOCKER_CONTAINER_NAME, - ports={5432: ("0.0.0.0", 8081)}, - command="postgres -c log_statement=all", - ) - time.sleep(0.5) - - database_url = cls._create_db_url(env_vars_postgres) - os.environ["DATABASE_URL"] = database_url - retries = 10 - db = None - while retries > 0: - try: - from open_webui.config import OPEN_WEBUI_DIR - - db = create_engine(database_url, pool_pre_ping=True) - db = db.connect() - log.info("postgres is ready!") - break - except Exception as e: - log.warning(e) - time.sleep(3) - retries -= 1 - - if db: - # import must be after setting env! - cls.fast_api_client = get_fast_api_client() - db.close() - else: - raise Exception("Could not connect to Postgres") - except Exception as ex: - log.error(ex) - cls.teardown_class() - pytest.fail(f"Could not setup test environment: {ex}") - - def _check_db_connection(self): - from open_webui.internal.db import Session - - retries = 10 - while retries > 0: - try: - Session.execute(text("SELECT 1")) - Session.commit() - break - except Exception as e: - Session.rollback() - log.warning(e) - time.sleep(3) - retries -= 1 - - def setup_method(self): - super().setup_method() - self._check_db_connection() - - @classmethod - def teardown_class(cls) -> None: - super().teardown_class() - cls.docker_client.containers.get(cls.DOCKER_CONTAINER_NAME).remove(force=True) - - def teardown_method(self): - from open_webui.internal.db import Session - - # rollback everything not yet committed - Session.commit() - - # truncate all tables - tables = [ - "auth", - "chat", - "chatidtag", - "document", - "memory", - "model", - "prompt", - "tag", - '"user"', - ] - for table in tables: - Session.execute(text(f"TRUNCATE TABLE {table}")) - Session.commit() From b1d0f00d8c4d024a55f84e4d465d2fddd637ef27 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 29 Dec 2025 00:21:18 +0400 Subject: [PATCH 034/254] refac/enh: db session sharing --- backend/open_webui/internal/db.py | 5 +- backend/open_webui/main.py | 17 +- .../retrieval/vector/dbs/opengauss.py | 77 ++-- .../retrieval/vector/dbs/pgvector.py | 4 +- backend/open_webui/routers/auths.py | 134 +++++-- backend/open_webui/routers/chats.py | 345 ++++++++++++------ backend/open_webui/routers/evaluations.py | 75 ++-- backend/open_webui/routers/files.py | 230 ++++++++---- backend/open_webui/routers/folders.py | 87 +++-- backend/open_webui/routers/functions.py | 84 ++--- backend/open_webui/routers/groups.py | 80 ++-- backend/open_webui/routers/knowledge.py | 153 +++++--- backend/open_webui/routers/memories.py | 30 +- backend/open_webui/routers/models.py | 82 +++-- backend/open_webui/routers/notes.py | 90 +++-- backend/open_webui/routers/prompts.py | 44 ++- backend/open_webui/routers/retrieval.py | 26 +- backend/open_webui/routers/tools.py | 88 ++--- backend/open_webui/routers/users.py | 129 ++++--- backend/open_webui/utils/access_control.py | 17 +- backend/open_webui/utils/auth.py | 13 +- backend/open_webui/utils/groups.py | 3 +- backend/open_webui/utils/oauth.py | 23 +- 23 files changed, 1173 insertions(+), 663 deletions(-) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index e84dfe9aa7..e4e4e0d2f8 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -19,7 +19,7 @@ from open_webui.env import ( from peewee_migrate import Router from sqlalchemy import Dialect, create_engine, MetaData, event, types from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import scoped_session, sessionmaker +from sqlalchemy.orm import scoped_session, sessionmaker, Session from sqlalchemy.pool import QueuePool, NullPool from sqlalchemy.sql.type_api import _T from typing_extensions import Self @@ -148,7 +148,7 @@ SessionLocal = sessionmaker( ) metadata_obj = MetaData(schema=DATABASE_SCHEMA) Base = declarative_base(metadata=metadata_obj) -Session = scoped_session(SessionLocal) +ScopedSession = scoped_session(SessionLocal) def get_session(): @@ -169,4 +169,3 @@ def get_db_context(db: Optional[Session] = None): else: with get_db() as session: yield session - diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 63ae72f7bc..97d91c0ee0 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -102,7 +102,9 @@ from open_webui.routers.retrieval import ( get_rf, ) -from open_webui.internal.db import Session, engine + +from sqlalchemy.orm import Session +from open_webui.internal.db import ScopedSession, engine, get_session from open_webui.models.functions import Functions from open_webui.models.models import Models @@ -1324,7 +1326,7 @@ app.add_middleware(APIKeyRestrictionMiddleware) async def commit_session_after_request(request: Request, call_next): response = await call_next(request) # log.debug("Commit session after request") - Session.commit() + ScopedSession.commit() return response @@ -2280,8 +2282,13 @@ async def oauth_login(provider: str, request: Request): # - Email addresses are considered unique, so we fail registration if the email address is already taken @app.get("/oauth/{provider}/login/callback") @app.get("/oauth/{provider}/callback") # Legacy endpoint -async def oauth_login_callback(provider: str, request: Request, response: Response): - return await oauth_manager.handle_callback(request, provider, response) +async def oauth_login_callback( + provider: str, + request: Request, + response: Response, + db: Session = Depends(get_session), +): + return await oauth_manager.handle_callback(request, provider, response, db=db) @app.get("/manifest.json") @@ -2340,7 +2347,7 @@ async def healthcheck(): @app.get("/health/db") async def healthcheck_with_db(): - Session.execute(text("SELECT 1;")).all() + ScopedSession.execute(text("SELECT 1;")).all() return {"status": True} diff --git a/backend/open_webui/retrieval/vector/dbs/opengauss.py b/backend/open_webui/retrieval/vector/dbs/opengauss.py index 13505e1852..056a8a61cc 100644 --- a/backend/open_webui/retrieval/vector/dbs/opengauss.py +++ b/backend/open_webui/retrieval/vector/dbs/opengauss.py @@ -30,27 +30,27 @@ from sqlalchemy.exc import NoSuchTableError from sqlalchemy.dialects.postgresql.psycopg2 import PGDialect_psycopg2 from sqlalchemy.dialects import registry + class OpenGaussDialect(PGDialect_psycopg2): name = "opengauss" - + def _get_server_version_info(self, connection): try: version = connection.exec_driver_sql("SELECT version()").scalar() if not version: return (9, 0, 0) - + match = re.search( - r"openGauss\s+(\d+)\.(\d+)\.(\d+)(?:-\w+)?", - version, - re.IGNORECASE + r"openGauss\s+(\d+)\.(\d+)\.(\d+)(?:-\w+)?", version, re.IGNORECASE ) if match: return (int(match.group(1)), int(match.group(2)), int(match.group(3))) - + return super()._get_server_version_info(connection) except Exception: return (9, 0, 0) + # Register dialect registry.register("opengauss", __name__, "OpenGaussDialect") @@ -78,6 +78,7 @@ Base = declarative_base() log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["RAG"]) + class DocumentChunk(Base): __tablename__ = "document_chunk" @@ -87,29 +88,30 @@ class DocumentChunk(Base): text = Column(Text, nullable=True) vmetadata = Column(MutableDict.as_mutable(JSONB), nullable=True) + class OpenGaussClient(VectorDBBase): def __init__(self) -> None: if not OPENGAUSS_DB_URL: - from open_webui.internal.db import Session - self.session = Session + from open_webui.internal.db import ScopedSession + + self.session = ScopedSession else: - engine_kwargs = { - "pool_pre_ping": True, - "dialect": OpenGaussDialect() - } - + engine_kwargs = {"pool_pre_ping": True, "dialect": OpenGaussDialect()} + if isinstance(OPENGAUSS_POOL_SIZE, int) and OPENGAUSS_POOL_SIZE > 0: - engine_kwargs.update({ - "pool_size": OPENGAUSS_POOL_SIZE, - "max_overflow": OPENGAUSS_POOL_MAX_OVERFLOW, - "pool_timeout": OPENGAUSS_POOL_TIMEOUT, - "pool_recycle": OPENGAUSS_POOL_RECYCLE, - "poolclass": QueuePool - }) + engine_kwargs.update( + { + "pool_size": OPENGAUSS_POOL_SIZE, + "max_overflow": OPENGAUSS_POOL_MAX_OVERFLOW, + "pool_timeout": OPENGAUSS_POOL_TIMEOUT, + "pool_recycle": OPENGAUSS_POOL_RECYCLE, + "poolclass": QueuePool, + } + ) else: engine_kwargs["poolclass"] = NullPool - engine = create_engine(OPENGAUSS_DB_URL,** engine_kwargs) + engine = create_engine(OPENGAUSS_DB_URL, **engine_kwargs) SessionLocal = sessionmaker( autocommit=False, autoflush=False, bind=engine, expire_on_commit=False @@ -160,7 +162,9 @@ class OpenGaussClient(VectorDBBase): else: raise Exception("The 'vector' column type is not Vector.") else: - raise Exception("The 'vector' column does not exist in the 'document_chunk' table.") + raise Exception( + "The 'vector' column does not exist in the 'document_chunk' table." + ) def adjust_vector_length(self, vector: List[float]) -> List[float]: current_length = len(vector) @@ -185,7 +189,9 @@ class OpenGaussClient(VectorDBBase): new_items.append(new_chunk) self.session.bulk_save_objects(new_items) self.session.commit() - log.info(f"Inserting {len(new_items)} items into collection '{collection_name}'.") + log.info( + f"Inserting {len(new_items)} items into collection '{collection_name}'." + ) except Exception as e: self.session.rollback() log.exception(f"Failed to insert data: {e}") @@ -215,7 +221,9 @@ class OpenGaussClient(VectorDBBase): ) self.session.add(new_chunk) self.session.commit() - log.info(f"Inserting/updating {len(items)} items in collection '{collection_name}'.") + log.info( + f"Inserting/updating {len(items)} items in collection '{collection_name}'." + ) except Exception as e: self.session.rollback() log.exception(f"Failed to insert or update data.: {e}") @@ -241,7 +249,9 @@ class OpenGaussClient(VectorDBBase): q_vector_col = column("q_vector", Vector(VECTOR_LENGTH)) query_vectors = ( values(qid_col, q_vector_col) - .data([(idx, vector_expr(vector)) for idx, vector in enumerate(vectors)]) + .data( + [(idx, vector_expr(vector)) for idx, vector in enumerate(vectors)] + ) .alias("query_vectors") ) @@ -249,13 +259,17 @@ class OpenGaussClient(VectorDBBase): DocumentChunk.id, DocumentChunk.text, DocumentChunk.vmetadata, - (DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector)).label("distance"), + (DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector)).label( + "distance" + ), ] subq = ( select(*result_fields) .where(DocumentChunk.collection_name == collection_name) - .order_by(DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector)) + .order_by( + DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector) + ) ) if limit is not None: subq = subq.limit(limit) @@ -368,7 +382,9 @@ class OpenGaussClient(VectorDBBase): query = query.filter(DocumentChunk.id.in_(ids)) if filter: for key, value in filter.items(): - query = query.filter(DocumentChunk.vmetadata[key].astext == str(value)) + query = query.filter( + DocumentChunk.vmetadata[key].astext == str(value) + ) deleted = query.delete(synchronize_session=False) self.session.commit() log.info(f"Deleted {deleted} items from collection '{collection_name}'") @@ -395,7 +411,8 @@ class OpenGaussClient(VectorDBBase): exists = ( self.session.query(DocumentChunk) .filter(DocumentChunk.collection_name == collection_name) - .first() is not None + .first() + is not None ) self.session.rollback() return exists @@ -406,4 +423,4 @@ class OpenGaussClient(VectorDBBase): def delete_collection(self, collection_name: str) -> None: self.delete(collection_name) - log.info(f"Collection '{collection_name}' has been deleted") \ No newline at end of file + log.info(f"Collection '{collection_name}' has been deleted") diff --git a/backend/open_webui/retrieval/vector/dbs/pgvector.py b/backend/open_webui/retrieval/vector/dbs/pgvector.py index 2f4677995a..b9b1dba07b 100644 --- a/backend/open_webui/retrieval/vector/dbs/pgvector.py +++ b/backend/open_webui/retrieval/vector/dbs/pgvector.py @@ -90,9 +90,9 @@ class PgvectorClient(VectorDBBase): # if no pgvector uri, use the existing database connection if not PGVECTOR_DB_URL: - from open_webui.internal.db import Session + from open_webui.internal.db import ScopedSession - self.session = Session + self.session = ScopedSession else: if isinstance(PGVECTOR_POOL_SIZE, int): if PGVECTOR_POOL_SIZE > 0: diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 59c5322c7f..7482e9053e 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -62,6 +62,8 @@ from open_webui.utils.auth import ( get_password_hash, get_http_authorization_cred, ) +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session from open_webui.utils.webhook import post_webhook from open_webui.utils.access_control import get_permissions, has_permission from open_webui.utils.groups import apply_default_group_assignment @@ -103,7 +105,10 @@ class SessionUserInfoResponse(SessionUserResponse, UserStatus): @router.get("/", response_model=SessionUserInfoResponse) async def get_session_user( - request: Request, response: Response, user=Depends(get_current_user) + request: Request, + response: Response, + user=Depends(get_current_user), + db: Session = Depends(get_session), ): auth_header = request.headers.get("Authorization") @@ -137,7 +142,7 @@ async def get_session_user( ) user_permissions = get_permissions( - user.id, request.app.state.config.USER_PERMISSIONS + user.id, request.app.state.config.USER_PERMISSIONS, db=db ) return { @@ -166,12 +171,15 @@ async def get_session_user( @router.post("/update/profile", response_model=UserProfileImageResponse) async def update_profile( - form_data: UpdateProfileForm, session_user=Depends(get_verified_user) + form_data: UpdateProfileForm, + session_user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if session_user: user = Users.update_user_by_id( session_user.id, form_data.model_dump(), + db=db, ) if user: return user @@ -188,13 +196,17 @@ async def update_profile( @router.post("/update/password", response_model=bool) async def update_password( - form_data: UpdatePasswordForm, session_user=Depends(get_current_user) + form_data: UpdatePasswordForm, + session_user=Depends(get_current_user), + db: Session = Depends(get_session), ): if WEBUI_AUTH_TRUSTED_EMAIL_HEADER: raise HTTPException(400, detail=ERROR_MESSAGES.ACTION_PROHIBITED) if session_user: user = Auths.authenticate_user( - session_user.email, lambda pw: verify_password(form_data.password, pw) + session_user.email, + lambda pw: verify_password(form_data.password, pw), + db=db, ) if user: @@ -203,7 +215,7 @@ async def update_password( except Exception as e: raise HTTPException(400, detail=str(e)) hashed = get_password_hash(form_data.new_password) - return Auths.update_user_password_by_id(user.id, hashed) + return Auths.update_user_password_by_id(user.id, hashed, db=db) else: raise HTTPException(400, detail=ERROR_MESSAGES.INCORRECT_PASSWORD) else: @@ -214,7 +226,12 @@ async def update_password( # LDAP Authentication ############################ @router.post("/ldap", response_model=SessionUserResponse) -async def ldap_auth(request: Request, response: Response, form_data: LdapForm): +async def ldap_auth( + request: Request, + response: Response, + form_data: LdapForm, + db: Session = Depends(get_session), +): # Security checks FIRST - before loading any config if not request.app.state.config.ENABLE_LDAP: raise HTTPException(400, detail="LDAP authentication is not enabled") @@ -400,12 +417,12 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): if not connection_user.bind(): raise HTTPException(400, "Authentication failed.") - user = Users.get_user_by_email(email) + user = Users.get_user_by_email(email, db=db) if not user: try: role = ( "admin" - if not Users.has_users() + if not Users.has_users(db=db) else request.app.state.config.DEFAULT_USER_ROLE ) @@ -414,6 +431,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): password=str(uuid.uuid4()), name=cn, role=role, + db=db, ) if not user: @@ -424,6 +442,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): apply_default_group_assignment( request.app.state.config.DEFAULT_GROUP_ID, user.id, + db=db, ) except HTTPException: @@ -434,7 +453,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): 500, detail="Internal error occurred during LDAP user creation." ) - user = Auths.authenticate_user_by_email(email) + user = Auths.authenticate_user_by_email(email, db=db) if user: expires_delta = parse_duration(request.app.state.config.JWT_EXPIRES_IN) @@ -464,7 +483,7 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): ) user_permissions = get_permissions( - user.id, request.app.state.config.USER_PERMISSIONS + user.id, request.app.state.config.USER_PERMISSIONS, db=db ) if ( @@ -473,9 +492,9 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): and user_groups ): if ENABLE_LDAP_GROUP_CREATION: - Groups.create_groups_by_group_names(user.id, user_groups) + Groups.create_groups_by_group_names(user.id, user_groups, db=db) try: - Groups.sync_groups_by_group_names(user.id, user_groups) + Groups.sync_groups_by_group_names(user.id, user_groups, db=db) log.info( f"Successfully synced groups for user {user.id}: {user_groups}" ) @@ -508,7 +527,12 @@ async def ldap_auth(request: Request, response: Response, form_data: LdapForm): @router.post("/signin", response_model=SessionUserResponse) -async def signin(request: Request, response: Response, form_data: SigninForm): +async def signin( + request: Request, + response: Response, + form_data: SigninForm, + db: Session = Depends(get_session), +): if not ENABLE_PASSWORD_AUTH: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, @@ -529,14 +553,15 @@ async def signin(request: Request, response: Response, form_data: SigninForm): except Exception as e: pass - if not Users.get_user_by_email(email.lower()): + if not Users.get_user_by_email(email.lower(), db=db): await signup( request, response, SignupForm(email=email, password=str(uuid.uuid4()), name=name), + db=db, ) - user = Auths.authenticate_user_by_email(email) + user = Auths.authenticate_user_by_email(email, db=db) if WEBUI_AUTH_TRUSTED_GROUPS_HEADER and user and user.role != "admin": group_names = request.headers.get( WEBUI_AUTH_TRUSTED_GROUPS_HEADER, "" @@ -544,28 +569,33 @@ async def signin(request: Request, response: Response, form_data: SigninForm): group_names = [name.strip() for name in group_names if name.strip()] if group_names: - Groups.sync_groups_by_group_names(user.id, group_names) + Groups.sync_groups_by_group_names(user.id, group_names, db=db) elif WEBUI_AUTH == False: admin_email = "admin@localhost" admin_password = "admin" - if Users.get_user_by_email(admin_email.lower()): + if Users.get_user_by_email(admin_email.lower(), db=db): user = Auths.authenticate_user( - admin_email.lower(), lambda pw: verify_password(admin_password, pw) + admin_email.lower(), + lambda pw: verify_password(admin_password, pw), + db=db, ) else: - if Users.has_users(): + if Users.has_users(db=db): raise HTTPException(400, detail=ERROR_MESSAGES.EXISTING_USERS) await signup( request, response, SignupForm(email=admin_email, password=admin_password, name="User"), + db=db, ) user = Auths.authenticate_user( - admin_email.lower(), lambda pw: verify_password(admin_password, pw) + admin_email.lower(), + lambda pw: verify_password(admin_password, pw), + db=db, ) else: if signin_rate_limiter.is_limited(form_data.email.lower()): @@ -584,7 +614,9 @@ async def signin(request: Request, response: Response, form_data: SigninForm): form_data.password = password_bytes.decode("utf-8", errors="ignore") user = Auths.authenticate_user( - form_data.email.lower(), lambda pw: verify_password(form_data.password, pw) + form_data.email.lower(), + lambda pw: verify_password(form_data.password, pw), + db=db, ) if user: @@ -616,7 +648,7 @@ async def signin(request: Request, response: Response, form_data: SigninForm): ) user_permissions = get_permissions( - user.id, request.app.state.config.USER_PERMISSIONS + user.id, request.app.state.config.USER_PERMISSIONS, db=db ) return { @@ -640,8 +672,13 @@ async def signin(request: Request, response: Response, form_data: SigninForm): @router.post("/signup", response_model=SessionUserResponse) -async def signup(request: Request, response: Response, form_data: SignupForm): - has_users = Users.has_users() +async def signup( + request: Request, + response: Response, + form_data: SignupForm, + db: Session = Depends(get_session), +): + has_users = Users.has_users(db=db) if WEBUI_AUTH: if ( @@ -663,7 +700,7 @@ async def signup(request: Request, response: Response, form_data: SignupForm): status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.INVALID_EMAIL_FORMAT ) - if Users.get_user_by_email(form_data.email.lower()): + if Users.get_user_by_email(form_data.email.lower(), db=db): raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN) try: @@ -681,6 +718,7 @@ async def signup(request: Request, response: Response, form_data: SignupForm): form_data.name, form_data.profile_image_url, role, + db=db, ) if user: @@ -723,7 +761,7 @@ async def signup(request: Request, response: Response, form_data: SignupForm): ) user_permissions = get_permissions( - user.id, request.app.state.config.USER_PERMISSIONS + user.id, request.app.state.config.USER_PERMISSIONS, db=db ) if not has_users: @@ -733,6 +771,7 @@ async def signup(request: Request, response: Response, form_data: SignupForm): apply_default_group_assignment( request.app.state.config.DEFAULT_GROUP_ID, user.id, + db=db, ) return { @@ -754,7 +793,9 @@ async def signup(request: Request, response: Response, form_data: SignupForm): @router.get("/signout") -async def signout(request: Request, response: Response): +async def signout( + request: Request, response: Response, db: Session = Depends(get_session) +): # get auth token from headers or cookies token = None @@ -776,7 +817,7 @@ async def signout(request: Request, response: Response): if oauth_session_id: response.delete_cookie("oauth_session_id") - session = OAuthSessions.get_session_by_id(oauth_session_id) + session = OAuthSessions.get_session_by_id(oauth_session_id, db=db) oauth_server_metadata_url = ( request.app.state.oauth_manager.get_server_metadata_url(session.provider) if session @@ -839,14 +880,17 @@ async def signout(request: Request, response: Response): @router.post("/add", response_model=SigninResponse) async def add_user( - request: Request, form_data: AddUserForm, user=Depends(get_admin_user) + request: Request, + form_data: AddUserForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): if not validate_email_format(form_data.email.lower()): raise HTTPException( status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.INVALID_EMAIL_FORMAT ) - if Users.get_user_by_email(form_data.email.lower()): + if Users.get_user_by_email(form_data.email.lower(), db=db): raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN) try: @@ -862,12 +906,14 @@ async def add_user( form_data.name, form_data.profile_image_url, form_data.role, + db=db, ) if user: apply_default_group_assignment( request.app.state.config.DEFAULT_GROUP_ID, user.id, + db=db, ) token = create_token(data={"id": user.id}) @@ -895,7 +941,9 @@ async def add_user( @router.get("/admin/details") -async def get_admin_details(request: Request, user=Depends(get_current_user)): +async def get_admin_details( + request: Request, user=Depends(get_current_user), db: Session = Depends(get_session) +): if request.app.state.config.SHOW_ADMIN_DETAILS: admin_email = request.app.state.config.ADMIN_EMAIL admin_name = None @@ -903,11 +951,11 @@ async def get_admin_details(request: Request, user=Depends(get_current_user)): log.info(f"Admin details - Email: {admin_email}, Name: {admin_name}") if admin_email: - admin = Users.get_user_by_email(admin_email) + admin = Users.get_user_by_email(admin_email, db=db) if admin: admin_name = admin.name else: - admin = Users.get_first_user() + admin = Users.get_first_user(db=db) if admin: admin_email = admin.email admin_name = admin.name @@ -1149,7 +1197,9 @@ async def update_ldap_config( # create api key @router.post("/api_key", response_model=ApiKey) -async def generate_api_key(request: Request, user=Depends(get_current_user)): +async def generate_api_key( + request: Request, user=Depends(get_current_user), db: Session = Depends(get_session) +): if not request.app.state.config.ENABLE_API_KEYS or not has_permission( user.id, "features.api_keys", request.app.state.config.USER_PERMISSIONS ): @@ -1159,7 +1209,7 @@ async def generate_api_key(request: Request, user=Depends(get_current_user)): ) api_key = create_api_key() - success = Users.update_user_api_key_by_id(user.id, api_key) + success = Users.update_user_api_key_by_id(user.id, api_key, db=db) if success: return { @@ -1171,14 +1221,18 @@ async def generate_api_key(request: Request, user=Depends(get_current_user)): # delete api key @router.delete("/api_key", response_model=bool) -async def delete_api_key(user=Depends(get_current_user)): - return Users.delete_user_api_key_by_id(user.id) +async def delete_api_key( + user=Depends(get_current_user), db: Session = Depends(get_session) +): + return Users.delete_user_api_key_by_id(user.id, db=db) # get api key @router.get("/api_key", response_model=ApiKey) -async def get_api_key(user=Depends(get_current_user)): - api_key = Users.get_user_api_key_by_id(user.id) +async def get_api_key( + user=Depends(get_current_user), db: Session = Depends(get_session) +): + api_key = Users.get_user_api_key_by_id(user.id, db=db) if api_key: return { "api_key": api_key, diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 684f929134..c98e119da5 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -1,6 +1,7 @@ import json import logging from typing import Optional +from sqlalchemy.orm import Session import asyncio from fastapi.responses import StreamingResponse @@ -23,6 +24,7 @@ from open_webui.models.chats import ( ) from open_webui.models.tags import TagModel, Tags from open_webui.models.folders import Folders +from open_webui.internal.db import get_session from open_webui.config import ENABLE_ADMIN_CHAT_ACCESS, ENABLE_ADMIN_EXPORT from open_webui.constants import ERROR_MESSAGES @@ -49,6 +51,7 @@ def get_session_user_chat_list( page: Optional[int] = None, include_pinned: Optional[bool] = False, include_folders: Optional[bool] = False, + db: Session = Depends(get_session), ): try: if page is not None: @@ -61,10 +64,14 @@ def get_session_user_chat_list( include_pinned=include_pinned, skip=skip, limit=limit, + db=db, ) else: return Chats.get_chat_title_id_list_by_user_id( - user.id, include_folders=include_folders, include_pinned=include_pinned + user.id, + include_folders=include_folders, + include_pinned=include_pinned, + db=db, ) except Exception as e: log.exception(e) @@ -84,12 +91,13 @@ def get_session_user_chat_usage_stats( items_per_page: Optional[int] = 50, page: Optional[int] = 1, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): try: limit = items_per_page skip = (page - 1) * limit - result = Chats.get_chats_by_user_id(user.id, skip=skip, limit=limit) + result = Chats.get_chats_by_user_id(user.id, skip=skip, limit=limit, db=db) chats = result.items total = result.total @@ -216,6 +224,7 @@ class ChatStatsExportList(BaseModel): def _process_chat_for_export(chat) -> Optional[ChatStatsExport]: try: + def get_message_content_length(message): content = message.get("content", "") if isinstance(content, str): @@ -348,7 +357,9 @@ def _process_chat_for_export(chat) -> Optional[ChatStatsExport]: return None -def calculate_chat_stats(user_id, skip=0, limit=10, filter=None): +def calculate_chat_stats( + user_id, skip=0, limit=10, filter=None, db: Optional[Session] = None +): if filter is None: filter = {} @@ -357,6 +368,7 @@ def calculate_chat_stats(user_id, skip=0, limit=10, filter=None): skip=skip, limit=limit, filter=filter, + db=db, ) chat_stats_export_list = [] @@ -368,14 +380,21 @@ def calculate_chat_stats(user_id, skip=0, limit=10, filter=None): return chat_stats_export_list, result.total -async def generate_chat_stats_jsonl_generator(user_id, filter): +async def generate_chat_stats_jsonl_generator( + user_id, filter, db: Optional[Session] = None +): skip = 0 limit = CHAT_EXPORT_PAGE_ITEM_COUNT while True: # Use asyncio.to_thread to make the blocking DB call non-blocking result = await asyncio.to_thread( - Chats.get_chats_by_user_id, user_id, filter=filter, skip=skip, limit=limit + Chats.get_chats_by_user_id, + user_id, + filter=filter, + skip=skip, + limit=limit, + db=db, ) if not result.items: break @@ -386,7 +405,7 @@ async def generate_chat_stats_jsonl_generator(user_id, filter): if chat_stat: yield chat_stat.model_dump_json() + "\n" except Exception as e: - log.exception(f"Error processing chat {chat.id}: {e}") + log.exception(f"Error processing chat {chat.id}: {e}") skip += limit @@ -400,6 +419,7 @@ async def export_chat_stats( page: Optional[int] = 1, stream: bool = False, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): # Check if the user has permission to share/export chats if (user.role != "admin") and ( @@ -415,7 +435,7 @@ async def export_chat_stats( filter = {"order_by": "created_at", "direction": "asc"} if chat_id: - chat = Chats.get_chat_by_id(chat_id) + chat = Chats.get_chat_by_id(chat_id, db=db) if chat: filter["start_time"] = chat.created_at @@ -426,7 +446,7 @@ async def export_chat_stats( if stream: return StreamingResponse( - generate_chat_stats_jsonl_generator(user.id, filter), + generate_chat_stats_jsonl_generator(user.id, filter, db=db), media_type="application/x-ndjson", headers={ "Content-Disposition": f"attachment; filename=chat-stats-export-{user.id}.jsonl" @@ -437,7 +457,7 @@ async def export_chat_stats( skip = (page - 1) * limit chat_stats_export_list, total = await asyncio.to_thread( - calculate_chat_stats, user.id, skip, limit, filter + calculate_chat_stats, user.id, skip, limit, filter, db=db ) return ChatStatsExportList( @@ -452,7 +472,11 @@ async def export_chat_stats( @router.delete("/", response_model=bool) -async def delete_all_user_chats(request: Request, user=Depends(get_verified_user)): +async def delete_all_user_chats( + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if user.role == "user" and not has_permission( user.id, "chat.delete", request.app.state.config.USER_PERMISSIONS @@ -462,7 +486,7 @@ async def delete_all_user_chats(request: Request, user=Depends(get_verified_user detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - result = Chats.delete_chats_by_user_id(user.id) + result = Chats.delete_chats_by_user_id(user.id, db=db) return result @@ -479,6 +503,7 @@ async def get_user_chat_list_by_user_id( order_by: Optional[str] = None, direction: Optional[str] = None, user=Depends(get_admin_user), + db: Session = Depends(get_session), ): if not ENABLE_ADMIN_CHAT_ACCESS: raise HTTPException( @@ -501,7 +526,7 @@ async def get_user_chat_list_by_user_id( filter["direction"] = direction return Chats.get_chat_list_by_user_id( - user_id, include_archived=True, filter=filter, skip=skip, limit=limit + user_id, include_archived=True, filter=filter, skip=skip, limit=limit, db=db ) @@ -511,9 +536,13 @@ async def get_user_chat_list_by_user_id( @router.post("/new", response_model=Optional[ChatResponse]) -async def create_new_chat(form_data: ChatForm, user=Depends(get_verified_user)): +async def create_new_chat( + form_data: ChatForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): try: - chat = Chats.insert_new_chat(user.id, form_data) + chat = Chats.insert_new_chat(user.id, form_data, db=db) return ChatResponse(**chat.model_dump()) except Exception as e: log.exception(e) @@ -528,9 +557,13 @@ async def create_new_chat(form_data: ChatForm, user=Depends(get_verified_user)): @router.post("/import", response_model=list[ChatResponse]) -async def import_chats(form_data: ChatsImportForm, user=Depends(get_verified_user)): +async def import_chats( + form_data: ChatsImportForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): try: - chats = Chats.import_chats(user.id, form_data.chats) + chats = Chats.import_chats(user.id, form_data.chats, db=db) return chats except Exception as e: log.exception(e) @@ -546,7 +579,10 @@ async def import_chats(form_data: ChatsImportForm, user=Depends(get_verified_use @router.get("/search", response_model=list[ChatTitleIdResponse]) def search_user_chats( - text: str, page: Optional[int] = None, user=Depends(get_verified_user) + text: str, + page: Optional[int] = None, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if page is None: page = 1 @@ -557,7 +593,7 @@ def search_user_chats( chat_list = [ ChatTitleIdResponse(**chat.model_dump()) for chat in Chats.get_chats_by_user_id_and_search_text( - user.id, text, skip=skip, limit=limit + user.id, text, skip=skip, limit=limit, db=db ) ] @@ -566,9 +602,9 @@ def search_user_chats( if page == 1 and len(words) == 1 and words[0].startswith("tag:"): tag_id = words[0].replace("tag:", "") if len(chat_list) == 0: - if Tags.get_tag_by_name_and_user_id(tag_id, user.id): + if Tags.get_tag_by_name_and_user_id(tag_id, user.id, db=db): log.debug(f"deleting tag: {tag_id}") - Tags.delete_tag_by_name_and_user_id(tag_id, user.id) + Tags.delete_tag_by_name_and_user_id(tag_id, user.id, db=db) return chat_list @@ -579,23 +615,30 @@ def search_user_chats( @router.get("/folder/{folder_id}", response_model=list[ChatResponse]) -async def get_chats_by_folder_id(folder_id: str, user=Depends(get_verified_user)): +async def get_chats_by_folder_id( + folder_id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): folder_ids = [folder_id] children_folders = Folders.get_children_folders_by_id_and_user_id( - folder_id, user.id + folder_id, user.id, db=db ) if children_folders: folder_ids.extend([folder.id for folder in children_folders]) return [ ChatResponse(**chat.model_dump()) - for chat in Chats.get_chats_by_folder_ids_and_user_id(folder_ids, user.id) + for chat in Chats.get_chats_by_folder_ids_and_user_id( + folder_ids, user.id, db=db + ) ] @router.get("/folder/{folder_id}/list") async def get_chat_list_by_folder_id( - folder_id: str, page: Optional[int] = 1, user=Depends(get_verified_user) + folder_id: str, + page: Optional[int] = 1, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): try: limit = 10 @@ -604,7 +647,7 @@ async def get_chat_list_by_folder_id( return [ {"title": chat.title, "id": chat.id, "updated_at": chat.updated_at} for chat in Chats.get_chats_by_folder_id_and_user_id( - folder_id, user.id, skip=skip, limit=limit + folder_id, user.id, skip=skip, limit=limit, db=db ) ] @@ -621,10 +664,12 @@ async def get_chat_list_by_folder_id( @router.get("/pinned", response_model=list[ChatTitleIdResponse]) -async def get_user_pinned_chats(user=Depends(get_verified_user)): +async def get_user_pinned_chats( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): return [ ChatTitleIdResponse(**chat.model_dump()) - for chat in Chats.get_pinned_chats_by_user_id(user.id) + for chat in Chats.get_pinned_chats_by_user_id(user.id, db=db) ] @@ -634,10 +679,12 @@ async def get_user_pinned_chats(user=Depends(get_verified_user)): @router.get("/all", response_model=list[ChatResponse]) -async def get_user_chats(user=Depends(get_verified_user)): +async def get_user_chats( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): return [ ChatResponse(**chat.model_dump()) - for chat in Chats.get_chats_by_user_id(user.id) + for chat in Chats.get_chats_by_user_id(user.id, db=db) ] @@ -647,10 +694,12 @@ async def get_user_chats(user=Depends(get_verified_user)): @router.get("/all/archived", response_model=list[ChatResponse]) -async def get_user_archived_chats(user=Depends(get_verified_user)): +async def get_user_archived_chats( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): return [ ChatResponse(**chat.model_dump()) - for chat in Chats.get_archived_chats_by_user_id(user.id) + for chat in Chats.get_archived_chats_by_user_id(user.id, db=db) ] @@ -660,9 +709,11 @@ async def get_user_archived_chats(user=Depends(get_verified_user)): @router.get("/all/tags", response_model=list[TagModel]) -async def get_all_user_tags(user=Depends(get_verified_user)): +async def get_all_user_tags( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): try: - tags = Tags.get_tags_by_user_id(user.id) + tags = Tags.get_tags_by_user_id(user.id, db=db) return tags except Exception as e: log.exception(e) @@ -677,13 +728,15 @@ async def get_all_user_tags(user=Depends(get_verified_user)): @router.get("/all/db", response_model=list[ChatResponse]) -async def get_all_user_chats_in_db(user=Depends(get_admin_user)): +async def get_all_user_chats_in_db( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): if not ENABLE_ADMIN_EXPORT: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - return [ChatResponse(**chat.model_dump()) for chat in Chats.get_chats()] + return [ChatResponse(**chat.model_dump()) for chat in Chats.get_chats(db=db)] ############################ @@ -698,6 +751,7 @@ async def get_archived_session_user_chat_list( order_by: Optional[str] = None, direction: Optional[str] = None, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if page is None: page = 1 @@ -720,6 +774,7 @@ async def get_archived_session_user_chat_list( filter=filter, skip=skip, limit=limit, + db=db, ) ] @@ -732,8 +787,10 @@ async def get_archived_session_user_chat_list( @router.post("/archive/all", response_model=bool) -async def archive_all_chats(user=Depends(get_verified_user)): - return Chats.archive_all_chats_by_user_id(user.id) +async def archive_all_chats( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + return Chats.archive_all_chats_by_user_id(user.id, db=db) ############################ @@ -742,8 +799,10 @@ async def archive_all_chats(user=Depends(get_verified_user)): @router.post("/unarchive/all", response_model=bool) -async def unarchive_all_chats(user=Depends(get_verified_user)): - return Chats.unarchive_all_chats_by_user_id(user.id) +async def unarchive_all_chats( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + return Chats.unarchive_all_chats_by_user_id(user.id, db=db) ############################ @@ -752,16 +811,18 @@ async def unarchive_all_chats(user=Depends(get_verified_user)): @router.get("/share/{share_id}", response_model=Optional[ChatResponse]) -async def get_shared_chat_by_id(share_id: str, user=Depends(get_verified_user)): +async def get_shared_chat_by_id( + share_id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "pending": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND ) if user.role == "user" or (user.role == "admin" and not ENABLE_ADMIN_CHAT_ACCESS): - chat = Chats.get_chat_by_share_id(share_id) + chat = Chats.get_chat_by_share_id(share_id, db=db) elif user.role == "admin" and ENABLE_ADMIN_CHAT_ACCESS: - chat = Chats.get_chat_by_id(share_id) + chat = Chats.get_chat_by_id(share_id, db=db) if chat: return ChatResponse(**chat.model_dump()) @@ -788,13 +849,15 @@ class TagFilterForm(TagForm): @router.post("/tags", response_model=list[ChatTitleIdResponse]) async def get_user_chat_list_by_tag_name( - form_data: TagFilterForm, user=Depends(get_verified_user) + form_data: TagFilterForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): chats = Chats.get_chat_list_by_user_id_and_tag_name( - user.id, form_data.name, form_data.skip, form_data.limit + user.id, form_data.name, form_data.skip, form_data.limit, db=db ) if len(chats) == 0: - Tags.delete_tag_by_name_and_user_id(form_data.name, user.id) + Tags.delete_tag_by_name_and_user_id(form_data.name, user.id, db=db) return chats @@ -805,8 +868,10 @@ async def get_user_chat_list_by_tag_name( @router.get("/{id}", response_model=Optional[ChatResponse]) -async def get_chat_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +async def get_chat_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: return ChatResponse(**chat.model_dump()) @@ -824,12 +889,15 @@ async def get_chat_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}", response_model=Optional[ChatResponse]) async def update_chat_by_id( - id: str, form_data: ChatForm, user=Depends(get_verified_user) + id: str, + form_data: ChatForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: updated_chat = {**chat.chat, **form_data.chat} - chat = Chats.update_chat_by_id(id, updated_chat) + chat = Chats.update_chat_by_id(id, updated_chat, db=db) return ChatResponse(**chat.model_dump()) else: raise HTTPException( @@ -847,9 +915,13 @@ class MessageForm(BaseModel): @router.post("/{id}/messages/{message_id}", response_model=Optional[ChatResponse]) async def update_chat_message_by_id( - id: str, message_id: str, form_data: MessageForm, user=Depends(get_verified_user) + id: str, + message_id: str, + form_data: MessageForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - chat = Chats.get_chat_by_id(id) + chat = Chats.get_chat_by_id(id, db=db) if not chat: raise HTTPException( @@ -869,6 +941,7 @@ async def update_chat_message_by_id( { "content": form_data.content, }, + db=db, ) event_emitter = get_event_emitter( @@ -905,9 +978,13 @@ class EventForm(BaseModel): @router.post("/{id}/messages/{message_id}/event", response_model=Optional[bool]) async def send_chat_message_event_by_id( - id: str, message_id: str, form_data: EventForm, user=Depends(get_verified_user) + id: str, + message_id: str, + form_data: EventForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - chat = Chats.get_chat_by_id(id) + chat = Chats.get_chat_by_id(id, db=db) if not chat: raise HTTPException( @@ -945,14 +1022,19 @@ async def send_chat_message_event_by_id( @router.delete("/{id}", response_model=bool) -async def delete_chat_by_id(request: Request, id: str, user=Depends(get_verified_user)): +async def delete_chat_by_id( + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if user.role == "admin": - chat = Chats.get_chat_by_id(id) + chat = Chats.get_chat_by_id(id, db=db) for tag in chat.meta.get("tags", []): - if Chats.count_chats_by_tag_name_and_user_id(tag, user.id) == 1: - Tags.delete_tag_by_name_and_user_id(tag, user.id) + if Chats.count_chats_by_tag_name_and_user_id(tag, user.id, db=db) == 1: + Tags.delete_tag_by_name_and_user_id(tag, user.id, db=db) - result = Chats.delete_chat_by_id(id) + result = Chats.delete_chat_by_id(id, db=db) return result else: @@ -964,12 +1046,12 @@ async def delete_chat_by_id(request: Request, id: str, user=Depends(get_verified detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - chat = Chats.get_chat_by_id(id) + chat = Chats.get_chat_by_id(id, db=db) for tag in chat.meta.get("tags", []): - if Chats.count_chats_by_tag_name_and_user_id(tag, user.id) == 1: - Tags.delete_tag_by_name_and_user_id(tag, user.id) + if Chats.count_chats_by_tag_name_and_user_id(tag, user.id, db=db) == 1: + Tags.delete_tag_by_name_and_user_id(tag, user.id, db=db) - result = Chats.delete_chat_by_id_and_user_id(id, user.id) + result = Chats.delete_chat_by_id_and_user_id(id, user.id, db=db) return result @@ -979,8 +1061,10 @@ async def delete_chat_by_id(request: Request, id: str, user=Depends(get_verified @router.get("/{id}/pinned", response_model=Optional[bool]) -async def get_pinned_status_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +async def get_pinned_status_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: return chat.pinned else: @@ -995,10 +1079,12 @@ async def get_pinned_status_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/pin", response_model=Optional[ChatResponse]) -async def pin_chat_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +async def pin_chat_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: - chat = Chats.toggle_chat_pinned_by_id(id) + chat = Chats.toggle_chat_pinned_by_id(id, db=db) return chat else: raise HTTPException( @@ -1017,9 +1103,12 @@ class CloneForm(BaseModel): @router.post("/{id}/clone", response_model=Optional[ChatResponse]) async def clone_chat_by_id( - form_data: CloneForm, id: str, user=Depends(get_verified_user) + form_data: CloneForm, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: updated_chat = { **chat.chat, @@ -1040,6 +1129,7 @@ async def clone_chat_by_id( } ) ], + db=db, ) if chats: @@ -1062,12 +1152,14 @@ async def clone_chat_by_id( @router.post("/{id}/clone/shared", response_model=Optional[ChatResponse]) -async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)): +async def clone_shared_chat_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "admin": - chat = Chats.get_chat_by_id(id) + chat = Chats.get_chat_by_id(id, db=db) else: - chat = Chats.get_chat_by_share_id(id) + chat = Chats.get_chat_by_share_id(id, db=db) if chat: updated_chat = { @@ -1089,6 +1181,7 @@ async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)): } ) ], + db=db, ) if chats: @@ -1111,23 +1204,28 @@ async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/archive", response_model=Optional[ChatResponse]) -async def archive_chat_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +async def archive_chat_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: - chat = Chats.toggle_chat_archive_by_id(id) + chat = Chats.toggle_chat_archive_by_id(id, db=db) # Delete tags if chat is archived if chat.archived: for tag_id in chat.meta.get("tags", []): - if Chats.count_chats_by_tag_name_and_user_id(tag_id, user.id) == 0: + if ( + Chats.count_chats_by_tag_name_and_user_id(tag_id, user.id, db=db) + == 0 + ): log.debug(f"deleting tag: {tag_id}") - Tags.delete_tag_by_name_and_user_id(tag_id, user.id) + Tags.delete_tag_by_name_and_user_id(tag_id, user.id, db=db) else: for tag_id in chat.meta.get("tags", []): - tag = Tags.get_tag_by_name_and_user_id(tag_id, user.id) + tag = Tags.get_tag_by_name_and_user_id(tag_id, user.id, db=db) if tag is None: log.debug(f"inserting tag: {tag_id}") - tag = Tags.insert_new_tag(tag_id, user.id) + tag = Tags.insert_new_tag(tag_id, user.id, db=db) return ChatResponse(**chat.model_dump()) else: @@ -1142,7 +1240,12 @@ async def archive_chat_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/share", response_model=Optional[ChatResponse]) -async def share_chat_by_id(request: Request, id: str, user=Depends(get_verified_user)): +async def share_chat_by_id( + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if (user.role != "admin") and ( not has_permission( user.id, "chat.share", request.app.state.config.USER_PERMISSIONS @@ -1153,14 +1256,14 @@ async def share_chat_by_id(request: Request, id: str, user=Depends(get_verified_ detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: if chat.share_id: - shared_chat = Chats.update_shared_chat_by_chat_id(chat.id) + shared_chat = Chats.update_shared_chat_by_chat_id(chat.id, db=db) return ChatResponse(**shared_chat.model_dump()) - shared_chat = Chats.insert_shared_chat_by_chat_id(chat.id) + shared_chat = Chats.insert_shared_chat_by_chat_id(chat.id, db=db) if not shared_chat: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -1181,14 +1284,16 @@ async def share_chat_by_id(request: Request, id: str, user=Depends(get_verified_ @router.delete("/{id}/share", response_model=Optional[bool]) -async def delete_shared_chat_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +async def delete_shared_chat_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: if not chat.share_id: return False - result = Chats.delete_shared_chat_by_chat_id(id) - update_result = Chats.update_chat_share_id_by_id(id, None) + result = Chats.delete_shared_chat_by_chat_id(id, db=db) + update_result = Chats.update_chat_share_id_by_id(id, None, db=db) return result and update_result != None else: @@ -1209,12 +1314,15 @@ class ChatFolderIdForm(BaseModel): @router.post("/{id}/folder", response_model=Optional[ChatResponse]) async def update_chat_folder_id_by_id( - id: str, form_data: ChatFolderIdForm, user=Depends(get_verified_user) + id: str, + form_data: ChatFolderIdForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: chat = Chats.update_chat_folder_id_by_id_and_user_id( - id, user.id, form_data.folder_id + id, user.id, form_data.folder_id, db=db ) return ChatResponse(**chat.model_dump()) else: @@ -1229,11 +1337,13 @@ async def update_chat_folder_id_by_id( @router.get("/{id}/tags", response_model=list[TagModel]) -async def get_chat_tags_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +async def get_chat_tags_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: tags = chat.meta.get("tags", []) - return Tags.get_tags_by_ids_and_user_id(tags, user.id) + return Tags.get_tags_by_ids_and_user_id(tags, user.id, db=db) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND @@ -1247,9 +1357,12 @@ async def get_chat_tags_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/tags", response_model=list[TagModel]) async def add_tag_by_id_and_tag_name( - id: str, form_data: TagForm, user=Depends(get_verified_user) + id: str, + form_data: TagForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: tags = chat.meta.get("tags", []) tag_id = form_data.name.replace(" ", "_").lower() @@ -1262,12 +1375,12 @@ async def add_tag_by_id_and_tag_name( if tag_id not in tags: Chats.add_chat_tag_by_id_and_user_id_and_tag_name( - id, user.id, form_data.name + id, user.id, form_data.name, db=db ) - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) tags = chat.meta.get("tags", []) - return Tags.get_tags_by_ids_and_user_id(tags, user.id) + return Tags.get_tags_by_ids_and_user_id(tags, user.id, db=db) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() @@ -1281,18 +1394,26 @@ async def add_tag_by_id_and_tag_name( @router.delete("/{id}/tags", response_model=list[TagModel]) async def delete_tag_by_id_and_tag_name( - id: str, form_data: TagForm, user=Depends(get_verified_user) + id: str, + form_data: TagForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: - Chats.delete_tag_by_id_and_user_id_and_tag_name(id, user.id, form_data.name) + Chats.delete_tag_by_id_and_user_id_and_tag_name( + id, user.id, form_data.name, db=db + ) - if Chats.count_chats_by_tag_name_and_user_id(form_data.name, user.id) == 0: - Tags.delete_tag_by_name_and_user_id(form_data.name, user.id) + if ( + Chats.count_chats_by_tag_name_and_user_id(form_data.name, user.id, db=db) + == 0 + ): + Tags.delete_tag_by_name_and_user_id(form_data.name, user.id, db=db) - chat = Chats.get_chat_by_id_and_user_id(id, user.id) + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) tags = chat.meta.get("tags", []) - return Tags.get_tags_by_ids_and_user_id(tags, user.id) + return Tags.get_tags_by_ids_and_user_id(tags, user.id, db=db) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND @@ -1305,14 +1426,16 @@ async def delete_tag_by_id_and_tag_name( @router.delete("/{id}/tags/all", response_model=Optional[bool]) -async def delete_all_tags_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +async def delete_all_tags_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + chat = Chats.get_chat_by_id_and_user_id(id, user.id, db=db) if chat: - Chats.delete_all_tags_by_id_and_user_id(id, user.id) + Chats.delete_all_tags_by_id_and_user_id(id, user.id, db=db) for tag in chat.meta.get("tags", []): - if Chats.count_chats_by_tag_name_and_user_id(tag, user.id) == 0: - Tags.delete_tag_by_name_and_user_id(tag, user.id) + if Chats.count_chats_by_tag_name_and_user_id(tag, user.id, db=db) == 0: + Tags.delete_tag_by_name_and_user_id(tag, user.id, db=db) return True else: diff --git a/backend/open_webui/routers/evaluations.py b/backend/open_webui/routers/evaluations.py index cdcefe6ba7..a445be5f98 100644 --- a/backend/open_webui/routers/evaluations.py +++ b/backend/open_webui/routers/evaluations.py @@ -15,6 +15,8 @@ from open_webui.models.feedbacks import ( from open_webui.constants import ERROR_MESSAGES from open_webui.utils.auth import get_admin_user, get_verified_user +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session router = APIRouter() @@ -60,38 +62,50 @@ async def update_config( @router.get("/feedbacks/all", response_model=list[FeedbackResponse]) -async def get_all_feedbacks(user=Depends(get_admin_user)): - feedbacks = Feedbacks.get_all_feedbacks() +async def get_all_feedbacks( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): + feedbacks = Feedbacks.get_all_feedbacks(db=db) return feedbacks @router.get("/feedbacks/all/ids", response_model=list[FeedbackIdResponse]) -async def get_all_feedback_ids(user=Depends(get_admin_user)): - feedbacks = Feedbacks.get_all_feedbacks() +async def get_all_feedback_ids( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): + feedbacks = Feedbacks.get_all_feedbacks(db=db) return feedbacks @router.delete("/feedbacks/all") -async def delete_all_feedbacks(user=Depends(get_admin_user)): - success = Feedbacks.delete_all_feedbacks() +async def delete_all_feedbacks( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): + success = Feedbacks.delete_all_feedbacks(db=db) return success @router.get("/feedbacks/all/export", response_model=list[FeedbackModel]) -async def export_all_feedbacks(user=Depends(get_admin_user)): - feedbacks = Feedbacks.get_all_feedbacks() +async def export_all_feedbacks( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): + feedbacks = Feedbacks.get_all_feedbacks(db=db) return feedbacks @router.get("/feedbacks/user", response_model=list[FeedbackUserResponse]) -async def get_feedbacks(user=Depends(get_verified_user)): - feedbacks = Feedbacks.get_feedbacks_by_user_id(user.id) +async def get_feedbacks( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + feedbacks = Feedbacks.get_feedbacks_by_user_id(user.id, db=db) return feedbacks @router.delete("/feedbacks", response_model=bool) -async def delete_feedbacks(user=Depends(get_verified_user)): - success = Feedbacks.delete_feedbacks_by_user_id(user.id) +async def delete_feedbacks( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + success = Feedbacks.delete_feedbacks_by_user_id(user.id, db=db) return success @@ -104,6 +118,7 @@ async def get_feedbacks( direction: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_admin_user), + db: Session = Depends(get_session), ): limit = PAGE_ITEM_COUNT @@ -116,7 +131,7 @@ async def get_feedbacks( if direction: filter["direction"] = direction - result = Feedbacks.get_feedback_items(filter=filter, skip=skip, limit=limit) + result = Feedbacks.get_feedback_items(filter=filter, skip=skip, limit=limit, db=db) return result @@ -125,8 +140,11 @@ async def create_feedback( request: Request, form_data: FeedbackForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - feedback = Feedbacks.insert_new_feedback(user_id=user.id, form_data=form_data) + feedback = Feedbacks.insert_new_feedback( + user_id=user.id, form_data=form_data, db=db + ) if not feedback: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -137,11 +155,15 @@ async def create_feedback( @router.get("/feedback/{id}", response_model=FeedbackModel) -async def get_feedback_by_id(id: str, user=Depends(get_verified_user)): +async def get_feedback_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "admin": - feedback = Feedbacks.get_feedback_by_id(id=id) + feedback = Feedbacks.get_feedback_by_id(id=id, db=db) else: - feedback = Feedbacks.get_feedback_by_id_and_user_id(id=id, user_id=user.id) + feedback = Feedbacks.get_feedback_by_id_and_user_id( + id=id, user_id=user.id, db=db + ) if not feedback: raise HTTPException( @@ -153,13 +175,16 @@ async def get_feedback_by_id(id: str, user=Depends(get_verified_user)): @router.post("/feedback/{id}", response_model=FeedbackModel) async def update_feedback_by_id( - id: str, form_data: FeedbackForm, user=Depends(get_verified_user) + id: str, + form_data: FeedbackForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role == "admin": - feedback = Feedbacks.update_feedback_by_id(id=id, form_data=form_data) + feedback = Feedbacks.update_feedback_by_id(id=id, form_data=form_data, db=db) else: feedback = Feedbacks.update_feedback_by_id_and_user_id( - id=id, user_id=user.id, form_data=form_data + id=id, user_id=user.id, form_data=form_data, db=db ) if not feedback: @@ -171,11 +196,15 @@ async def update_feedback_by_id( @router.delete("/feedback/{id}") -async def delete_feedback_by_id(id: str, user=Depends(get_verified_user)): +async def delete_feedback_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "admin": - success = Feedbacks.delete_feedback_by_id(id=id) + success = Feedbacks.delete_feedback_by_id(id=id, db=db) else: - success = Feedbacks.delete_feedback_by_id_and_user_id(id=id, user_id=user.id) + success = Feedbacks.delete_feedback_by_id_and_user_id( + id=id, user_id=user.id, db=db + ) if not success: raise HTTPException( diff --git a/backend/open_webui/routers/files.py b/backend/open_webui/routers/files.py index 7f01537e66..311f5f7b84 100644 --- a/backend/open_webui/routers/files.py +++ b/backend/open_webui/routers/files.py @@ -22,6 +22,8 @@ from fastapi import ( ) from fastapi.responses import FileResponse, StreamingResponse +from sqlalchemy.orm import Session +from open_webui.internal.db import get_session, SessionLocal from open_webui.constants import ERROR_MESSAGES from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT @@ -62,9 +64,12 @@ router = APIRouter() # TODO: Optimize this function to use the knowledge_file table for faster lookups. def has_access_to_file( - file_id: Optional[str], access_type: str, user=Depends(get_verified_user) + file_id: Optional[str], + access_type: str, + user=Depends(get_verified_user), + db: Optional[Session] = None, ) -> bool: - file = Files.get_file_by_id(file_id) + file = Files.get_file_by_id(file_id, db=db) log.debug(f"Checking if user has {access_type} access to file") if not file: raise HTTPException( @@ -73,31 +78,33 @@ def has_access_to_file( ) # Check if the file is associated with any knowledge bases the user has access to - knowledge_bases = Knowledges.get_knowledges_by_file_id(file_id) - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user.id)} + knowledge_bases = Knowledges.get_knowledges_by_file_id(file_id, db=db) + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user.id, db=db) + } for knowledge_base in knowledge_bases: if knowledge_base.user_id == user.id or has_access( - user.id, access_type, knowledge_base.access_control, user_group_ids + user.id, access_type, knowledge_base.access_control, user_group_ids, db=db ): return True knowledge_base_id = file.meta.get("collection_name") if file.meta else None if knowledge_base_id: knowledge_bases = Knowledges.get_knowledge_bases_by_user_id( - user.id, access_type + user.id, access_type, db=db ) for knowledge_base in knowledge_bases: if knowledge_base.id == knowledge_base_id: return True # Check if the file is associated with any channels the user has access to - channels = Channels.get_channels_by_file_id_and_user_id(file_id, user.id) + channels = Channels.get_channels_by_file_id_and_user_id(file_id, user.id, db=db) if access_type == "read" and channels: return True # Check if the file is associated with any chats the user has access to # TODO: Granular access control for chats - chats = Chats.get_shared_chats_by_file_id(file_id) + chats = Chats.get_shared_chats_by_file_id(file_id, db=db) if chats: return True @@ -109,47 +116,78 @@ def has_access_to_file( ############################ -def process_uploaded_file(request, file, file_path, file_item, file_metadata, user): - try: - if file.content_type: - stt_supported_content_types = getattr( - request.app.state.config, "STT_SUPPORTED_CONTENT_TYPES", [] - ) +def process_uploaded_file( + request, + file, + file_path, + file_item, + file_metadata, + user, + db: Optional[Session] = None, +): + def _process_handler(db_session): + try: + if file.content_type: + stt_supported_content_types = getattr( + request.app.state.config, "STT_SUPPORTED_CONTENT_TYPES", [] + ) - if strict_match_mime_type(stt_supported_content_types, file.content_type): - file_path = Storage.get_file(file_path) - result = transcribe(request, file_path, file_metadata, user) + if strict_match_mime_type( + stt_supported_content_types, file.content_type + ): + file_path_processed = Storage.get_file(file_path) + result = transcribe( + request, file_path_processed, file_metadata, user + ) + process_file( + request, + ProcessFileForm( + file_id=file_item.id, content=result.get("text", "") + ), + user=user, + db=db_session, + ) + elif (not file.content_type.startswith(("image/", "video/"))) or ( + request.app.state.config.CONTENT_EXTRACTION_ENGINE == "external" + ): + process_file( + request, + ProcessFileForm(file_id=file_item.id), + user=user, + db=db_session, + ) + else: + raise Exception( + f"File type {file.content_type} is not supported for processing" + ) + else: + log.info( + f"File type {file.content_type} is not provided, but trying to process anyway" + ) process_file( request, - ProcessFileForm( - file_id=file_item.id, content=result.get("text", "") - ), + ProcessFileForm(file_id=file_item.id), user=user, + db=db_session, ) - elif (not file.content_type.startswith(("image/", "video/"))) or ( - request.app.state.config.CONTENT_EXTRACTION_ENGINE == "external" - ): - process_file(request, ProcessFileForm(file_id=file_item.id), user=user) - else: - raise Exception( - f"File type {file.content_type} is not supported for processing" - ) - else: - log.info( - f"File type {file.content_type} is not provided, but trying to process anyway" - ) - process_file(request, ProcessFileForm(file_id=file_item.id), user=user) - except Exception as e: - log.error(f"Error processing file: {file_item.id}") - Files.update_file_data_by_id( - file_item.id, - { - "status": "failed", - "error": str(e.detail) if hasattr(e, "detail") else str(e), - }, - ) + except Exception as e: + log.error(f"Error processing file: {file_item.id}") + Files.update_file_data_by_id( + file_item.id, + { + "status": "failed", + "error": str(e.detail) if hasattr(e, "detail") else str(e), + }, + db=db_session, + ) + + if db: + _process_handler(db) + else: + with SessionLocal() as db_session: + _process_handler(db_session) @router.post("/", response_model=FileModelResponse) @@ -161,6 +199,7 @@ def upload_file( process: bool = Query(True), process_in_background: bool = Query(True), user=Depends(get_verified_user), + db: Session = Depends(get_session), ): return upload_file_handler( request, @@ -170,6 +209,7 @@ def upload_file( process_in_background=process_in_background, user=user, background_tasks=background_tasks, + db=db, ) @@ -181,6 +221,7 @@ def upload_file_handler( process_in_background: bool = Query(True), user=Depends(get_verified_user), background_tasks: Optional[BackgroundTasks] = None, + db: Optional[Session] = None, ): log.info(f"file.content_type: {file.content_type} {process}") @@ -248,14 +289,17 @@ def upload_file_handler( }, } ), + db=db, ) if "channel_id" in file_metadata: channel = Channels.get_channel_by_id_and_user_id( - file_metadata["channel_id"], user.id + file_metadata["channel_id"], user.id, db=db ) if channel: - Channels.add_file_to_channel_by_id(channel.id, file_item.id, user.id) + Channels.add_file_to_channel_by_id( + channel.id, file_item.id, user.id, db=db + ) if process: if background_tasks and process_in_background: @@ -277,6 +321,7 @@ def upload_file_handler( file_item, file_metadata, user, + db=db, ) return {"status": True, **file_item.model_dump()} else: @@ -302,11 +347,15 @@ def upload_file_handler( @router.get("/", response_model=list[FileModelResponse]) -async def list_files(user=Depends(get_verified_user), content: bool = Query(True)): +async def list_files( + user=Depends(get_verified_user), + content: bool = Query(True), + db: Session = Depends(get_session), +): if user.role == "admin": - files = Files.get_files() + files = Files.get_files(db=db) else: - files = Files.get_files_by_user_id(user.id) + files = Files.get_files_by_user_id(user.id, db=db) if not content: for file in files: @@ -329,15 +378,16 @@ async def search_files( ), content: bool = Query(True), user=Depends(get_verified_user), + db: Session = Depends(get_session), ): """ Search for files by filename with support for wildcard patterns. """ # Get files according to user role if user.role == "admin": - files = Files.get_files() + files = Files.get_files(db=db) else: - files = Files.get_files_by_user_id(user.id) + files = Files.get_files_by_user_id(user.id, db=db) # Get matching files matching_files = [ @@ -364,8 +414,10 @@ async def search_files( @router.delete("/all") -async def delete_all_files(user=Depends(get_admin_user)): - result = Files.delete_all_files() +async def delete_all_files( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): + result = Files.delete_all_files(db=db) if result: try: Storage.delete_all_files() @@ -391,8 +443,10 @@ async def delete_all_files(user=Depends(get_admin_user)): @router.get("/{id}", response_model=Optional[FileModel]) -async def get_file_by_id(id: str, user=Depends(get_verified_user)): - file = Files.get_file_by_id(id) +async def get_file_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -403,7 +457,7 @@ async def get_file_by_id(id: str, user=Depends(get_verified_user)): if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "read", user) + or has_access_to_file(id, "read", user, db=db) ): return file else: @@ -415,9 +469,12 @@ async def get_file_by_id(id: str, user=Depends(get_verified_user)): @router.get("/{id}/process/status") async def get_file_process_status( - id: str, stream: bool = Query(False), user=Depends(get_verified_user) + id: str, + stream: bool = Query(False), + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - file = Files.get_file_by_id(id) + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -428,7 +485,7 @@ async def get_file_process_status( if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "read", user) + or has_access_to_file(id, "read", user, db=db) ): if stream: MAX_FILE_PROCESSING_DURATION = 3600 * 2 @@ -436,7 +493,7 @@ async def get_file_process_status( async def event_stream(file_item): if file_item: for _ in range(MAX_FILE_PROCESSING_DURATION): - file_item = Files.get_file_by_id(file_item.id) + file_item = Files.get_file_by_id(file_item.id, db=db) if file_item: data = file_item.model_dump().get("data", {}) status = data.get("status") @@ -476,8 +533,10 @@ async def get_file_process_status( @router.get("/{id}/data/content") -async def get_file_data_content_by_id(id: str, user=Depends(get_verified_user)): - file = Files.get_file_by_id(id) +async def get_file_data_content_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -488,7 +547,7 @@ async def get_file_data_content_by_id(id: str, user=Depends(get_verified_user)): if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "read", user) + or has_access_to_file(id, "read", user, db=db) ): return {"content": file.data.get("content", "")} else: @@ -509,9 +568,13 @@ class ContentForm(BaseModel): @router.post("/{id}/data/content/update") async def update_file_data_content_by_id( - request: Request, id: str, form_data: ContentForm, user=Depends(get_verified_user) + request: Request, + id: str, + form_data: ContentForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - file = Files.get_file_by_id(id) + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -522,7 +585,7 @@ async def update_file_data_content_by_id( if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "write", user) + or has_access_to_file(id, "write", user, db=db) ): try: process_file( @@ -530,7 +593,7 @@ async def update_file_data_content_by_id( ProcessFileForm(file_id=id, content=form_data.content), user=user, ) - file = Files.get_file_by_id(id=id) + file = Files.get_file_by_id(id=id, db=db) except Exception as e: log.exception(e) log.error(f"Error processing file: {file.id}") @@ -550,9 +613,12 @@ async def update_file_data_content_by_id( @router.get("/{id}/content") async def get_file_content_by_id( - id: str, user=Depends(get_verified_user), attachment: bool = Query(False) + id: str, + user=Depends(get_verified_user), + attachment: bool = Query(False), + db: Session = Depends(get_session), ): - file = Files.get_file_by_id(id) + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -563,7 +629,7 @@ async def get_file_content_by_id( if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "read", user) + or has_access_to_file(id, "read", user, db=db) ): try: file_path = Storage.get_file(file.path) @@ -619,8 +685,10 @@ async def get_file_content_by_id( @router.get("/{id}/content/html") -async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)): - file = Files.get_file_by_id(id) +async def get_html_file_content_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -628,7 +696,7 @@ async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)): detail=ERROR_MESSAGES.NOT_FOUND, ) - file_user = Users.get_user_by_id(file.user_id) + file_user = Users.get_user_by_id(file.user_id, db=db) if not file_user.role == "admin": raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -638,7 +706,7 @@ async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)): if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "read", user) + or has_access_to_file(id, "read", user, db=db) ): try: file_path = Storage.get_file(file.path) @@ -668,8 +736,10 @@ async def get_html_file_content_by_id(id: str, user=Depends(get_verified_user)): @router.get("/{id}/content/{file_name}") -async def get_file_content_by_id(id: str, user=Depends(get_verified_user)): - file = Files.get_file_by_id(id) +async def get_file_content_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -680,7 +750,7 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)): if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "read", user) + or has_access_to_file(id, "read", user, db=db) ): file_path = file.path @@ -730,8 +800,10 @@ async def get_file_content_by_id(id: str, user=Depends(get_verified_user)): @router.delete("/{id}") -async def delete_file_by_id(id: str, user=Depends(get_verified_user)): - file = Files.get_file_by_id(id) +async def delete_file_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + file = Files.get_file_by_id(id, db=db) if not file: raise HTTPException( @@ -742,10 +814,10 @@ async def delete_file_by_id(id: str, user=Depends(get_verified_user)): if ( file.user_id == user.id or user.role == "admin" - or has_access_to_file(id, "write", user) + or has_access_to_file(id, "write", user, db=db) ): - result = Files.delete_file_by_id(id) + result = Files.delete_file_by_id(id, db=db) if result: try: Storage.delete_file(file.path) diff --git a/backend/open_webui/routers/folders.py b/backend/open_webui/routers/folders.py index 32911fa509..1c9b2229cf 100644 --- a/backend/open_webui/routers/folders.py +++ b/backend/open_webui/routers/folders.py @@ -22,6 +22,8 @@ from open_webui.models.knowledge import Knowledges from open_webui.config import UPLOAD_DIR from open_webui.constants import ERROR_MESSAGES +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status, Request @@ -44,7 +46,11 @@ router = APIRouter() @router.get("/", response_model=list[FolderNameIdResponse]) -async def get_folders(request: Request, user=Depends(get_verified_user)): +async def get_folders( + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if request.app.state.config.ENABLE_FOLDERS is False: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, @@ -55,22 +61,23 @@ async def get_folders(request: Request, user=Depends(get_verified_user)): user.id, "features.folders", request.app.state.config.USER_PERMISSIONS, + db=db, ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - folders = Folders.get_folders_by_user_id(user.id) + folders = Folders.get_folders_by_user_id(user.id, db=db) # Verify folder data integrity folder_list = [] for folder in folders: if folder.parent_id and not Folders.get_folder_by_id_and_user_id( - folder.parent_id, user.id + folder.parent_id, user.id, db=db ): folder = Folders.update_folder_parent_id_by_id_and_user_id( - folder.id, user.id, None + folder.id, user.id, None, db=db ) if folder.data: @@ -80,12 +87,12 @@ async def get_folders(request: Request, user=Depends(get_verified_user)): if file.get("type") == "file": if Files.check_access_by_user_id( - file.get("id"), user.id, "read" + file.get("id"), user.id, "read", db=db ): valid_files.append(file) elif file.get("type") == "collection": if Knowledges.check_access_by_user_id( - file.get("id"), user.id, "read" + file.get("id"), user.id, "read", db=db ): valid_files.append(file) else: @@ -93,7 +100,7 @@ async def get_folders(request: Request, user=Depends(get_verified_user)): folder.data["files"] = valid_files Folders.update_folder_by_id_and_user_id( - folder.id, user.id, FolderUpdateForm(data=folder.data) + folder.id, user.id, FolderUpdateForm(data=folder.data), db=db ) folder_list.append(FolderNameIdResponse(**folder.model_dump())) @@ -107,9 +114,13 @@ async def get_folders(request: Request, user=Depends(get_verified_user)): @router.post("/") -def create_folder(form_data: FolderForm, user=Depends(get_verified_user)): +def create_folder( + form_data: FolderForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): folder = Folders.get_folder_by_parent_id_and_user_id_and_name( - None, user.id, form_data.name + None, user.id, form_data.name, db=db ) if folder: @@ -119,7 +130,7 @@ def create_folder(form_data: FolderForm, user=Depends(get_verified_user)): ) try: - folder = Folders.insert_new_folder(user.id, form_data) + folder = Folders.insert_new_folder(user.id, form_data, db=db) return folder except Exception as e: log.exception(e) @@ -136,8 +147,10 @@ def create_folder(form_data: FolderForm, user=Depends(get_verified_user)): @router.get("/{id}", response_model=Optional[FolderModel]) -async def get_folder_by_id(id: str, user=Depends(get_verified_user)): - folder = Folders.get_folder_by_id_and_user_id(id, user.id) +async def get_folder_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + folder = Folders.get_folder_by_id_and_user_id(id, user.id, db=db) if folder: return folder else: @@ -154,15 +167,18 @@ async def get_folder_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/update") async def update_folder_name_by_id( - id: str, form_data: FolderUpdateForm, user=Depends(get_verified_user) + id: str, + form_data: FolderUpdateForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - folder = Folders.get_folder_by_id_and_user_id(id, user.id) + folder = Folders.get_folder_by_id_and_user_id(id, user.id, db=db) if folder: if form_data.name is not None: # Check if folder with same name exists existing_folder = Folders.get_folder_by_parent_id_and_user_id_and_name( - folder.parent_id, user.id, form_data.name + folder.parent_id, user.id, form_data.name, db=db ) if existing_folder and existing_folder.id != id: raise HTTPException( @@ -171,7 +187,9 @@ async def update_folder_name_by_id( ) try: - folder = Folders.update_folder_by_id_and_user_id(id, user.id, form_data) + folder = Folders.update_folder_by_id_and_user_id( + id, user.id, form_data, db=db + ) return folder except Exception as e: log.exception(e) @@ -198,12 +216,15 @@ class FolderParentIdForm(BaseModel): @router.post("/{id}/update/parent") async def update_folder_parent_id_by_id( - id: str, form_data: FolderParentIdForm, user=Depends(get_verified_user) + id: str, + form_data: FolderParentIdForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - folder = Folders.get_folder_by_id_and_user_id(id, user.id) + folder = Folders.get_folder_by_id_and_user_id(id, user.id, db=db) if folder: existing_folder = Folders.get_folder_by_parent_id_and_user_id_and_name( - form_data.parent_id, user.id, folder.name + form_data.parent_id, user.id, folder.name, db=db ) if existing_folder: @@ -214,7 +235,7 @@ async def update_folder_parent_id_by_id( try: folder = Folders.update_folder_parent_id_by_id_and_user_id( - id, user.id, form_data.parent_id + id, user.id, form_data.parent_id, db=db ) return folder except Exception as e: @@ -242,13 +263,16 @@ class FolderIsExpandedForm(BaseModel): @router.post("/{id}/update/expanded") async def update_folder_is_expanded_by_id( - id: str, form_data: FolderIsExpandedForm, user=Depends(get_verified_user) + id: str, + form_data: FolderIsExpandedForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - folder = Folders.get_folder_by_id_and_user_id(id, user.id) + folder = Folders.get_folder_by_id_and_user_id(id, user.id, db=db) if folder: try: folder = Folders.update_folder_is_expanded_by_id_and_user_id( - id, user.id, form_data.is_expanded + id, user.id, form_data.is_expanded, db=db ) return folder except Exception as e: @@ -276,10 +300,11 @@ async def delete_folder_by_id( id: str, delete_contents: Optional[bool] = True, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - if Chats.count_chats_by_folder_id_and_user_id(id, user.id): + if Chats.count_chats_by_folder_id_and_user_id(id, user.id, db=db): chat_delete_permission = has_permission( - user.id, "chat.delete", request.app.state.config.USER_PERMISSIONS + user.id, "chat.delete", request.app.state.config.USER_PERMISSIONS, db=db ) if user.role != "admin" and not chat_delete_permission: raise HTTPException( @@ -288,19 +313,21 @@ async def delete_folder_by_id( ) folders = [] - folders.append(Folders.get_folder_by_id_and_user_id(id, user.id)) + folders.append(Folders.get_folder_by_id_and_user_id(id, user.id, db=db)) while folders: folder = folders.pop() if folder: try: - folder_ids = Folders.delete_folder_by_id_and_user_id(id, user.id) + folder_ids = Folders.delete_folder_by_id_and_user_id(id, user.id, db=db) for folder_id in folder_ids: if delete_contents: - Chats.delete_chats_by_user_id_and_folder_id(user.id, folder_id) + Chats.delete_chats_by_user_id_and_folder_id( + user.id, folder_id, db=db + ) else: Chats.move_chats_by_user_id_and_folder_id( - user.id, folder_id, None + user.id, folder_id, None, db=db ) return True @@ -314,7 +341,7 @@ async def delete_folder_by_id( finally: # Get all subfolders subfolders = Folders.get_folders_by_parent_id_and_user_id( - folder.id, user.id + folder.id, user.id, db=db ) folders.extend(subfolders) diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index 82321cb546..b6dd07d736 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -24,6 +24,8 @@ from open_webui.constants import ERROR_MESSAGES from fastapi import APIRouter, Depends, HTTPException, Request, status from open_webui.utils.auth import get_admin_user, get_verified_user from pydantic import BaseModel, HttpUrl +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session log = logging.getLogger(__name__) @@ -37,13 +39,13 @@ router = APIRouter() @router.get("/", response_model=list[FunctionResponse]) -async def get_functions(user=Depends(get_verified_user)): - return Functions.get_functions() +async def get_functions(user=Depends(get_verified_user), db: Session = Depends(get_session)): + return Functions.get_functions(db=db) @router.get("/list", response_model=list[FunctionUserResponse]) -async def get_function_list(user=Depends(get_admin_user)): - return Functions.get_function_list() +async def get_function_list(user=Depends(get_admin_user), db: Session = Depends(get_session)): + return Functions.get_function_list(db=db) ############################ @@ -52,8 +54,8 @@ async def get_function_list(user=Depends(get_admin_user)): @router.get("/export", response_model=list[FunctionModel | FunctionWithValvesModel]) -async def get_functions(include_valves: bool = False, user=Depends(get_admin_user)): - return Functions.get_functions(include_valves=include_valves) +async def get_functions(include_valves: bool = False, user=Depends(get_admin_user), db: Session = Depends(get_session)): + return Functions.get_functions(include_valves=include_valves, db=db) ############################ @@ -142,7 +144,7 @@ class SyncFunctionsForm(BaseModel): @router.post("/sync", response_model=list[FunctionWithValvesModel]) async def sync_functions( - request: Request, form_data: SyncFunctionsForm, user=Depends(get_admin_user) + request: Request, form_data: SyncFunctionsForm, user=Depends(get_admin_user), db: Session = Depends(get_session) ): try: for function in form_data.functions: @@ -164,7 +166,7 @@ async def sync_functions( ) raise e - return Functions.sync_functions(user.id, form_data.functions) + return Functions.sync_functions(user.id, form_data.functions, db=db) except Exception as e: log.exception(f"Failed to load a function: {e}") raise HTTPException( @@ -180,7 +182,7 @@ async def sync_functions( @router.post("/create", response_model=Optional[FunctionResponse]) async def create_new_function( - request: Request, form_data: FunctionForm, user=Depends(get_admin_user) + request: Request, form_data: FunctionForm, user=Depends(get_admin_user), db: Session = Depends(get_session) ): if not form_data.id.isidentifier(): raise HTTPException( @@ -190,7 +192,7 @@ async def create_new_function( form_data.id = form_data.id.lower() - function = Functions.get_function_by_id(form_data.id) + function = Functions.get_function_by_id(form_data.id, db=db) if function is None: try: form_data.content = replace_imports(form_data.content) @@ -203,13 +205,13 @@ async def create_new_function( FUNCTIONS = request.app.state.FUNCTIONS FUNCTIONS[form_data.id] = function_module - function = Functions.insert_new_function(user.id, function_type, form_data) + function = Functions.insert_new_function(user.id, function_type, form_data, db=db) function_cache_dir = CACHE_DIR / "functions" / form_data.id function_cache_dir.mkdir(parents=True, exist_ok=True) if function_type == "filter" and getattr(function_module, "toggle", None): - Functions.update_function_metadata_by_id(id, {"toggle": True}) + Functions.update_function_metadata_by_id(form_data.id, {"toggle": True}, db=db) if function: return function @@ -237,8 +239,8 @@ async def create_new_function( @router.get("/id/{id}", response_model=Optional[FunctionModel]) -async def get_function_by_id(id: str, user=Depends(get_admin_user)): - function = Functions.get_function_by_id(id) +async def get_function_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): + function = Functions.get_function_by_id(id, db=db) if function: return function @@ -255,11 +257,11 @@ async def get_function_by_id(id: str, user=Depends(get_admin_user)): @router.post("/id/{id}/toggle", response_model=Optional[FunctionModel]) -async def toggle_function_by_id(id: str, user=Depends(get_admin_user)): - function = Functions.get_function_by_id(id) +async def toggle_function_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): + function = Functions.get_function_by_id(id, db=db) if function: function = Functions.update_function_by_id( - id, {"is_active": not function.is_active} + id, {"is_active": not function.is_active}, db=db ) if function: @@ -282,11 +284,11 @@ async def toggle_function_by_id(id: str, user=Depends(get_admin_user)): @router.post("/id/{id}/toggle/global", response_model=Optional[FunctionModel]) -async def toggle_global_by_id(id: str, user=Depends(get_admin_user)): - function = Functions.get_function_by_id(id) +async def toggle_global_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): + function = Functions.get_function_by_id(id, db=db) if function: function = Functions.update_function_by_id( - id, {"is_global": not function.is_global} + id, {"is_global": not function.is_global}, db=db ) if function: @@ -310,7 +312,7 @@ async def toggle_global_by_id(id: str, user=Depends(get_admin_user)): @router.post("/id/{id}/update", response_model=Optional[FunctionModel]) async def update_function_by_id( - request: Request, id: str, form_data: FunctionForm, user=Depends(get_admin_user) + request: Request, id: str, form_data: FunctionForm, user=Depends(get_admin_user), db: Session = Depends(get_session) ): try: form_data.content = replace_imports(form_data.content) @@ -325,10 +327,10 @@ async def update_function_by_id( updated = {**form_data.model_dump(exclude={"id"}), "type": function_type} log.debug(updated) - function = Functions.update_function_by_id(id, updated) + function = Functions.update_function_by_id(id, updated, db=db) if function_type == "filter" and getattr(function_module, "toggle", None): - Functions.update_function_metadata_by_id(id, {"toggle": True}) + Functions.update_function_metadata_by_id(id, {"toggle": True}, db=db) if function: return function @@ -352,9 +354,9 @@ async def update_function_by_id( @router.delete("/id/{id}/delete", response_model=bool) async def delete_function_by_id( - request: Request, id: str, user=Depends(get_admin_user) + request: Request, id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) ): - result = Functions.delete_function_by_id(id) + result = Functions.delete_function_by_id(id, db=db) if result: FUNCTIONS = request.app.state.FUNCTIONS @@ -370,11 +372,11 @@ async def delete_function_by_id( @router.get("/id/{id}/valves", response_model=Optional[dict]) -async def get_function_valves_by_id(id: str, user=Depends(get_admin_user)): - function = Functions.get_function_by_id(id) +async def get_function_valves_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): + function = Functions.get_function_by_id(id, db=db) if function: try: - valves = Functions.get_function_valves_by_id(id) + valves = Functions.get_function_valves_by_id(id, db=db) return valves except Exception as e: raise HTTPException( @@ -395,9 +397,9 @@ async def get_function_valves_by_id(id: str, user=Depends(get_admin_user)): @router.get("/id/{id}/valves/spec", response_model=Optional[dict]) async def get_function_valves_spec_by_id( - request: Request, id: str, user=Depends(get_admin_user) + request: Request, id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) ): - function = Functions.get_function_by_id(id) + function = Functions.get_function_by_id(id, db=db) if function: function_module, function_type, frontmatter = get_function_module_from_cache( request, id @@ -421,9 +423,9 @@ async def get_function_valves_spec_by_id( @router.post("/id/{id}/valves/update", response_model=Optional[dict]) async def update_function_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_admin_user) + request: Request, id: str, form_data: dict, user=Depends(get_admin_user), db: Session = Depends(get_session) ): - function = Functions.get_function_by_id(id) + function = Functions.get_function_by_id(id, db=db) if function: function_module, function_type, frontmatter = get_function_module_from_cache( request, id @@ -437,7 +439,7 @@ async def update_function_valves_by_id( valves = Valves(**form_data) valves_dict = valves.model_dump(exclude_unset=True) - Functions.update_function_valves_by_id(id, valves_dict) + Functions.update_function_valves_by_id(id, valves_dict, db=db) return valves_dict except Exception as e: log.exception(f"Error updating function values by id {id}: {e}") @@ -464,11 +466,11 @@ async def update_function_valves_by_id( @router.get("/id/{id}/valves/user", response_model=Optional[dict]) -async def get_function_user_valves_by_id(id: str, user=Depends(get_verified_user)): - function = Functions.get_function_by_id(id) +async def get_function_user_valves_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + function = Functions.get_function_by_id(id, db=db) if function: try: - user_valves = Functions.get_user_valves_by_id_and_user_id(id, user.id) + user_valves = Functions.get_user_valves_by_id_and_user_id(id, user.id, db=db) return user_valves except Exception as e: raise HTTPException( @@ -484,9 +486,9 @@ async def get_function_user_valves_by_id(id: str, user=Depends(get_verified_user @router.get("/id/{id}/valves/user/spec", response_model=Optional[dict]) async def get_function_user_valves_spec_by_id( - request: Request, id: str, user=Depends(get_verified_user) + request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - function = Functions.get_function_by_id(id) + function = Functions.get_function_by_id(id, db=db) if function: function_module, function_type, frontmatter = get_function_module_from_cache( request, id @@ -505,9 +507,9 @@ async def get_function_user_valves_spec_by_id( @router.post("/id/{id}/valves/user/update", response_model=Optional[dict]) async def update_function_user_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_verified_user) + request: Request, id: str, form_data: dict, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - function = Functions.get_function_by_id(id) + function = Functions.get_function_by_id(id, db=db) if function: function_module, function_type, frontmatter = get_function_module_from_cache( @@ -522,7 +524,7 @@ async def update_function_user_valves_by_id( user_valves = UserValves(**form_data) user_valves_dict = user_valves.model_dump(exclude_unset=True) Functions.update_user_valves_by_id_and_user_id( - id, user.id, user_valves_dict + id, user.id, user_valves_dict, db=db ) return user_valves_dict except Exception as e: diff --git a/backend/open_webui/routers/groups.py b/backend/open_webui/routers/groups.py index 423f6b1c67..f1c567fe81 100755 --- a/backend/open_webui/routers/groups.py +++ b/backend/open_webui/routers/groups.py @@ -16,6 +16,9 @@ from open_webui.config import CACHE_DIR from open_webui.constants import ERROR_MESSAGES from fastapi import APIRouter, Depends, HTTPException, Request, status +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session + from open_webui.utils.auth import get_admin_user, get_verified_user @@ -29,7 +32,11 @@ router = APIRouter() @router.get("/", response_model=list[GroupResponse]) -async def get_groups(share: Optional[bool] = None, user=Depends(get_verified_user)): +async def get_groups( + share: Optional[bool] = None, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): filter = {} if user.role != "admin": @@ -38,7 +45,7 @@ async def get_groups(share: Optional[bool] = None, user=Depends(get_verified_use if share is not None: filter["share"] = share - groups = Groups.get_groups(filter=filter) + groups = Groups.get_groups(filter=filter, db=db) return groups @@ -49,13 +56,17 @@ async def get_groups(share: Optional[bool] = None, user=Depends(get_verified_use @router.post("/create", response_model=Optional[GroupResponse]) -async def create_new_group(form_data: GroupForm, user=Depends(get_admin_user)): +async def create_new_group( + form_data: GroupForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), +): try: - group = Groups.insert_new_group(user.id, form_data) + group = Groups.insert_new_group(user.id, form_data, db=db) if group: return GroupResponse( **group.model_dump(), - member_count=Groups.get_group_member_count_by_id(group.id), + member_count=Groups.get_group_member_count_by_id(group.id, db=db), ) else: raise HTTPException( @@ -76,12 +87,14 @@ async def create_new_group(form_data: GroupForm, user=Depends(get_admin_user)): @router.get("/id/{id}", response_model=Optional[GroupResponse]) -async def get_group_by_id(id: str, user=Depends(get_admin_user)): - group = Groups.get_group_by_id(id) +async def get_group_by_id( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): + group = Groups.get_group_by_id(id, db=db) if group: return GroupResponse( **group.model_dump(), - member_count=Groups.get_group_member_count_by_id(group.id), + member_count=Groups.get_group_member_count_by_id(group.id, db=db), ) else: raise HTTPException( @@ -101,13 +114,15 @@ class GroupExportResponse(GroupResponse): @router.get("/id/{id}/export", response_model=Optional[GroupExportResponse]) -async def export_group_by_id(id: str, user=Depends(get_admin_user)): - group = Groups.get_group_by_id(id) +async def export_group_by_id( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): + group = Groups.get_group_by_id(id, db=db) if group: return GroupExportResponse( **group.model_dump(), - member_count=Groups.get_group_member_count_by_id(group.id), - user_ids=Groups.get_group_user_ids_by_id(group.id), + member_count=Groups.get_group_member_count_by_id(group.id, db=db), + user_ids=Groups.get_group_user_ids_by_id(group.id, db=db), ) else: raise HTTPException( @@ -122,9 +137,11 @@ async def export_group_by_id(id: str, user=Depends(get_admin_user)): @router.post("/id/{id}/users", response_model=list[UserInfoResponse]) -async def get_users_in_group(id: str, user=Depends(get_admin_user)): +async def get_users_in_group( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): try: - users = Users.get_users_by_group_id(id) + users = Users.get_users_by_group_id(id, db=db) return users except Exception as e: log.exception(f"Error adding users to group {id}: {e}") @@ -141,14 +158,17 @@ async def get_users_in_group(id: str, user=Depends(get_admin_user)): @router.post("/id/{id}/update", response_model=Optional[GroupResponse]) async def update_group_by_id( - id: str, form_data: GroupUpdateForm, user=Depends(get_admin_user) + id: str, + form_data: GroupUpdateForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): try: - group = Groups.update_group_by_id(id, form_data) + group = Groups.update_group_by_id(id, form_data, db=db) if group: return GroupResponse( **group.model_dump(), - member_count=Groups.get_group_member_count_by_id(group.id), + member_count=Groups.get_group_member_count_by_id(group.id, db=db), ) else: raise HTTPException( @@ -170,17 +190,20 @@ async def update_group_by_id( @router.post("/id/{id}/users/add", response_model=Optional[GroupResponse]) async def add_user_to_group( - id: str, form_data: UserIdsForm, user=Depends(get_admin_user) + id: str, + form_data: UserIdsForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): try: if form_data.user_ids: - form_data.user_ids = Users.get_valid_user_ids(form_data.user_ids) + form_data.user_ids = Users.get_valid_user_ids(form_data.user_ids, db=db) - group = Groups.add_users_to_group(id, form_data.user_ids) + group = Groups.add_users_to_group(id, form_data.user_ids, db=db) if group: return GroupResponse( **group.model_dump(), - member_count=Groups.get_group_member_count_by_id(group.id), + member_count=Groups.get_group_member_count_by_id(group.id, db=db), ) else: raise HTTPException( @@ -197,14 +220,17 @@ async def add_user_to_group( @router.post("/id/{id}/users/remove", response_model=Optional[GroupResponse]) async def remove_users_from_group( - id: str, form_data: UserIdsForm, user=Depends(get_admin_user) + id: str, + form_data: UserIdsForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): try: - group = Groups.remove_users_from_group(id, form_data.user_ids) + group = Groups.remove_users_from_group(id, form_data.user_ids, db=db) if group: return GroupResponse( **group.model_dump(), - member_count=Groups.get_group_member_count_by_id(group.id), + member_count=Groups.get_group_member_count_by_id(group.id, db=db), ) else: raise HTTPException( @@ -225,9 +251,11 @@ async def remove_users_from_group( @router.delete("/id/{id}/delete", response_model=bool) -async def delete_group_by_id(id: str, user=Depends(get_admin_user)): +async def delete_group_by_id( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): try: - result = Groups.delete_group_by_id(id) + result = Groups.delete_group_by_id(id, db=db) if result: return result else: diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index 467f6f3896..0b322fa862 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -4,6 +4,8 @@ from fastapi import APIRouter, Depends, HTTPException, status, Request, Query from fastapi.concurrency import run_in_threadpool import logging +from sqlalchemy.orm import Session +from open_webui.internal.db import get_session from open_webui.models.groups import Groups from open_webui.models.knowledge import ( KnowledgeFileListResponse, @@ -52,21 +54,25 @@ class KnowledgeAccessListResponse(BaseModel): @router.get("/", response_model=KnowledgeAccessListResponse) -async def get_knowledge_bases(page: Optional[int] = 1, user=Depends(get_verified_user)): +async def get_knowledge_bases( + page: Optional[int] = 1, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): page = max(page, 1) limit = PAGE_ITEM_COUNT skip = (page - 1) * limit filter = {} if not user.role == "admin" or not BYPASS_ADMIN_ACCESS_CONTROL: - groups = Groups.get_groups_by_member_id(user.id) + groups = Groups.get_groups_by_member_id(user.id, db=db) if groups: filter["group_ids"] = [group.id for group in groups] filter["user_id"] = user.id result = Knowledges.search_knowledge_bases( - user.id, filter=filter, skip=skip, limit=limit + user.id, filter=filter, skip=skip, limit=limit, db=db ) return KnowledgeAccessListResponse( @@ -75,7 +81,9 @@ async def get_knowledge_bases(page: Optional[int] = 1, user=Depends(get_verified **knowledge_base.model_dump(), write_access=( user.id == knowledge_base.user_id - or has_access(user.id, "write", knowledge_base.access_control) + or has_access( + user.id, "write", knowledge_base.access_control, db=db + ) ), ) for knowledge_base in result.items @@ -90,6 +98,7 @@ async def search_knowledge_bases( view_option: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): page = max(page, 1) limit = PAGE_ITEM_COUNT @@ -102,14 +111,14 @@ async def search_knowledge_bases( filter["view_option"] = view_option if not user.role == "admin" or not BYPASS_ADMIN_ACCESS_CONTROL: - groups = Groups.get_groups_by_member_id(user.id) + groups = Groups.get_groups_by_member_id(user.id, db=db) if groups: filter["group_ids"] = [group.id for group in groups] filter["user_id"] = user.id result = Knowledges.search_knowledge_bases( - user.id, filter=filter, skip=skip, limit=limit + user.id, filter=filter, skip=skip, limit=limit, db=db ) return KnowledgeAccessListResponse( @@ -118,7 +127,9 @@ async def search_knowledge_bases( **knowledge_base.model_dump(), write_access=( user.id == knowledge_base.user_id - or has_access(user.id, "write", knowledge_base.access_control) + or has_access( + user.id, "write", knowledge_base.access_control, db=db + ) ), ) for knowledge_base in result.items @@ -132,6 +143,7 @@ async def search_knowledge_files( query: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): page = max(page, 1) limit = PAGE_ITEM_COUNT @@ -141,13 +153,15 @@ async def search_knowledge_files( if query: filter["query"] = query - groups = Groups.get_groups_by_member_id(user.id) + groups = Groups.get_groups_by_member_id(user.id, db=db) if groups: filter["group_ids"] = [group.id for group in groups] filter["user_id"] = user.id - return Knowledges.search_knowledge_files(filter=filter, skip=skip, limit=limit) + return Knowledges.search_knowledge_files( + filter=filter, skip=skip, limit=limit, db=db + ) ############################ @@ -157,10 +171,13 @@ async def search_knowledge_files( @router.post("/create", response_model=Optional[KnowledgeResponse]) async def create_new_knowledge( - request: Request, form_data: KnowledgeForm, user=Depends(get_verified_user) + request: Request, + form_data: KnowledgeForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "workspace.knowledge", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.knowledge", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -175,11 +192,12 @@ async def create_new_knowledge( user.id, "sharing.public_knowledge", request.app.state.config.USER_PERMISSIONS, + db=db, ) ): form_data.access_control = {} - knowledge = Knowledges.insert_new_knowledge(user.id, form_data) + knowledge = Knowledges.insert_new_knowledge(user.id, form_data, db=db) if knowledge: return knowledge @@ -196,20 +214,24 @@ async def create_new_knowledge( @router.post("/reindex", response_model=bool) -async def reindex_knowledge_files(request: Request, user=Depends(get_verified_user)): +async def reindex_knowledge_files( + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if user.role != "admin": raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, ) - knowledge_bases = Knowledges.get_knowledge_bases() + knowledge_bases = Knowledges.get_knowledge_bases(db=db) log.info(f"Starting reindexing for {len(knowledge_bases)} knowledge bases") for knowledge_base in knowledge_bases: try: - files = Knowledges.get_files_by_id(knowledge_base.id) + files = Knowledges.get_files_by_id(knowledge_base.id, db=db) try: if VECTOR_DB_CLIENT.has_collection(collection_name=knowledge_base.id): VECTOR_DB_CLIENT.delete_collection( @@ -229,6 +251,7 @@ async def reindex_knowledge_files(request: Request, user=Depends(get_verified_us file_id=file.id, collection_name=knowledge_base.id ), user=user, + db=db, ) except Exception as e: log.error( @@ -264,21 +287,23 @@ class KnowledgeFilesResponse(KnowledgeResponse): @router.get("/{id}", response_model=Optional[KnowledgeFilesResponse]) -async def get_knowledge_by_id(id: str, user=Depends(get_verified_user)): - knowledge = Knowledges.get_knowledge_by_id(id=id) +async def get_knowledge_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if knowledge: if ( user.role == "admin" or knowledge.user_id == user.id - or has_access(user.id, "read", knowledge.access_control) + or has_access(user.id, "read", knowledge.access_control, db=db) ): return KnowledgeFilesResponse( **knowledge.model_dump(), write_access=( user.id == knowledge.user_id - or has_access(user.id, "write", knowledge.access_control) + or has_access(user.id, "write", knowledge.access_control, db=db) ), ) else: @@ -299,8 +324,9 @@ async def update_knowledge_by_id( id: str, form_data: KnowledgeForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - knowledge = Knowledges.get_knowledge_by_id(id=id) + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -309,7 +335,7 @@ async def update_knowledge_by_id( # Is the user the original creator, in a group with write access, or an admin if ( knowledge.user_id != user.id - and not has_access(user.id, "write", knowledge.access_control) + and not has_access(user.id, "write", knowledge.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -325,15 +351,16 @@ async def update_knowledge_by_id( user.id, "sharing.public_knowledge", request.app.state.config.USER_PERMISSIONS, + db=db, ) ): form_data.access_control = {} - knowledge = Knowledges.update_knowledge_by_id(id=id, form_data=form_data) + knowledge = Knowledges.update_knowledge_by_id(id=id, form_data=form_data, db=db) if knowledge: return KnowledgeFilesResponse( **knowledge.model_dump(), - files=Knowledges.get_file_metadatas_by_id(knowledge.id), + files=Knowledges.get_file_metadatas_by_id(knowledge.id, db=db), ) else: raise HTTPException( @@ -356,9 +383,10 @@ async def get_knowledge_files_by_id( direction: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - knowledge = Knowledges.get_knowledge_by_id(id=id) + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -368,7 +396,7 @@ async def get_knowledge_files_by_id( if not ( user.role == "admin" or knowledge.user_id == user.id - or has_access(user.id, "read", knowledge.access_control) + or has_access(user.id, "read", knowledge.access_control, db=db) ): raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -391,7 +419,7 @@ async def get_knowledge_files_by_id( filter["direction"] = direction return Knowledges.search_files_by_id( - id, user.id, filter=filter, skip=skip, limit=limit + id, user.id, filter=filter, skip=skip, limit=limit, db=db ) @@ -410,8 +438,9 @@ def add_file_to_knowledge_by_id( id: str, form_data: KnowledgeFileIdForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - knowledge = Knowledges.get_knowledge_by_id(id=id) + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -420,7 +449,7 @@ def add_file_to_knowledge_by_id( if ( knowledge.user_id != user.id - and not has_access(user.id, "write", knowledge.access_control) + and not has_access(user.id, "write", knowledge.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -428,7 +457,7 @@ def add_file_to_knowledge_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - file = Files.get_file_by_id(form_data.file_id) + file = Files.get_file_by_id(form_data.file_id, db=db) if not file: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -446,11 +475,12 @@ def add_file_to_knowledge_by_id( request, ProcessFileForm(file_id=form_data.file_id, collection_name=id), user=user, + db=db, ) # Add file to knowledge base Knowledges.add_file_to_knowledge_by_id( - knowledge_id=id, file_id=form_data.file_id, user_id=user.id + knowledge_id=id, file_id=form_data.file_id, user_id=user.id, db=db ) except Exception as e: log.debug(e) @@ -462,7 +492,7 @@ def add_file_to_knowledge_by_id( if knowledge: return KnowledgeFilesResponse( **knowledge.model_dump(), - files=Knowledges.get_file_metadatas_by_id(knowledge.id), + files=Knowledges.get_file_metadatas_by_id(knowledge.id, db=db), ) else: raise HTTPException( @@ -477,8 +507,9 @@ def update_file_from_knowledge_by_id( id: str, form_data: KnowledgeFileIdForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - knowledge = Knowledges.get_knowledge_by_id(id=id) + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -487,7 +518,7 @@ def update_file_from_knowledge_by_id( if ( knowledge.user_id != user.id - and not has_access(user.id, "write", knowledge.access_control) + and not has_access(user.id, "write", knowledge.access_control, db=db) and user.role != "admin" ): @@ -496,7 +527,7 @@ def update_file_from_knowledge_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - file = Files.get_file_by_id(form_data.file_id) + file = Files.get_file_by_id(form_data.file_id, db=db) if not file: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -514,6 +545,7 @@ def update_file_from_knowledge_by_id( request, ProcessFileForm(file_id=form_data.file_id, collection_name=id), user=user, + db=db, ) except Exception as e: raise HTTPException( @@ -524,7 +556,7 @@ def update_file_from_knowledge_by_id( if knowledge: return KnowledgeFilesResponse( **knowledge.model_dump(), - files=Knowledges.get_file_metadatas_by_id(knowledge.id), + files=Knowledges.get_file_metadatas_by_id(knowledge.id, db=db), ) else: raise HTTPException( @@ -544,8 +576,9 @@ def remove_file_from_knowledge_by_id( form_data: KnowledgeFileIdForm, delete_file: bool = Query(True), user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - knowledge = Knowledges.get_knowledge_by_id(id=id) + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -554,7 +587,7 @@ def remove_file_from_knowledge_by_id( if ( knowledge.user_id != user.id - and not has_access(user.id, "write", knowledge.access_control) + and not has_access(user.id, "write", knowledge.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -562,7 +595,7 @@ def remove_file_from_knowledge_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - file = Files.get_file_by_id(form_data.file_id) + file = Files.get_file_by_id(form_data.file_id, db=db) if not file: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -570,7 +603,7 @@ def remove_file_from_knowledge_by_id( ) Knowledges.remove_file_from_knowledge_by_id( - knowledge_id=id, file_id=form_data.file_id + knowledge_id=id, file_id=form_data.file_id, db=db ) # Remove content from the vector database @@ -599,12 +632,12 @@ def remove_file_from_knowledge_by_id( pass # Delete file from database - Files.delete_file_by_id(form_data.file_id) + Files.delete_file_by_id(form_data.file_id, db=db) if knowledge: return KnowledgeFilesResponse( **knowledge.model_dump(), - files=Knowledges.get_file_metadatas_by_id(knowledge.id), + files=Knowledges.get_file_metadatas_by_id(knowledge.id, db=db), ) else: raise HTTPException( @@ -619,8 +652,10 @@ def remove_file_from_knowledge_by_id( @router.delete("/{id}/delete", response_model=bool) -async def delete_knowledge_by_id(id: str, user=Depends(get_verified_user)): - knowledge = Knowledges.get_knowledge_by_id(id=id) +async def delete_knowledge_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -629,7 +664,7 @@ async def delete_knowledge_by_id(id: str, user=Depends(get_verified_user)): if ( knowledge.user_id != user.id - and not has_access(user.id, "write", knowledge.access_control) + and not has_access(user.id, "write", knowledge.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -640,7 +675,7 @@ async def delete_knowledge_by_id(id: str, user=Depends(get_verified_user)): log.info(f"Deleting knowledge base: {id} (name: {knowledge.name})") # Get all models - models = Models.get_all_models() + models = Models.get_all_models(db=db) log.info(f"Found {len(models)} models to check for knowledge base {id}") # Update models that reference this knowledge base @@ -664,7 +699,7 @@ async def delete_knowledge_by_id(id: str, user=Depends(get_verified_user)): access_control=model.access_control, is_active=model.is_active, ) - Models.update_model_by_id(model.id, model_form) + Models.update_model_by_id(model.id, model_form, db=db) # Clean up vector DB try: @@ -672,7 +707,7 @@ async def delete_knowledge_by_id(id: str, user=Depends(get_verified_user)): except Exception as e: log.debug(e) pass - result = Knowledges.delete_knowledge_by_id(id=id) + result = Knowledges.delete_knowledge_by_id(id=id, db=db) return result @@ -682,8 +717,10 @@ async def delete_knowledge_by_id(id: str, user=Depends(get_verified_user)): @router.post("/{id}/reset", response_model=Optional[KnowledgeResponse]) -async def reset_knowledge_by_id(id: str, user=Depends(get_verified_user)): - knowledge = Knowledges.get_knowledge_by_id(id=id) +async def reset_knowledge_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -692,7 +729,7 @@ async def reset_knowledge_by_id(id: str, user=Depends(get_verified_user)): if ( knowledge.user_id != user.id - and not has_access(user.id, "write", knowledge.access_control) + and not has_access(user.id, "write", knowledge.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -706,7 +743,7 @@ async def reset_knowledge_by_id(id: str, user=Depends(get_verified_user)): log.debug(e) pass - knowledge = Knowledges.reset_knowledge_by_id(id=id) + knowledge = Knowledges.reset_knowledge_by_id(id=id, db=db) return knowledge @@ -721,11 +758,12 @@ async def add_files_to_knowledge_batch( id: str, form_data: list[KnowledgeFileIdForm], user=Depends(get_verified_user), + db: Session = Depends(get_session), ): """ Add multiple files to a knowledge base """ - knowledge = Knowledges.get_knowledge_by_id(id=id) + knowledge = Knowledges.get_knowledge_by_id(id=id, db=db) if not knowledge: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -734,7 +772,7 @@ async def add_files_to_knowledge_batch( if ( knowledge.user_id != user.id - and not has_access(user.id, "write", knowledge.access_control) + and not has_access(user.id, "write", knowledge.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -746,7 +784,7 @@ async def add_files_to_knowledge_batch( log.info(f"files/batch/add - {len(form_data)} files") files: List[FileModel] = [] for form in form_data: - file = Files.get_file_by_id(form.file_id) + file = Files.get_file_by_id(form.file_id, db=db) if not file: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -760,6 +798,7 @@ async def add_files_to_knowledge_batch( request=request, form_data=BatchProcessFilesForm(files=files, collection_name=id), user=user, + db=db, ) except Exception as e: log.error( @@ -771,7 +810,7 @@ async def add_files_to_knowledge_batch( successful_file_ids = [r.file_id for r in result.results if r.status == "completed"] for file_id in successful_file_ids: Knowledges.add_file_to_knowledge_by_id( - knowledge_id=id, file_id=file_id, user_id=user.id + knowledge_id=id, file_id=file_id, user_id=user.id, db=db ) # If there were any errors, include them in the response @@ -779,7 +818,7 @@ async def add_files_to_knowledge_batch( error_details = [f"{err.file_id}: {err.error}" for err in result.errors] return KnowledgeFilesResponse( **knowledge.model_dump(), - files=Knowledges.get_file_metadatas_by_id(knowledge.id), + files=Knowledges.get_file_metadatas_by_id(knowledge.id, db=db), warnings={ "message": "Some files failed to process", "errors": error_details, @@ -788,5 +827,5 @@ async def add_files_to_knowledge_batch( return KnowledgeFilesResponse( **knowledge.model_dump(), - files=Knowledges.get_file_metadatas_by_id(knowledge.id), + files=Knowledges.get_file_metadatas_by_id(knowledge.id, db=db), ) diff --git a/backend/open_webui/routers/memories.py b/backend/open_webui/routers/memories.py index 9bb1ef518d..3747ab14ed 100644 --- a/backend/open_webui/routers/memories.py +++ b/backend/open_webui/routers/memories.py @@ -9,6 +9,10 @@ from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT from open_webui.utils.auth import get_verified_user +from open_webui.utils.auth import get_verified_user +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session + log = logging.getLogger(__name__) router = APIRouter() @@ -25,8 +29,8 @@ async def get_embeddings(request: Request): @router.get("/", response_model=list[MemoryModel]) -async def get_memories(user=Depends(get_verified_user)): - return Memories.get_memories_by_user_id(user.id) +async def get_memories(user=Depends(get_verified_user), db: Session = Depends(get_session)): + return Memories.get_memories_by_user_id(user.id, db=db) ############################ @@ -47,8 +51,9 @@ async def add_memory( request: Request, form_data: AddMemoryForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - memory = Memories.insert_new_memory(user.id, form_data.content) + memory = Memories.insert_new_memory(user.id, form_data.content, db=db) vector = await request.app.state.EMBEDDING_FUNCTION(memory.content, user=user) @@ -79,9 +84,9 @@ class QueryMemoryForm(BaseModel): @router.post("/query") async def query_memory( - request: Request, form_data: QueryMemoryForm, user=Depends(get_verified_user) + request: Request, form_data: QueryMemoryForm, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - memories = Memories.get_memories_by_user_id(user.id) + memories = Memories.get_memories_by_user_id(user.id, db=db) if not memories: raise HTTPException(status_code=404, detail="No memories found for user") @@ -101,11 +106,11 @@ async def query_memory( ############################ @router.post("/reset", response_model=bool) async def reset_memory_from_vector_db( - request: Request, user=Depends(get_verified_user) + request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) ): VECTOR_DB_CLIENT.delete_collection(f"user-memory-{user.id}") - memories = Memories.get_memories_by_user_id(user.id) + memories = Memories.get_memories_by_user_id(user.id, db=db) # Generate vectors in parallel vectors = await asyncio.gather( @@ -140,8 +145,8 @@ async def reset_memory_from_vector_db( @router.delete("/delete/user", response_model=bool) -async def delete_memory_by_user_id(user=Depends(get_verified_user)): - result = Memories.delete_memories_by_user_id(user.id) +async def delete_memory_by_user_id(user=Depends(get_verified_user), db: Session = Depends(get_session)): + result = Memories.delete_memories_by_user_id(user.id, db=db) if result: try: @@ -164,9 +169,10 @@ async def update_memory_by_id( request: Request, form_data: MemoryUpdateModel, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): memory = Memories.update_memory_by_id_and_user_id( - memory_id, user.id, form_data.content + memory_id, user.id, form_data.content, db=db ) if memory is None: raise HTTPException(status_code=404, detail="Memory not found") @@ -198,8 +204,8 @@ async def update_memory_by_id( @router.delete("/{memory_id}", response_model=bool) -async def delete_memory_by_id(memory_id: str, user=Depends(get_verified_user)): - result = Memories.delete_memory_by_id_and_user_id(memory_id, user.id) +async def delete_memory_by_id(memory_id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + result = Memories.delete_memory_by_id_and_user_id(memory_id, user.id, db=db) if result: VECTOR_DB_CLIENT.delete( diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index c5d8b6d102..d65a28cc1f 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -30,6 +30,8 @@ from fastapi.responses import FileResponse, StreamingResponse from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.access_control import has_access, has_permission from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL, STATIC_DIR +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session log = logging.getLogger(__name__) @@ -59,6 +61,7 @@ async def get_models( direction: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): limit = PAGE_ITEM_COUNT @@ -79,13 +82,13 @@ async def get_models( filter["direction"] = direction if not user.role == "admin" or not BYPASS_ADMIN_ACCESS_CONTROL: - groups = Groups.get_groups_by_member_id(user.id) + groups = Groups.get_groups_by_member_id(user.id, db=db) if groups: filter["group_ids"] = [group.id for group in groups] filter["user_id"] = user.id - return Models.search_models(user.id, filter=filter, skip=skip, limit=limit) + return Models.search_models(user.id, filter=filter, skip=skip, limit=limit, db=db) ########################### @@ -94,8 +97,8 @@ async def get_models( @router.get("/base", response_model=list[ModelResponse]) -async def get_base_models(user=Depends(get_admin_user)): - return Models.get_base_models() +async def get_base_models(user=Depends(get_admin_user), db: Session = Depends(get_session)): + return Models.get_base_models(db=db) ########################### @@ -104,11 +107,11 @@ async def get_base_models(user=Depends(get_admin_user)): @router.get("/tags", response_model=list[str]) -async def get_model_tags(user=Depends(get_verified_user)): +async def get_model_tags(user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: - models = Models.get_models() + models = Models.get_models(db=db) else: - models = Models.get_models_by_user_id(user.id) + models = Models.get_models_by_user_id(user.id, db=db) tags_set = set() for model in models: @@ -132,16 +135,17 @@ async def create_new_model( request: Request, form_data: ModelForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "workspace.models", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.models", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, ) - model = Models.get_model_by_id(form_data.id) + model = Models.get_model_by_id(form_data.id, db=db) if model: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -155,7 +159,7 @@ async def create_new_model( ) else: - model = Models.insert_new_model(form_data, user.id) + model = Models.insert_new_model(form_data, user.id, db=db) if model: return model else: @@ -171,9 +175,9 @@ async def create_new_model( @router.get("/export", response_model=list[ModelModel]) -async def export_models(request: Request, user=Depends(get_verified_user)): +async def export_models(request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role != "admin" and not has_permission( - user.id, "workspace.models_export", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.models_export", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -181,9 +185,9 @@ async def export_models(request: Request, user=Depends(get_verified_user)): ) if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: - return Models.get_models() + return Models.get_models(db=db) else: - return Models.get_models_by_user_id(user.id) + return Models.get_models_by_user_id(user.id, db=db) ############################ @@ -200,9 +204,10 @@ async def import_models( request: Request, user=Depends(get_verified_user), form_data: ModelsImportForm = (...), + db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "workspace.models_import", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.models_import", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -216,7 +221,7 @@ async def import_models( model_id = model_data.get("id") if model_id and is_valid_model_id(model_id): - existing_model = Models.get_model_by_id(model_id) + existing_model = Models.get_model_by_id(model_id, db=db) if existing_model: # Update existing model model_data["meta"] = model_data.get("meta", {}) @@ -225,13 +230,13 @@ async def import_models( updated_model = ModelForm( **{**existing_model.model_dump(), **model_data} ) - Models.update_model_by_id(model_id, updated_model) + Models.update_model_by_id(model_id, updated_model, db=db) else: # Insert new model model_data["meta"] = model_data.get("meta", {}) model_data["params"] = model_data.get("params", {}) new_model = ModelForm(**model_data) - Models.insert_new_model(user_id=user.id, form_data=new_model) + Models.insert_new_model(user_id=user.id, form_data=new_model, db=db) return True else: raise HTTPException(status_code=400, detail="Invalid JSON format") @@ -251,9 +256,9 @@ class SyncModelsForm(BaseModel): @router.post("/sync", response_model=list[ModelModel]) async def sync_models( - request: Request, form_data: SyncModelsForm, user=Depends(get_admin_user) + request: Request, form_data: SyncModelsForm, user=Depends(get_admin_user), db: Session = Depends(get_session) ): - return Models.sync_models(user.id, form_data.models) + return Models.sync_models(user.id, form_data.models, db=db) ########################### @@ -267,13 +272,13 @@ class ModelIdForm(BaseModel): # Note: We're not using the typical url path param here, but instead using a query parameter to allow '/' in the id @router.get("/model", response_model=Optional[ModelResponse]) -async def get_model_by_id(id: str, user=Depends(get_verified_user)): - model = Models.get_model_by_id(id) +async def get_model_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + model = Models.get_model_by_id(id, db=db) if model: if ( (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) or model.user_id == user.id - or has_access(user.id, "read", model.access_control) + or has_access(user.id, "read", model.access_control, db=db) ): return model else: @@ -289,8 +294,8 @@ async def get_model_by_id(id: str, user=Depends(get_verified_user)): @router.get("/model/profile/image") -async def get_model_profile_image(id: str, user=Depends(get_verified_user)): - model = Models.get_model_by_id(id) +async def get_model_profile_image(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + model = Models.get_model_by_id(id, db=db) # Cache-control headers to prevent stale cached images cache_headers = {"Cache-Control": "no-cache, must-revalidate"} @@ -330,15 +335,15 @@ async def get_model_profile_image(id: str, user=Depends(get_verified_user)): @router.post("/model/toggle", response_model=Optional[ModelResponse]) -async def toggle_model_by_id(id: str, user=Depends(get_verified_user)): - model = Models.get_model_by_id(id) +async def toggle_model_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + model = Models.get_model_by_id(id, db=db) if model: if ( user.role == "admin" or model.user_id == user.id - or has_access(user.id, "write", model.access_control) + or has_access(user.id, "write", model.access_control, db=db) ): - model = Models.toggle_model_by_id(id) + model = Models.toggle_model_by_id(id, db=db) if model: return model @@ -368,8 +373,9 @@ async def toggle_model_by_id(id: str, user=Depends(get_verified_user)): async def update_model_by_id( form_data: ModelForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - model = Models.get_model_by_id(form_data.id) + model = Models.get_model_by_id(form_data.id, db=db) if not model: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -378,7 +384,7 @@ async def update_model_by_id( if ( model.user_id != user.id - and not has_access(user.id, "write", model.access_control) + and not has_access(user.id, "write", model.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -386,7 +392,7 @@ async def update_model_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - model = Models.update_model_by_id(form_data.id, ModelForm(**form_data.model_dump())) + model = Models.update_model_by_id(form_data.id, ModelForm(**form_data.model_dump()), db=db) return model @@ -396,8 +402,8 @@ async def update_model_by_id( @router.post("/model/delete", response_model=bool) -async def delete_model_by_id(form_data: ModelIdForm, user=Depends(get_verified_user)): - model = Models.get_model_by_id(form_data.id) +async def delete_model_by_id(form_data: ModelIdForm, user=Depends(get_verified_user), db: Session = Depends(get_session)): + model = Models.get_model_by_id(form_data.id, db=db) if not model: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -407,18 +413,18 @@ async def delete_model_by_id(form_data: ModelIdForm, user=Depends(get_verified_u if ( user.role != "admin" and model.user_id != user.id - and not has_access(user.id, "write", model.access_control) + and not has_access(user.id, "write", model.access_control, db=db) ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, ) - result = Models.delete_model_by_id(form_data.id) + result = Models.delete_model_by_id(form_data.id, db=db) return result @router.delete("/delete/all", response_model=bool) -async def delete_all_models(user=Depends(get_admin_user)): - result = Models.delete_all_models() +async def delete_all_models(user=Depends(get_admin_user), db: Session = Depends(get_session)): + result = Models.delete_all_models(db=db) return result diff --git a/backend/open_webui/routers/notes.py b/backend/open_webui/routers/notes.py index 853e7848cc..98138a7535 100644 --- a/backend/open_webui/routers/notes.py +++ b/backend/open_webui/routers/notes.py @@ -28,6 +28,8 @@ from open_webui.constants import ERROR_MESSAGES from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.access_control import has_access, has_permission +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session log = logging.getLogger(__name__) @@ -49,10 +51,13 @@ class NoteItemResponse(BaseModel): @router.get("/", response_model=list[NoteItemResponse]) async def get_notes( - request: Request, page: Optional[int] = None, user=Depends(get_verified_user) + request: Request, + page: Optional[int] = None, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -69,10 +74,14 @@ async def get_notes( NoteUserResponse( **{ **note.model_dump(), - "user": UserResponse(**Users.get_user_by_id(note.user_id).model_dump()), + "user": UserResponse( + **Users.get_user_by_id(note.user_id, db=db).model_dump() + ), } ) - for note in Notes.get_notes_by_user_id(user.id, "read", skip=skip, limit=limit) + for note in Notes.get_notes_by_user_id( + user.id, "read", skip=skip, limit=limit, db=db + ) ] return notes @@ -87,9 +96,10 @@ async def search_notes( direction: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -115,13 +125,13 @@ async def search_notes( filter["direction"] = direction if not user.role == "admin" or not BYPASS_ADMIN_ACCESS_CONTROL: - groups = Groups.get_groups_by_member_id(user.id) + groups = Groups.get_groups_by_member_id(user.id, db=db) if groups: filter["group_ids"] = [group.id for group in groups] filter["user_id"] = user.id - return Notes.search_notes(user.id, filter, skip=skip, limit=limit) + return Notes.search_notes(user.id, filter, skip=skip, limit=limit, db=db) ############################ @@ -131,10 +141,13 @@ async def search_notes( @router.post("/create", response_model=Optional[NoteModel]) async def create_new_note( - request: Request, form_data: NoteForm, user=Depends(get_verified_user) + request: Request, + form_data: NoteForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -142,7 +155,7 @@ async def create_new_note( ) try: - note = Notes.insert_new_note(user.id, form_data) + note = Notes.insert_new_note(user.id, form_data, db=db) return note except Exception as e: log.exception(e) @@ -161,16 +174,21 @@ class NoteResponse(NoteModel): @router.get("/{id}", response_model=Optional[NoteResponse]) -async def get_note_by_id(request: Request, id: str, user=Depends(get_verified_user)): +async def get_note_by_id( + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if user.role != "admin" and not has_permission( - user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, ) - note = Notes.get_note_by_id(id) + note = Notes.get_note_by_id(id, db=db) if not note: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND @@ -178,7 +196,11 @@ async def get_note_by_id(request: Request, id: str, user=Depends(get_verified_us if user.role != "admin" and ( user.id != note.user_id - and (not has_access(user.id, type="read", access_control=note.access_control)) + and ( + not has_access( + user.id, type="read", access_control=note.access_control, db=db + ) + ) ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() @@ -188,7 +210,11 @@ async def get_note_by_id(request: Request, id: str, user=Depends(get_verified_us user.role == "admin" or (user.id == note.user_id) or has_access( - user.id, type="write", access_control=note.access_control, strict=False + user.id, + type="write", + access_control=note.access_control, + strict=False, + db=db, ) ) @@ -202,17 +228,21 @@ async def get_note_by_id(request: Request, id: str, user=Depends(get_verified_us @router.post("/{id}/update", response_model=Optional[NoteModel]) async def update_note_by_id( - request: Request, id: str, form_data: NoteForm, user=Depends(get_verified_user) + request: Request, + id: str, + form_data: NoteForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, ) - note = Notes.get_note_by_id(id) + note = Notes.get_note_by_id(id, db=db) if not note: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND @@ -220,7 +250,9 @@ async def update_note_by_id( if user.role != "admin" and ( user.id != note.user_id - and not has_access(user.id, type="write", access_control=note.access_control) + and not has_access( + user.id, type="write", access_control=note.access_control, db=db + ) ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() @@ -234,12 +266,13 @@ async def update_note_by_id( user.id, "sharing.public_notes", request.app.state.config.USER_PERMISSIONS, + db=db, ) ): form_data.access_control = {} try: - note = Notes.update_note_by_id(id, form_data) + note = Notes.update_note_by_id(id, form_data, db=db) await sio.emit( "note-events", note.model_dump(), @@ -260,16 +293,21 @@ async def update_note_by_id( @router.delete("/{id}/delete", response_model=bool) -async def delete_note_by_id(request: Request, id: str, user=Depends(get_verified_user)): +async def delete_note_by_id( + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if user.role != "admin" and not has_permission( - user.id, "features.notes", request.app.state.config.USER_PERMISSIONS + user.id, "features.notes", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.UNAUTHORIZED, ) - note = Notes.get_note_by_id(id) + note = Notes.get_note_by_id(id, db=db) if not note: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND @@ -277,14 +315,16 @@ async def delete_note_by_id(request: Request, id: str, user=Depends(get_verified if user.role != "admin" and ( user.id != note.user_id - and not has_access(user.id, type="write", access_control=note.access_control) + and not has_access( + user.id, type="write", access_control=note.access_control, db=db + ) ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() ) try: - note = Notes.delete_note_by_id(id) + note = Notes.delete_note_by_id(id, db=db) return True except Exception as e: log.exception(e) diff --git a/backend/open_webui/routers/prompts.py b/backend/open_webui/routers/prompts.py index 6a957f2547..4633cee86b 100644 --- a/backend/open_webui/routers/prompts.py +++ b/backend/open_webui/routers/prompts.py @@ -11,6 +11,8 @@ from open_webui.constants import ERROR_MESSAGES from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.access_control import has_access, has_permission from open_webui.config import BYPASS_ADMIN_ACCESS_CONTROL +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session router = APIRouter() @@ -20,21 +22,21 @@ router = APIRouter() @router.get("/", response_model=list[PromptModel]) -async def get_prompts(user=Depends(get_verified_user)): +async def get_prompts(user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: - prompts = Prompts.get_prompts() + prompts = Prompts.get_prompts(db=db) else: - prompts = Prompts.get_prompts_by_user_id(user.id, "read") + prompts = Prompts.get_prompts_by_user_id(user.id, "read", db=db) return prompts @router.get("/list", response_model=list[PromptUserResponse]) -async def get_prompt_list(user=Depends(get_verified_user)): +async def get_prompt_list(user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: - prompts = Prompts.get_prompts() + prompts = Prompts.get_prompts(db=db) else: - prompts = Prompts.get_prompts_by_user_id(user.id, "write") + prompts = Prompts.get_prompts_by_user_id(user.id, "write", db=db) return prompts @@ -46,16 +48,17 @@ async def get_prompt_list(user=Depends(get_verified_user)): @router.post("/create", response_model=Optional[PromptModel]) async def create_new_prompt( - request: Request, form_data: PromptForm, user=Depends(get_verified_user) + request: Request, form_data: PromptForm, user=Depends(get_verified_user), db: Session = Depends(get_session) ): if user.role != "admin" and not ( has_permission( - user.id, "workspace.prompts", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.prompts", request.app.state.config.USER_PERMISSIONS, db=db ) or has_permission( user.id, "workspace.prompts_import", request.app.state.config.USER_PERMISSIONS, + db=db, ) ): raise HTTPException( @@ -63,9 +66,9 @@ async def create_new_prompt( detail=ERROR_MESSAGES.UNAUTHORIZED, ) - prompt = Prompts.get_prompt_by_command(form_data.command) + prompt = Prompts.get_prompt_by_command(form_data.command, db=db) if prompt is None: - prompt = Prompts.insert_new_prompt(user.id, form_data) + prompt = Prompts.insert_new_prompt(user.id, form_data, db=db) if prompt: return prompt @@ -85,14 +88,14 @@ async def create_new_prompt( @router.get("/command/{command}", response_model=Optional[PromptModel]) -async def get_prompt_by_command(command: str, user=Depends(get_verified_user)): - prompt = Prompts.get_prompt_by_command(f"/{command}") +async def get_prompt_by_command(command: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + prompt = Prompts.get_prompt_by_command(f"/{command}", db=db) if prompt: if ( user.role == "admin" or prompt.user_id == user.id - or has_access(user.id, "read", prompt.access_control) + or has_access(user.id, "read", prompt.access_control, db=db) ): return prompt else: @@ -112,8 +115,9 @@ async def update_prompt_by_command( command: str, form_data: PromptForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - prompt = Prompts.get_prompt_by_command(f"/{command}") + prompt = Prompts.get_prompt_by_command(f"/{command}", db=db) if not prompt: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -123,7 +127,7 @@ async def update_prompt_by_command( # Is the user the original creator, in a group with write access, or an admin if ( prompt.user_id != user.id - and not has_access(user.id, "write", prompt.access_control) + and not has_access(user.id, "write", prompt.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -131,7 +135,7 @@ async def update_prompt_by_command( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - prompt = Prompts.update_prompt_by_command(f"/{command}", form_data) + prompt = Prompts.update_prompt_by_command(f"/{command}", form_data, db=db) if prompt: return prompt else: @@ -147,8 +151,8 @@ async def update_prompt_by_command( @router.delete("/command/{command}/delete", response_model=bool) -async def delete_prompt_by_command(command: str, user=Depends(get_verified_user)): - prompt = Prompts.get_prompt_by_command(f"/{command}") +async def delete_prompt_by_command(command: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + prompt = Prompts.get_prompt_by_command(f"/{command}", db=db) if not prompt: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -157,7 +161,7 @@ async def delete_prompt_by_command(command: str, user=Depends(get_verified_user) if ( prompt.user_id != user.id - and not has_access(user.id, "write", prompt.access_control) + and not has_access(user.id, "write", prompt.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -165,5 +169,5 @@ async def delete_prompt_by_command(command: str, user=Depends(get_verified_user) detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - result = Prompts.delete_prompt_by_command(f"/{command}") + result = Prompts.delete_prompt_by_command(f"/{command}", db=db) return result diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index a2c1cc80d5..c24ebf8d56 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -39,6 +39,8 @@ from langchain_core.documents import Document from open_webui.models.files import FileModel, FileUpdateForm, Files from open_webui.models.knowledge import Knowledges from open_webui.storage.provider import Storage +from open_webui.internal.db import get_session +from sqlalchemy.orm import Session from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT @@ -1484,14 +1486,15 @@ def process_file( request: Request, form_data: ProcessFileForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): """ Process a file and save its content to the vector database. """ if user.role == "admin": - file = Files.get_file_by_id(form_data.file_id) + file = Files.get_file_by_id(form_data.file_id, db=db) else: - file = Files.get_file_by_id_and_user_id(form_data.file_id, user.id) + file = Files.get_file_by_id_and_user_id(form_data.file_id, user.id, db=db) if file: try: @@ -1633,12 +1636,13 @@ def process_file( Files.update_file_data_by_id( file.id, {"content": text_content}, + db=db, ) hash = calculate_sha256_string(text_content) - Files.update_file_hash_by_id(file.id, hash) + Files.update_file_hash_by_id(file.id, hash, db=db) if request.app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL: - Files.update_file_data_by_id(file.id, {"status": "completed"}) + Files.update_file_data_by_id(file.id, {"status": "completed"}, db=db) return { "status": True, "collection_name": None, @@ -1667,11 +1671,13 @@ def process_file( { "collection_name": collection_name, }, + db=db, ) Files.update_file_data_by_id( file.id, {"status": "completed"}, + db=db, ) return { @@ -1690,6 +1696,7 @@ def process_file( Files.update_file_data_by_id( file.id, {"status": "failed"}, + db=db, ) if "No pandoc was found" in str(e): @@ -2417,10 +2424,10 @@ class DeleteForm(BaseModel): @router.post("/delete") -def delete_entries_from_collection(form_data: DeleteForm, user=Depends(get_admin_user)): +def delete_entries_from_collection(form_data: DeleteForm, user=Depends(get_admin_user), db: Session = Depends(get_session)): try: if VECTOR_DB_CLIENT.has_collection(collection_name=form_data.collection_name): - file = Files.get_file_by_id(form_data.file_id) + file = Files.get_file_by_id(form_data.file_id, db=db) hash = file.hash VECTOR_DB_CLIENT.delete( @@ -2436,9 +2443,9 @@ def delete_entries_from_collection(form_data: DeleteForm, user=Depends(get_admin @router.post("/reset/db") -def reset_vector_db(user=Depends(get_admin_user)): +def reset_vector_db(user=Depends(get_admin_user), db: Session = Depends(get_session)): VECTOR_DB_CLIENT.reset() - Knowledges.delete_all_knowledge() + Knowledges.delete_all_knowledge(db=db) @router.post("/reset/uploads") @@ -2496,6 +2503,7 @@ async def process_files_batch( request: Request, form_data: BatchProcessFilesForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ) -> BatchProcessFilesResponse: """ Process a batch of files and save them to the vector database. @@ -2558,7 +2566,7 @@ async def process_files_batch( # Update all files with collection name for file_update, file_result in zip(file_updates, file_results): - Files.update_file_by_id(id=file_result.file_id, form_data=file_update) + Files.update_file_by_id(id=file_result.file_id, form_data=file_update, db=db) file_result.status = "completed" except Exception as e: diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index fdcaf266fa..144f017edf 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -7,6 +7,8 @@ import aiohttp from open_webui.models.groups import Groups from pydantic import BaseModel, HttpUrl from fastapi import APIRouter, Depends, HTTPException, Request, status +from sqlalchemy.orm import Session +from open_webui.internal.db import get_session from open_webui.models.oauth_sessions import OAuthSessions @@ -51,11 +53,11 @@ def get_tool_module(request, tool_id, load_from_db=True): @router.get("/", response_model=list[ToolUserResponse]) -async def get_tools(request: Request, user=Depends(get_verified_user)): +async def get_tools(request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session)): tools = [] # Local Tools - for tool in Tools.get_tools(): + for tool in Tools.get_tools(db=db): tool_module = get_tool_module(request, tool.id) tools.append( ToolUserResponse( @@ -140,12 +142,12 @@ async def get_tools(request: Request, user=Depends(get_verified_user)): # Admin can see all tools return tools else: - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user.id)} + user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user.id, db=db)} tools = [ tool for tool in tools if tool.user_id == user.id - or has_access(user.id, "read", tool.access_control, user_group_ids) + or has_access(user.id, "read", tool.access_control, user_group_ids, db=db) ] return tools @@ -156,11 +158,11 @@ async def get_tools(request: Request, user=Depends(get_verified_user)): @router.get("/list", response_model=list[ToolUserResponse]) -async def get_tool_list(user=Depends(get_verified_user)): +async def get_tool_list(user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: - tools = Tools.get_tools() + tools = Tools.get_tools(db=db) else: - tools = Tools.get_tools_by_user_id(user.id, "write") + tools = Tools.get_tools_by_user_id(user.id, "write", db=db) return tools @@ -245,9 +247,9 @@ async def load_tool_from_url( @router.get("/export", response_model=list[ToolModel]) -async def export_tools(request: Request, user=Depends(get_verified_user)): +async def export_tools(request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role != "admin" and not has_permission( - user.id, "workspace.tools_export", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.tools_export", request.app.state.config.USER_PERMISSIONS, db=db ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -255,9 +257,9 @@ async def export_tools(request: Request, user=Depends(get_verified_user)): ) if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: - return Tools.get_tools() + return Tools.get_tools(db=db) else: - return Tools.get_tools_by_user_id(user.id, "read") + return Tools.get_tools_by_user_id(user.id, "read", db=db) ############################ @@ -270,13 +272,14 @@ async def create_new_tools( request: Request, form_data: ToolForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not ( has_permission( - user.id, "workspace.tools", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.tools", request.app.state.config.USER_PERMISSIONS, db=db ) or has_permission( - user.id, "workspace.tools_import", request.app.state.config.USER_PERMISSIONS + user.id, "workspace.tools_import", request.app.state.config.USER_PERMISSIONS, db=db ) ): raise HTTPException( @@ -292,7 +295,7 @@ async def create_new_tools( form_data.id = form_data.id.lower() - tools = Tools.get_tool_by_id(form_data.id) + tools = Tools.get_tool_by_id(form_data.id, db=db) if tools is None: try: form_data.content = replace_imports(form_data.content) @@ -305,7 +308,7 @@ async def create_new_tools( TOOLS[form_data.id] = tool_module specs = get_tool_specs(TOOLS[form_data.id]) - tools = Tools.insert_new_tool(user.id, form_data, specs) + tools = Tools.insert_new_tool(user.id, form_data, specs, db=db) tool_cache_dir = CACHE_DIR / "tools" / form_data.id tool_cache_dir.mkdir(parents=True, exist_ok=True) @@ -336,14 +339,14 @@ async def create_new_tools( @router.get("/id/{id}", response_model=Optional[ToolModel]) -async def get_tools_by_id(id: str, user=Depends(get_verified_user)): - tools = Tools.get_tool_by_id(id) +async def get_tools_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + tools = Tools.get_tool_by_id(id, db=db) if tools: if ( user.role == "admin" or tools.user_id == user.id - or has_access(user.id, "read", tools.access_control) + or has_access(user.id, "read", tools.access_control, db=db) ): return tools else: @@ -364,8 +367,9 @@ async def update_tools_by_id( id: str, form_data: ToolForm, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - tools = Tools.get_tool_by_id(id) + tools = Tools.get_tool_by_id(id, db=db) if not tools: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -375,7 +379,7 @@ async def update_tools_by_id( # Is the user the original creator, in a group with write access, or an admin if ( tools.user_id != user.id - and not has_access(user.id, "write", tools.access_control) + and not has_access(user.id, "write", tools.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -399,7 +403,7 @@ async def update_tools_by_id( } log.debug(updated) - tools = Tools.update_tool_by_id(id, updated) + tools = Tools.update_tool_by_id(id, updated, db=db) if tools: return tools @@ -423,9 +427,9 @@ async def update_tools_by_id( @router.delete("/id/{id}/delete", response_model=bool) async def delete_tools_by_id( - request: Request, id: str, user=Depends(get_verified_user) + request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - tools = Tools.get_tool_by_id(id) + tools = Tools.get_tool_by_id(id, db=db) if not tools: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -434,7 +438,7 @@ async def delete_tools_by_id( if ( tools.user_id != user.id - and not has_access(user.id, "write", tools.access_control) + and not has_access(user.id, "write", tools.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -442,7 +446,7 @@ async def delete_tools_by_id( detail=ERROR_MESSAGES.UNAUTHORIZED, ) - result = Tools.delete_tool_by_id(id) + result = Tools.delete_tool_by_id(id, db=db) if result: TOOLS = request.app.state.TOOLS if id in TOOLS: @@ -457,11 +461,11 @@ async def delete_tools_by_id( @router.get("/id/{id}/valves", response_model=Optional[dict]) -async def get_tools_valves_by_id(id: str, user=Depends(get_verified_user)): - tools = Tools.get_tool_by_id(id) +async def get_tools_valves_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + tools = Tools.get_tool_by_id(id, db=db) if tools: try: - valves = Tools.get_tool_valves_by_id(id) + valves = Tools.get_tool_valves_by_id(id, db=db) return valves except Exception as e: raise HTTPException( @@ -482,9 +486,9 @@ async def get_tools_valves_by_id(id: str, user=Depends(get_verified_user)): @router.get("/id/{id}/valves/spec", response_model=Optional[dict]) async def get_tools_valves_spec_by_id( - request: Request, id: str, user=Depends(get_verified_user) + request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - tools = Tools.get_tool_by_id(id) + tools = Tools.get_tool_by_id(id, db=db) if tools: if id in request.app.state.TOOLS: tools_module = request.app.state.TOOLS[id] @@ -510,9 +514,9 @@ async def get_tools_valves_spec_by_id( @router.post("/id/{id}/valves/update", response_model=Optional[dict]) async def update_tools_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_verified_user) + request: Request, id: str, form_data: dict, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - tools = Tools.get_tool_by_id(id) + tools = Tools.get_tool_by_id(id, db=db) if not tools: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -521,7 +525,7 @@ async def update_tools_valves_by_id( if ( tools.user_id != user.id - and not has_access(user.id, "write", tools.access_control) + and not has_access(user.id, "write", tools.access_control, db=db) and user.role != "admin" ): raise HTTPException( @@ -546,7 +550,7 @@ async def update_tools_valves_by_id( form_data = {k: v for k, v in form_data.items() if v is not None} valves = Valves(**form_data) valves_dict = valves.model_dump(exclude_unset=True) - Tools.update_tool_valves_by_id(id, valves_dict) + Tools.update_tool_valves_by_id(id, valves_dict, db=db) return valves_dict except Exception as e: log.exception(f"Failed to update tool valves by id {id}: {e}") @@ -562,11 +566,11 @@ async def update_tools_valves_by_id( @router.get("/id/{id}/valves/user", response_model=Optional[dict]) -async def get_tools_user_valves_by_id(id: str, user=Depends(get_verified_user)): - tools = Tools.get_tool_by_id(id) +async def get_tools_user_valves_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): + tools = Tools.get_tool_by_id(id, db=db) if tools: try: - user_valves = Tools.get_user_valves_by_id_and_user_id(id, user.id) + user_valves = Tools.get_user_valves_by_id_and_user_id(id, user.id, db=db) return user_valves except Exception as e: raise HTTPException( @@ -582,9 +586,9 @@ async def get_tools_user_valves_by_id(id: str, user=Depends(get_verified_user)): @router.get("/id/{id}/valves/user/spec", response_model=Optional[dict]) async def get_tools_user_valves_spec_by_id( - request: Request, id: str, user=Depends(get_verified_user) + request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - tools = Tools.get_tool_by_id(id) + tools = Tools.get_tool_by_id(id, db=db) if tools: if id in request.app.state.TOOLS: tools_module = request.app.state.TOOLS[id] @@ -605,9 +609,9 @@ async def get_tools_user_valves_spec_by_id( @router.post("/id/{id}/valves/user/update", response_model=Optional[dict]) async def update_tools_user_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_verified_user) + request: Request, id: str, form_data: dict, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - tools = Tools.get_tool_by_id(id) + tools = Tools.get_tool_by_id(id, db=db) if tools: if id in request.app.state.TOOLS: @@ -624,7 +628,7 @@ async def update_tools_user_valves_by_id( user_valves = UserValves(**form_data) user_valves_dict = user_valves.model_dump(exclude_unset=True) Tools.update_user_valves_by_id_and_user_id( - id, user.id, user_valves_dict + id, user.id, user_valves_dict, db=db ) return user_valves_dict except Exception as e: diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 12d1415059..a9686f1d15 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -1,5 +1,6 @@ import logging from typing import Optional +from sqlalchemy.orm import Session import base64 import io @@ -29,6 +30,7 @@ from open_webui.models.users import ( from open_webui.constants import ERROR_MESSAGES from open_webui.env import STATIC_DIR +from open_webui.internal.db import get_session from open_webui.utils.auth import ( @@ -60,6 +62,7 @@ async def get_users( direction: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_admin_user), + db: Session = Depends(get_session), ): limit = PAGE_ITEM_COUNT @@ -74,7 +77,9 @@ async def get_users( if direction: filter["direction"] = direction - result = Users.get_users(filter=filter, skip=skip, limit=limit) + filter["direction"] = direction + + result = Users.get_users(filter=filter, skip=skip, limit=limit, db=db) users = result["users"] total = result["total"] @@ -85,7 +90,8 @@ async def get_users( **{ **user.model_dump(), "group_ids": [ - group.id for group in Groups.get_groups_by_member_id(user.id) + group.id + for group in Groups.get_groups_by_member_id(user.id, db=db) ], } ) @@ -98,8 +104,9 @@ async def get_users( @router.get("/all", response_model=UserInfoListResponse) async def get_all_users( user=Depends(get_admin_user), + db: Session = Depends(get_session), ): - return Users.get_users() + return Users.get_users(db=db) @router.get("/search", response_model=UserInfoListResponse) @@ -109,16 +116,13 @@ async def search_users( direction: Optional[str] = None, page: Optional[int] = 1, user=Depends(get_verified_user), + db: Session = Depends(get_session), ): limit = PAGE_ITEM_COUNT page = max(1, page) skip = (page - 1) * limit - filter = {} - if query: - filter["query"] = query - filter = {} if query: filter["query"] = query @@ -127,7 +131,7 @@ async def search_users( if direction: filter["direction"] = direction - return Users.get_users(filter=filter, skip=skip, limit=limit) + return Users.get_users(filter=filter, skip=skip, limit=limit, db=db) ############################ @@ -136,8 +140,10 @@ async def search_users( @router.get("/groups") -async def get_user_groups(user=Depends(get_verified_user)): - return Groups.get_groups_by_member_id(user.id) +async def get_user_groups( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + return Groups.get_groups_by_member_id(user.id, db=db) ############################ @@ -146,9 +152,13 @@ async def get_user_groups(user=Depends(get_verified_user)): @router.get("/permissions") -async def get_user_permissisions(request: Request, user=Depends(get_verified_user)): +async def get_user_permissisions( + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): user_permissions = get_permissions( - user.id, request.app.state.config.USER_PERMISSIONS + user.id, request.app.state.config.USER_PERMISSIONS, db=db ) return user_permissions @@ -256,8 +266,10 @@ async def update_default_user_permissions( @router.get("/user/settings", response_model=Optional[UserSettings]) -async def get_user_settings_by_session_user(user=Depends(get_verified_user)): - user = Users.get_user_by_id(user.id) +async def get_user_settings_by_session_user( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + user = Users.get_user_by_id(user.id, db=db) if user: return user.settings else: @@ -274,7 +286,10 @@ async def get_user_settings_by_session_user(user=Depends(get_verified_user)): @router.post("/user/settings/update", response_model=UserSettings) async def update_user_settings_by_session_user( - request: Request, form_data: UserSettings, user=Depends(get_verified_user) + request: Request, + form_data: UserSettings, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): updated_user_settings = form_data.model_dump() if ( @@ -289,7 +304,7 @@ async def update_user_settings_by_session_user( # If the user is not an admin and does not have permission to use tool servers, remove the key updated_user_settings["ui"].pop("toolServers", None) - user = Users.update_user_settings_by_id(user.id, updated_user_settings) + user = Users.update_user_settings_by_id(user.id, updated_user_settings, db=db) if user: return user.settings else: @@ -305,8 +320,10 @@ async def update_user_settings_by_session_user( @router.get("/user/status") -async def get_user_status_by_session_user(user=Depends(get_verified_user)): - user = Users.get_user_by_id(user.id) +async def get_user_status_by_session_user( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + user = Users.get_user_by_id(user.id, db=db) if user: return user else: @@ -323,11 +340,13 @@ async def get_user_status_by_session_user(user=Depends(get_verified_user)): @router.post("/user/status/update") async def update_user_status_by_session_user( - form_data: UserStatus, user=Depends(get_verified_user) + form_data: UserStatus, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): - user = Users.get_user_by_id(user.id) + user = Users.get_user_by_id(user.id, db=db) if user: - user = Users.update_user_status_by_id(user.id, form_data) + user = Users.update_user_status_by_id(user.id, form_data, db=db) return user else: raise HTTPException( @@ -342,8 +361,10 @@ async def update_user_status_by_session_user( @router.get("/user/info", response_model=Optional[dict]) -async def get_user_info_by_session_user(user=Depends(get_verified_user)): - user = Users.get_user_by_id(user.id) +async def get_user_info_by_session_user( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): + user = Users.get_user_by_id(user.id, db=db) if user: return user.info else: @@ -360,14 +381,16 @@ async def get_user_info_by_session_user(user=Depends(get_verified_user)): @router.post("/user/info/update", response_model=Optional[dict]) async def update_user_info_by_session_user( - form_data: dict, user=Depends(get_verified_user) + form_data: dict, user=Depends(get_verified_user), db: Session = Depends(get_session) ): - user = Users.get_user_by_id(user.id) + user = Users.get_user_by_id(user.id, db=db) if user: if user.info is None: user.info = {} - user = Users.update_user_by_id(user.id, {"info": {**user.info, **form_data}}) + user = Users.update_user_by_id( + user.id, {"info": {**user.info, **form_data}}, db=db + ) if user: return user.info else: @@ -397,7 +420,9 @@ class UserActiveResponse(UserStatus): @router.get("/{user_id}", response_model=UserActiveResponse) -async def get_user_by_id(user_id: str, user=Depends(get_verified_user)): +async def get_user_by_id( + user_id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): # Check if user_id is a shared chat # If it is, get the user_id from the chat if user_id.startswith("shared-"): @@ -411,14 +436,14 @@ async def get_user_by_id(user_id: str, user=Depends(get_verified_user)): detail=ERROR_MESSAGES.USER_NOT_FOUND, ) - user = Users.get_user_by_id(user_id) + user = Users.get_user_by_id(user_id, db=db) if user: - groups = Groups.get_groups_by_member_id(user_id) + groups = Groups.get_groups_by_member_id(user_id, db=db) return UserActiveResponse( **{ **user.model_dump(), "groups": [{"id": group.id, "name": group.name} for group in groups], - "is_active": Users.is_user_active(user_id), + "is_active": Users.is_user_active(user_id, db=db), } ) else: @@ -429,8 +454,10 @@ async def get_user_by_id(user_id: str, user=Depends(get_verified_user)): @router.get("/{user_id}/oauth/sessions") -async def get_user_oauth_sessions_by_id(user_id: str, user=Depends(get_admin_user)): - sessions = OAuthSessions.get_sessions_by_user_id(user_id) +async def get_user_oauth_sessions_by_id( + user_id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): + sessions = OAuthSessions.get_sessions_by_user_id(user_id, db=db) if sessions and len(sessions) > 0: return sessions else: @@ -446,8 +473,10 @@ async def get_user_oauth_sessions_by_id(user_id: str, user=Depends(get_admin_use @router.get("/{user_id}/profile/image") -async def get_user_profile_image_by_id(user_id: str, user=Depends(get_verified_user)): - user = Users.get_user_by_id(user_id) +async def get_user_profile_image_by_id( + user_id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + user = Users.get_user_by_id(user_id, db=db) if user: if user.profile_image_url: # check if it's url or base64 @@ -484,9 +513,11 @@ async def get_user_profile_image_by_id(user_id: str, user=Depends(get_verified_u @router.get("/{user_id}/active", response_model=dict) -async def get_user_active_status_by_id(user_id: str, user=Depends(get_verified_user)): +async def get_user_active_status_by_id( + user_id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): return { - "active": Users.is_user_active(user_id), + "active": Users.is_user_active(user_id, db=db), } @@ -500,10 +531,11 @@ async def update_user_by_id( user_id: str, form_data: UserUpdateForm, session_user=Depends(get_admin_user), + db: Session = Depends(get_session), ): # Prevent modification of the primary admin user by other admins try: - first_user = Users.get_first_user() + first_user = Users.get_first_user(db=db) if first_user: if user_id == first_user.id: if session_user.id != user_id: @@ -527,11 +559,11 @@ async def update_user_by_id( detail="Could not verify primary admin status.", ) - user = Users.get_user_by_id(user_id) + user = Users.get_user_by_id(user_id, db=db) if user: if form_data.email.lower() != user.email: - email_user = Users.get_user_by_email(form_data.email.lower()) + email_user = Users.get_user_by_email(form_data.email.lower(), db=db) if email_user: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, @@ -545,9 +577,9 @@ async def update_user_by_id( raise HTTPException(400, detail=str(e)) hashed = get_password_hash(form_data.password) - Auths.update_user_password_by_id(user_id, hashed) + Auths.update_user_password_by_id(user_id, hashed, db=db) - Auths.update_email_by_id(user_id, form_data.email.lower()) + Auths.update_email_by_id(user_id, form_data.email.lower(), db=db) updated_user = Users.update_user_by_id( user_id, { @@ -556,6 +588,7 @@ async def update_user_by_id( "email": form_data.email.lower(), "profile_image_url": form_data.profile_image_url, }, + db=db, ) if updated_user: @@ -578,10 +611,12 @@ async def update_user_by_id( @router.delete("/{user_id}", response_model=bool) -async def delete_user_by_id(user_id: str, user=Depends(get_admin_user)): +async def delete_user_by_id( + user_id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): # Prevent deletion of the primary admin user try: - first_user = Users.get_first_user() + first_user = Users.get_first_user(db=db) if first_user and user_id == first_user.id: raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, @@ -595,7 +630,7 @@ async def delete_user_by_id(user_id: str, user=Depends(get_admin_user)): ) if user.id != user_id: - result = Auths.delete_auth_by_id(user_id) + result = Auths.delete_auth_by_id(user_id, db=db) if result: return True @@ -618,5 +653,7 @@ async def delete_user_by_id(user_id: str, user=Depends(get_admin_user)): @router.get("/{user_id}/groups") -async def get_user_groups_by_id(user_id: str, user=Depends(get_admin_user)): - return Groups.get_groups_by_member_id(user_id) +async def get_user_groups_by_id( + user_id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): + return Groups.get_groups_by_member_id(user_id, db=db) diff --git a/backend/open_webui/utils/access_control.py b/backend/open_webui/utils/access_control.py index 97d0b41491..7784f6efd7 100644 --- a/backend/open_webui/utils/access_control.py +++ b/backend/open_webui/utils/access_control.py @@ -28,6 +28,7 @@ def fill_missing_permissions( def get_permissions( user_id: str, default_permissions: Dict[str, Any], + db: Optional[Any] = None, ) -> Dict[str, Any]: """ Get all permissions for a user by combining the permissions of all groups the user is a member of. @@ -53,7 +54,7 @@ def get_permissions( ) # Use the most permissive value (True > False) return permissions - user_groups = Groups.get_groups_by_member_id(user_id) + user_groups = Groups.get_groups_by_member_id(user_id, db=db) # Deep copy default permissions to avoid modifying the original dict permissions = json.loads(json.dumps(default_permissions)) @@ -72,6 +73,7 @@ def has_permission( user_id: str, permission_key: str, default_permissions: Dict[str, Any] = {}, + db: Optional[Any] = None, ) -> bool: """ Check if a user has a specific permission by checking the group permissions @@ -92,7 +94,7 @@ def has_permission( permission_hierarchy = permission_key.split(".") # Retrieve user group permissions - user_groups = Groups.get_groups_by_member_id(user_id) + user_groups = Groups.get_groups_by_member_id(user_id, db=db) for group in user_groups: if get_permission(group.permissions or {}, permission_hierarchy): @@ -127,6 +129,7 @@ def has_access( access_control: Optional[dict] = None, user_group_ids: Optional[Set[str]] = None, strict: bool = True, + db: Optional[Any] = None, ) -> bool: if access_control is None: if strict: @@ -135,7 +138,7 @@ def has_access( return True if user_group_ids is None: - user_groups = Groups.get_groups_by_member_id(user_id) + user_groups = Groups.get_groups_by_member_id(user_id, db=db) user_group_ids = {group.id for group in user_groups} permitted_ids = get_permitted_group_and_user_ids(type, access_control) @@ -152,10 +155,10 @@ def has_access( # Get all users with access to a resource def get_users_with_access( - type: str = "write", access_control: Optional[dict] = None + type: str = "write", access_control: Optional[dict] = None, db: Optional[Any] = None ) -> list[UserModel]: if access_control is None: - result = Users.get_users(filter={"roles": ["!pending"]}) + result = Users.get_users(filter={"roles": ["!pending"]}, db=db) return result.get("users", []) permitted_ids = get_permitted_group_and_user_ids(type, access_control) @@ -167,8 +170,8 @@ def get_users_with_access( user_ids_with_access = set(permitted_user_ids) - group_user_ids_map = Groups.get_group_user_ids_by_ids(permitted_group_ids) + group_user_ids_map = Groups.get_group_user_ids_by_ids(permitted_group_ids, db=db) for user_ids in group_user_ids_map.values(): user_ids_with_access.update(user_ids) - return Users.get_users_by_user_ids(list(user_ids_with_access)) + return Users.get_users_by_user_ids(list(user_ids_with_access), db=db) diff --git a/backend/open_webui/utils/auth.py b/backend/open_webui/utils/auth.py index 6cd5fd2d1b..d89beb2ae5 100644 --- a/backend/open_webui/utils/auth.py +++ b/backend/open_webui/utils/auth.py @@ -42,6 +42,8 @@ from open_webui.env import ( from fastapi import BackgroundTasks, Depends, HTTPException, Request, Response, status from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer +from sqlalchemy.orm import Session +from open_webui.internal.db import get_session log = logging.getLogger(__name__) @@ -271,6 +273,7 @@ async def get_current_user( response: Response, background_tasks: BackgroundTasks, auth_token: HTTPAuthorizationCredentials = Depends(bearer_security), + db: Session = Depends(get_session), ): token = None @@ -285,7 +288,7 @@ async def get_current_user( # auth by api key if token.startswith("sk-"): - user = get_current_user_by_api_key(request, token) + user = get_current_user_by_api_key(request, token, db=db) # Add user info to current span current_span = trace.get_current_span() @@ -314,7 +317,7 @@ async def get_current_user( detail="Invalid token", ) - user = Users.get_user_by_id(data["id"]) + user = Users.get_user_by_id(data["id"], db=db) if user is None: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -364,8 +367,8 @@ async def get_current_user( raise e -def get_current_user_by_api_key(request, api_key: str): - user = Users.get_user_by_api_key(api_key) +def get_current_user_by_api_key(request, api_key: str, db: Session = None): + user = Users.get_user_by_api_key(api_key, db=db) if user is None: raise HTTPException( @@ -393,7 +396,7 @@ def get_current_user_by_api_key(request, api_key: str): current_span.set_attribute("client.user.role", user.role) current_span.set_attribute("client.auth.type", "api_key") - Users.update_last_active_by_id(user.id) + Users.update_last_active_by_id(user.id, db=db) return user diff --git a/backend/open_webui/utils/groups.py b/backend/open_webui/utils/groups.py index 0f15f27e2c..26fc5d8434 100644 --- a/backend/open_webui/utils/groups.py +++ b/backend/open_webui/utils/groups.py @@ -7,6 +7,7 @@ log = logging.getLogger(__name__) def apply_default_group_assignment( default_group_id: str, user_id: str, + db=None, ) -> None: """ Apply default group assignment to a user if default_group_id is provided. @@ -17,7 +18,7 @@ def apply_default_group_assignment( """ if default_group_id: try: - Groups.add_users_to_group(default_group_id, [user_id]) + Groups.add_users_to_group(default_group_id, [user_id], db=db) except Exception as e: log.error( f"Failed to add user {user_id} to default group {default_group_id}: {e}" diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index 13108f78e5..ffdd99b878 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -1336,7 +1336,7 @@ class OAuthManager: return await client.authorize_redirect(request, redirect_uri, **kwargs) - async def handle_callback(self, request, provider, response): + async def handle_callback(self, request, provider, response, db=None): if provider not in OAUTH_PROVIDERS: raise HTTPException(404) @@ -1461,20 +1461,20 @@ class OAuthManager: raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) # Check if the user exists - user = Users.get_user_by_oauth_sub(provider, sub) + user = Users.get_user_by_oauth_sub(provider, sub, db=db) if not user: # If the user does not exist, check if merging is enabled if auth_manager_config.OAUTH_MERGE_ACCOUNTS_BY_EMAIL: # Check if the user exists by email - user = Users.get_user_by_email(email) + user = Users.get_user_by_email(email, db=db) if user: # Update the user with the new oauth sub - Users.update_user_oauth_by_id(user.id, provider, sub) + Users.update_user_oauth_by_id(user.id, provider, sub, db=db) if user: determined_role = self.get_user_role(user, user_data) if user.role != determined_role: - Users.update_user_role_by_id(user.id, determined_role) + Users.update_user_role_by_id(user.id, determined_role, db=db) # Update the user object in memory as well, # to avoid problems with the ENABLE_OAUTH_GROUP_MANAGEMENT check below user.role = determined_role @@ -1491,14 +1491,14 @@ class OAuthManager: ) if processed_picture_url != user.profile_image_url: Users.update_user_profile_image_url_by_id( - user.id, processed_picture_url + user.id, processed_picture_url, db=db ) log.debug(f"Updated profile picture for user {user.email}") else: # If the user does not exist, check if signups are enabled if auth_manager_config.ENABLE_OAUTH_SIGNUP: # Check if an existing user with the same email already exists - existing_user = Users.get_user_by_email(email) + existing_user = Users.get_user_by_email(email, db=db) if existing_user: raise HTTPException(400, detail=ERROR_MESSAGES.EMAIL_TAKEN) @@ -1529,6 +1529,7 @@ class OAuthManager: profile_image_url=picture_url, role=self.get_user_role(None, user_data), oauth=oauth_data, + db=db, ) if auth_manager_config.WEBHOOK_URL: @@ -1544,8 +1545,7 @@ class OAuthManager: ) apply_default_group_assignment( - request.app.state.config.DEFAULT_GROUP_ID, - user.id, + request.app.state.config.DEFAULT_GROUP_ID, user.id, db=db ) else: @@ -1616,15 +1616,16 @@ class OAuthManager: token["expires_at"] = datetime.now().timestamp() + token["expires_in"] # Clean up any existing sessions for this user/provider first - sessions = OAuthSessions.get_sessions_by_user_id(user.id) + sessions = OAuthSessions.get_sessions_by_user_id(user.id, db=db) for session in sessions: if session.provider == provider: - OAuthSessions.delete_session_by_id(session.id) + OAuthSessions.delete_session_by_id(session.id, db=db) session = OAuthSessions.create_session( user_id=user.id, provider=provider, token=token, + db=db, ) response.set_cookie( From 93db0a4e575155875943af561ca51c92fc365778 Mon Sep 17 00:00:00 2001 From: Shirasawa <764798966@qq.com> Date: Mon, 29 Dec 2025 04:23:28 +0800 Subject: [PATCH 035/254] I18n: improve chinese translation (#20197) * i18n: improve zh-CN translation * i18n: improve zh-TW translation --- src/lib/i18n/locales/zh-CN/translation.json | 17 +++++++++++++++++ src/lib/i18n/locales/zh-TW/translation.json | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index a20b7514aa..091927eb6d 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -336,6 +336,7 @@ "Contact Admin for WebUI Access": "请联系管理员以获取访问权限", "Content": "内容", "Content Extraction Engine": "内容提取引擎", + "Content lengths (character counts only)": "内容长度(仅统计字符)", "Continue Response": "继续生成", "Continue with {{provider}}": "使用 {{provider}} 继续", "Continue with Email": "使用邮箱登录", @@ -474,6 +475,7 @@ "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?": "您希望将使用统计数据同步至 Open WebUI 社区吗?", "Docling": "Docling", "Docling Parameters": "Docling 参数", "Docling Server URL required.": "需要提供 Docling 服务器接口地址", @@ -1051,6 +1053,7 @@ "Merge Responses": "合并回答", "Merged Response": "合并的回答", "Message": "消息", + "Message counts and response timestamps": "消息数量与响应时间戳", "Message rating should be enabled to use this feature": "要使用此功能,需先启用回答评价功能", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "创建链接后发送的消息将不会被分享。通过该链接访问的用户可以查看对话记录。", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1086,11 @@ "Model Name": "模型名称", "Model name already exists, please choose a different one": "模型名称已存在,请使用不同的名称", "Model Name is required.": "模型名称是必填项。", + "Model names and usage frequency": "模型名称与使用频率", "Model not selected": "未选择模型", "Model Params": "模型参数", "Model Permissions": "模型权限", + "Model responses or outputs": "模型响应或输出", "Model unloaded successfully": "模型卸载成功", "Model updated successfully": "模型更新成功", "Model(s) do not support file upload": "模型不支持上传文件", @@ -1211,6 +1216,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI 可使用任何 OpenAPI 服务器提供的工具。", "Open WebUI uses faster-whisper internally.": "Open WebUI 使用内置 faster-whisper", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI 使用 SpeechT5 和 CMU Arctic speaker embedding。", + "Open WebUI version": "Open WebUI 版本", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "当前 Open WebUI 版本 (v{{OPEN_WEBUI_VERSION}}) 低于所需的版本 (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI 接口", @@ -1235,6 +1241,7 @@ "page": "页", "Paginate": "分页", "Parameters": "参数", + "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": "粘贴大文本为文件", @@ -1570,7 +1577,11 @@ "Support": "支持", "Support this plugin:": "支持此插件", "Supported MIME Types": "支持的 MIME 类型", + "Sync": "同步", + "Sync Complete!": "同步完成!", "Sync directory": "同步目录", + "Sync Usage Stats": "同步使用统计数据", + "Syncing stats...": "同步统计数据...", "System": "系统", "System Instructions": "系统指令", "System Prompt": "系统提示词", @@ -1729,6 +1740,7 @@ "Upload Pipeline": "上传 Pipeline", "Upload Progress": "上传进度", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "上传进度:{{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "上传的文件或图片", "Uploading file...": "正在上传文件...", "URL": "URL", "URL is required": "URL 是必填项。", @@ -1746,6 +1758,7 @@ "User Groups": "用户组", "User location successfully retrieved.": "成功检索到用户位置", "User menu": "用户菜单", + "User ratings (thumbs up/down)": "用户评分(赞/踩)", "User Webhooks": "用户 Webhook", "Username": "用户名", "users": "用户", @@ -1795,6 +1808,8 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI 将向 \"{{url}}/chat/completions\" 发出请求", "What are you trying to achieve?": "您想要达到什么目标?", "What are you working on?": "您在忙于什么?", + "What is NOT shared:": "不共享的内容:", + "What is shared:": "共享的内容:", "What's New in": "最近更新内容于", "What's on your mind?": "聊聊您的想法吧!", "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.": "启用后,模型将实时回答每条对话信息,在用户发送信息后立即生成回答。这种模式适用于即时对话应用,但在性能较低的设备上可能会影响响应速度", @@ -1833,6 +1848,8 @@ "Your Account": "您的账号", "Your account status is currently pending activation.": "您的账号当前状态为待激活", "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 with the Open WebUI Community.": "您的使用统计数据已成功同步至 Open WebUI 社区。", "YouTube": "YouTube", "Youtube Language": "Youtube 语言", "Youtube Proxy URL": "Youtube 代理地址" diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index 3c07719ff3..a6d5ba69a6 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -336,6 +336,7 @@ "Contact Admin for WebUI Access": "請聯絡管理員以取得 WebUI 存取權限", "Content": "內容", "Content Extraction Engine": "內容擷取引擎", + "Content lengths (character counts only)": "內容長度(僅統計字元)", "Continue Response": "繼續回應", "Continue with {{provider}}": "使用 {{provider}} 繼續", "Continue with Email": "使用 Email 繼續", @@ -474,6 +475,7 @@ "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?": "您想要同步使用統計資料至 Open WebUI 社群嗎?", "Docling": "Docling", "Docling Parameters": "Docling 參數", "Docling Server URL required.": "需要提供 Docling 伺服器 URL。", @@ -1051,6 +1053,7 @@ "Merge Responses": "合併回應", "Merged Response": "整合回應結果", "Message": "訊息", + "Message counts and response timestamps": "訊息數量和回應時間戳記", "Message rating should be enabled to use this feature": "需要啟用訊息評分才能使用此功能", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "建立連結後傳送的訊息不會被分享。擁有網址的使用者可檢視分享的對話內容。", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1086,11 @@ "Model Name": "模型名稱", "Model name already exists, please choose a different one": "模型名稱已存在,請使用不同的名稱", "Model Name is required.": "模型名稱是必填項。", + "Model names and usage frequency": "模型名稱和使用頻率", "Model not selected": "未選取模型", "Model Params": "模型參數", "Model Permissions": "模型權限", + "Model responses or outputs": "模型回應或輸出", "Model unloaded successfully": "成功卸載模型", "Model updated successfully": "成功更新模型", "Model(s) do not support file upload": "模型不支援檔案上傳", @@ -1211,6 +1216,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI 可使用任何 OpenAPI 伺服器提供的工具。", "Open WebUI uses faster-whisper internally.": "Open WebUI 使用內部 faster-whisper。", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI 使用 SpeechT5 和 CMU Arctic 說話者嵌入。", + "Open WebUI version": "Open WebUI 版本", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI 版本 (v{{OPEN_WEBUI_VERSION}}) 低於所需版本 (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1241,7 @@ "page": "頁面", "Paginate": "啟用分頁", "Parameters": "參數", + "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": "將大型文字以檔案貼上", @@ -1570,7 +1577,11 @@ "Support": "支援", "Support this plugin:": "支持這個外掛:", "Supported MIME Types": "支援的 MIME 類型", + "Sync": "同步", + "Sync Complete!": "同步完成!", "Sync directory": "同步目錄", + "Sync Usage Stats": "同步使用統計資料", + "Syncing stats...": "同步統計資料...", "System": "系統", "System Instructions": "系統指令", "System Prompt": "系統提示詞", @@ -1729,6 +1740,7 @@ "Upload Pipeline": "上傳管線", "Upload Progress": "上傳進度", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "上傳進度:{{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "上傳的檔案或圖片", "Uploading file...": "正在上傳檔案...", "URL": "URL", "URL is required": "URL 為必填項目", @@ -1746,6 +1758,7 @@ "User Groups": "使用者群組", "User location successfully retrieved.": "成功取得使用者位置。", "User menu": "使用者選單", + "User ratings (thumbs up/down)": "使用者評分(讚/踩)", "User Webhooks": "使用者 Webhooks", "Username": "使用者名稱", "users": "使用者", @@ -1795,6 +1808,8 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI 將向 \"{{url}}/chat/completions\" 傳送請求", "What are you trying to achieve?": "您正在試圖完成什麼?", "What are you working on?": "您現在的工作是什麼?", + "What is NOT shared:": "不會分享的內容:", + "What is shared:": "會分享的內容:", "What's New in": "新功能", "What's on your mind?": "聊聊您的想法?", "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.": "啟用時,模型將即時回應每個對話訊息,在使用者傳送訊息後立即生成回應。此模式適用於即時對話應用程式,但在較慢的硬體上可能會影響效能。", @@ -1833,6 +1848,8 @@ "Your Account": "您的帳號", "Your account status is currently pending activation.": "您的帳號目前正在等待啟用。", "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 with the Open WebUI Community.": "您的使用統計資料已成功同步至 Open WebUI 社群。", "YouTube": "YouTube", "Youtube Language": "YouTube 語言", "Youtube Proxy URL": "YouTube 代理伺服器 URL" From 9405628e46a2a8793ac1d4f73e120c96f1a17440 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 29 Dec 2025 00:24:49 +0400 Subject: [PATCH 036/254] chore: dep-min --- backend/requirements-min.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/backend/requirements-min.txt b/backend/requirements-min.txt index e2827ec659..0861477501 100644 --- a/backend/requirements-min.txt +++ b/backend/requirements-min.txt @@ -41,8 +41,11 @@ asgiref==3.11.0 mcp==1.25.0 openai -langchain==0.3.27 -langchain-community==0.3.29 +langchain==1.2.0 +langchain-community==0.4.1 +langchain-classic==1.0.0 +langchain-text-splitters==1.1.0 + fake-useragent==2.2.0 chromadb==1.3.7 From 475dd91ed798f2efcdf27799d5c5cae3f0e6e847 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 29 Dec 2025 00:39:43 +0400 Subject: [PATCH 037/254] refac --- backend/open_webui/routers/scim.py | 55 ++++++++++++++++++------------ 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/backend/open_webui/routers/scim.py b/backend/open_webui/routers/scim.py index bd2fd3d4f7..d26b499700 100644 --- a/backend/open_webui/routers/scim.py +++ b/backend/open_webui/routers/scim.py @@ -25,6 +25,10 @@ from open_webui.utils.auth import ( ) from open_webui.constants import ERROR_MESSAGES + +from sqlalchemy.orm import Session +from open_webui.internal.db import get_session + log = logging.getLogger(__name__) router = APIRouter() @@ -345,13 +349,13 @@ def user_to_scim(user: UserModel, request: Request) -> SCIMUser: ) -def group_to_scim(group: GroupModel, request: Request) -> SCIMGroup: +def group_to_scim(group: GroupModel, request: Request, db=None) -> SCIMGroup: """Convert internal Group model to SCIM Group""" - member_ids = Groups.get_group_user_ids_by_id(group.id) + member_ids = Groups.get_group_user_ids_by_id(group.id, db) or [] members = [] for user_id in member_ids: - user = Users.get_user_by_id(user_id) + user = Users.get_user_by_id(user_id, db=db) if user: members.append( SCIMGroupMember( @@ -714,10 +718,11 @@ async def get_groups( count: int = Query(20, ge=1, le=100), filter: Optional[str] = None, _: bool = Depends(get_scim_auth), + db: Session = Depends(get_session), ): """List SCIM Groups""" # Get all groups - groups_list = Groups.get_all_groups() + groups_list = Groups.get_all_groups(db=db) # Apply pagination total = len(groups_list) @@ -726,7 +731,7 @@ async def get_groups( paginated_groups = groups_list[start:end] # Convert to SCIM format - scim_groups = [group_to_scim(group, request) for group in paginated_groups] + scim_groups = [group_to_scim(group, request, db=db) for group in paginated_groups] return SCIMListResponse( totalResults=total, @@ -741,6 +746,7 @@ async def get_group( group_id: str, request: Request, _: bool = Depends(get_scim_auth), + db: Session = Depends(get_session), ): """Get SCIM Group by ID""" group = Groups.get_group_by_id(group_id) @@ -750,7 +756,7 @@ async def get_group( detail=f"Group {group_id} not found", ) - return group_to_scim(group, request) + return group_to_scim(group, request, db=db) @router.post("/Groups", response_model=SCIMGroup, status_code=status.HTTP_201_CREATED) @@ -758,6 +764,7 @@ async def create_group( request: Request, group_data: SCIMGroupCreateRequest, _: bool = Depends(get_scim_auth), + db: Session = Depends(get_session), ): """Create SCIM Group""" # Extract member IDs @@ -775,14 +782,14 @@ async def create_group( ) # Need to get the creating user's ID - we'll use the first admin - admin_user = Users.get_super_admin_user() + admin_user = Users.get_super_admin_user(db=db) if not admin_user: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="No admin user found", ) - new_group = Groups.insert_new_group(admin_user.id, form) + new_group = Groups.insert_new_group(admin_user.id, form, db=db) if not new_group: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, @@ -798,12 +805,12 @@ async def create_group( description=new_group.description, ) - Groups.update_group_by_id(new_group.id, update_form) - Groups.set_group_user_ids_by_id(new_group.id, member_ids) + Groups.update_group_by_id(new_group.id, update_form, db=db) + Groups.set_group_user_ids_by_id(new_group.id, member_ids, db=db) - new_group = Groups.get_group_by_id(new_group.id) + new_group = Groups.get_group_by_id(new_group.id, db=db) - return group_to_scim(new_group, request) + return group_to_scim(new_group, request, db=db) @router.put("/Groups/{group_id}", response_model=SCIMGroup) @@ -812,9 +819,10 @@ async def update_group( request: Request, group_data: SCIMGroupUpdateRequest, _: bool = Depends(get_scim_auth), + db: Session = Depends(get_session), ): """Update SCIM Group (full update)""" - group = Groups.get_group_by_id(group_id) + group = Groups.get_group_by_id(group_id, db=db) if not group: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -832,17 +840,17 @@ async def update_group( # Handle members if provided if group_data.members is not None: member_ids = [member.value for member in group_data.members] - Groups.set_group_user_ids_by_id(group_id, member_ids) + Groups.set_group_user_ids_by_id(group_id, member_ids, db=db) # Update group - updated_group = Groups.update_group_by_id(group_id, update_form) + updated_group = Groups.update_group_by_id(group_id, update_form, db=db) if not updated_group: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to update group", ) - return group_to_scim(updated_group, request) + return group_to_scim(updated_group, request, db=db) @router.patch("/Groups/{group_id}", response_model=SCIMGroup) @@ -851,9 +859,10 @@ async def patch_group( request: Request, patch_data: SCIMPatchRequest, _: bool = Depends(get_scim_auth), + db: Session = Depends(get_session), ): """Update SCIM Group (partial update)""" - group = Groups.get_group_by_id(group_id) + group = Groups.get_group_by_id(group_id, db=db) if not group: raise HTTPException( status_code=status.HTTP_404_NOT_FOUND, @@ -878,7 +887,7 @@ async def patch_group( elif path == "members": # Replace all members Groups.set_group_user_ids_by_id( - group_id, [member["value"] for member in value] + group_id, [member["value"] for member in value], db=db ) elif op == "add": @@ -887,22 +896,24 @@ async def patch_group( if isinstance(value, list): for member in value: if isinstance(member, dict) and "value" in member: - Groups.add_users_to_group(group_id, [member["value"]]) + Groups.add_users_to_group( + group_id, [member["value"]], db=db + ) elif op == "remove": if path and path.startswith("members[value eq"): # Remove specific member member_id = path.split('"')[1] - Groups.remove_users_from_group(group_id, [member_id]) + Groups.remove_users_from_group(group_id, [member_id], db=db) # Update group - updated_group = Groups.update_group_by_id(group_id, update_form) + updated_group = Groups.update_group_by_id(group_id, update_form, db=db) if not updated_group: raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to update group", ) - return group_to_scim(updated_group, request) + return group_to_scim(updated_group, request, db=db) @router.delete("/Groups/{group_id}", status_code=status.HTTP_204_NO_CONTENT) From 26af1f92e21ddfd08348570bf54a6f345ac69648 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 29 Dec 2025 00:41:47 +0400 Subject: [PATCH 038/254] enh: WHISPER_COMPUTE_TYPE env var --- backend/open_webui/config.py | 1 + backend/open_webui/routers/audio.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index bea37ecc44..2f052ca6e0 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -3675,6 +3675,7 @@ WHISPER_MODEL = PersistentConfig( os.getenv("WHISPER_MODEL", "base"), ) +WHISPER_COMPUTE_TYPE = os.getenv("WHISPER_COMPUTE_TYPE", "int8") WHISPER_MODEL_DIR = os.getenv("WHISPER_MODEL_DIR", f"{CACHE_DIR}/whisper/models") WHISPER_MODEL_AUTO_UPDATE = ( not OFFLINE_MODE diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py index 120300d49e..4d6c50f089 100644 --- a/backend/open_webui/routers/audio.py +++ b/backend/open_webui/routers/audio.py @@ -38,6 +38,7 @@ from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.utils.headers import include_user_info_headers from open_webui.config import ( WHISPER_MODEL_AUTO_UPDATE, + WHISPER_COMPUTE_TYPE, WHISPER_MODEL_DIR, CACHE_DIR, WHISPER_LANGUAGE, @@ -129,7 +130,7 @@ def set_faster_whisper_model(model: str, auto_update: bool = False): faster_whisper_kwargs = { "model_size_or_path": model, "device": DEVICE_TYPE if DEVICE_TYPE and DEVICE_TYPE == "cuda" else "cpu", - "compute_type": "int8", + "compute_type": WHISPER_COMPUTE_TYPE, "download_root": WHISPER_MODEL_DIR, "local_files_only": not auto_update, } From 267cc14d2d98b2bb2771ce9bd359e9622153f0ee Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 29 Dec 2025 00:42:49 +0400 Subject: [PATCH 039/254] chore: rm google-generativeai --- backend/requirements.txt | 1 - pyproject.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 8f94d3e665..b5c0733edb 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -43,7 +43,6 @@ mcp==1.25.0 openai anthropic google-genai==1.56.0 -google-generativeai==0.8.6 langchain==1.2.0 langchain-community==0.4.1 diff --git a/pyproject.toml b/pyproject.toml index da20abe6e2..23cbdd3bbc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,7 +50,6 @@ dependencies = [ "openai", "anthropic", "google-genai==1.56.0", - "google-generativeai==0.8.6", "langchain==1.2.0", "langchain-community==0.4.1", From cc602abcb285e45cba509ec8e697131bcd044c7c Mon Sep 17 00:00:00 2001 From: Shirasawa <764798966@qq.com> Date: Mon, 29 Dec 2025 04:44:22 +0800 Subject: [PATCH 040/254] feat: Dynamically load yaml to speed up page loading (#20204) --- src/lib/apis/index.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib/apis/index.ts b/src/lib/apis/index.ts index e865e9ba0e..f37f525793 100644 --- a/src/lib/apis/index.ts +++ b/src/lib/apis/index.ts @@ -1,10 +1,7 @@ -import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; +import { WEBUI_BASE_URL } from '$lib/constants'; import { convertOpenApiToToolPayload } from '$lib/utils'; import { getOpenAIModelsDirect } from './openai'; -import { parse } from 'yaml'; -import { toast } from 'svelte-sonner'; - export const getModels = async ( token: string = '', connections: object | null = null, @@ -316,7 +313,7 @@ export const getToolServerData = async (token: string, url: string) => { // Check if URL ends with .yaml or .yml to determine format if (url.toLowerCase().endsWith('.yaml') || url.toLowerCase().endsWith('.yml')) { if (!res.ok) throw await res.text(); - const text = await res.text(); + const [text, { parse }] = await Promise.all([res.text(), import('yaml')]); return parse(text); } else { if (!res.ok) throw await res.json(); From 3994d88c908f4bf4d20e5b78dad8223fefbcf9d5 Mon Sep 17 00:00:00 2001 From: Shirasawa <764798966@qq.com> Date: Mon, 29 Dec 2025 04:44:44 +0800 Subject: [PATCH 041/254] chore: remove vega import to reduce build size (#20200) --- src/lib/components/layout/Sidebar.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index c1d89adaa3..70281503e4 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -64,7 +64,6 @@ import Note from '../icons/Note.svelte'; import { slide } from 'svelte/transition'; import HotkeyHint from '../common/HotkeyHint.svelte'; - import { key } from 'vega'; const BREAKPOINT = 768; From 9a9b5ef699cd2b1023deccd62f0ba98ce7903284 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Sun, 28 Dec 2025 15:45:45 -0500 Subject: [PATCH 042/254] feat: add sidebar toggle to workspace and admin models pages (#20176) --- .../components/admin/Settings/Models.svelte | 17 ++++++++++++ .../admin/Settings/Models/ModelMenu.svelte | 26 ++++++++++++++++++- .../chat/ModelSelector/ModelItemMenu.svelte | 9 ++++--- src/lib/components/workspace/Models.svelte | 17 ++++++++++++ .../workspace/Models/ModelMenu.svelte | 26 ++++++++++++++++++- 5 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/lib/components/admin/Settings/Models.svelte b/src/lib/components/admin/Settings/Models.svelte index 1c1fc6512b..d107e09f70 100644 --- a/src/lib/components/admin/Settings/Models.svelte +++ b/src/lib/components/admin/Settings/Models.svelte @@ -17,6 +17,7 @@ } from '$lib/apis/models'; import { copyToClipboard } from '$lib/utils'; import { page } from '$app/stores'; + import { updateUserSettings } from '$lib/apis/users'; import { getModels } from '$lib/apis'; import Search from '$lib/components/icons/Search.svelte'; @@ -218,6 +219,19 @@ saveAs(blob, `${model.id}-${Date.now()}.json`); }; + const pinModelHandler = async (modelId) => { + let pinnedModels = $settings?.pinnedModels ?? []; + + if (pinnedModels.includes(modelId)) { + pinnedModels = pinnedModels.filter((id) => id !== modelId); + } else { + pinnedModels = [...new Set([...pinnedModels, modelId])]; + } + + settings.set({ ...$settings, pinnedModels: pinnedModels }); + await updateUserSettings(localStorage.token, { ui: $settings }); + }; + onMount(async () => { await init(); const id = $page.url.searchParams.get('id'); @@ -427,6 +441,9 @@ hideHandler={() => { hideModelHandler(model); }} + pinModelHandler={() => { + pinModelHandler(model.id); + }} copyLinkHandler={() => { copyLinkHandler(model); }} diff --git a/src/lib/components/admin/Settings/Models/ModelMenu.svelte b/src/lib/components/admin/Settings/Models/ModelMenu.svelte index b7e694b165..d4cd48a37d 100644 --- a/src/lib/components/admin/Settings/Models/ModelMenu.svelte +++ b/src/lib/components/admin/Settings/Models/ModelMenu.svelte @@ -13,8 +13,10 @@ import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte'; import Download from '$lib/components/icons/Download.svelte'; import ArrowUpCircle from '$lib/components/icons/ArrowUpCircle.svelte'; + import Pin from '$lib/components/icons/Pin.svelte'; + import PinSlash from '$lib/components/icons/PinSlash.svelte'; - import { config } from '$lib/stores'; + import { config, settings } from '$lib/stores'; import Link from '$lib/components/icons/Link.svelte'; const i18n = getContext('i18n'); @@ -24,6 +26,7 @@ export let exportHandler: Function; export let hideHandler: Function; + export let pinModelHandler: Function; export let copyLinkHandler: Function; export let cloneHandler: Function; @@ -104,6 +107,27 @@
+ { + pinModelHandler(model?.id); + }} + > + {#if ($settings?.pinnedModels ?? []).includes(model?.id)} + + {:else} + + {/if} + +
+ {#if ($settings?.pinnedModels ?? []).includes(model?.id)} + {$i18n.t('Hide from Sidebar')} + {:else} + {$i18n.t('Keep in Sidebar')} + {/if} +
+
+ { diff --git a/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte b/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte index 64e79dbcbb..5f795a6709 100644 --- a/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte +++ b/src/lib/components/chat/ModelSelector/ModelItemMenu.svelte @@ -5,9 +5,10 @@ import { getContext } from 'svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte'; + import Pin from '$lib/components/icons/Pin.svelte'; + import PinSlash from '$lib/components/icons/PinSlash.svelte'; + import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte'; import Link from '$lib/components/icons/Link.svelte'; - import Eye from '$lib/components/icons/Eye.svelte'; - import EyeSlash from '$lib/components/icons/EyeSlash.svelte'; import { settings } from '$lib/stores'; const i18n = getContext('i18n'); @@ -63,9 +64,9 @@ }} > {#if ($settings?.pinnedModels ?? []).includes(model?.id)} - + {:else} - + {/if}
diff --git a/src/lib/components/workspace/Models.svelte b/src/lib/components/workspace/Models.svelte index 7f42c2da4d..10e8c70a81 100644 --- a/src/lib/components/workspace/Models.svelte +++ b/src/lib/components/workspace/Models.svelte @@ -24,6 +24,7 @@ import { getModels } from '$lib/apis'; import { getGroups } from '$lib/apis/groups'; + import { updateUserSettings } from '$lib/apis/users'; import { capitalizeFirstLetter, copyToClipboard } from '$lib/utils'; @@ -215,6 +216,19 @@ saveAs(blob, `${model.id}-${Date.now()}.json`); }; + const pinModelHandler = async (modelId) => { + let pinnedModels = $settings?.pinnedModels ?? []; + + if (pinnedModels.includes(modelId)) { + pinnedModels = pinnedModels.filter((id) => id !== modelId); + } else { + pinnedModels = [...new Set([...pinnedModels, modelId])]; + } + + settings.set({ ...$settings, pinnedModels: pinnedModels }); + await updateUserSettings(localStorage.token, { ui: $settings }); + }; + onMount(async () => { viewOption = localStorage.workspaceViewOption ?? ''; page = 1; @@ -547,6 +561,9 @@ hideHandler={() => { hideModelHandler(model); }} + pinModelHandler={() => { + pinModelHandler(model.id); + }} copyLinkHandler={() => { copyLinkHandler(model); }} diff --git a/src/lib/components/workspace/Models/ModelMenu.svelte b/src/lib/components/workspace/Models/ModelMenu.svelte index 825250e6af..30712eef5c 100644 --- a/src/lib/components/workspace/Models/ModelMenu.svelte +++ b/src/lib/components/workspace/Models/ModelMenu.svelte @@ -13,8 +13,10 @@ import DocumentDuplicate from '$lib/components/icons/DocumentDuplicate.svelte'; import Download from '$lib/components/icons/Download.svelte'; import ArrowUpCircle from '$lib/components/icons/ArrowUpCircle.svelte'; + import Pin from '$lib/components/icons/Pin.svelte'; + import PinSlash from '$lib/components/icons/PinSlash.svelte'; - import { config, user as currentUser } from '$lib/stores'; + import { config, user as currentUser, settings } from '$lib/stores'; import Link from '$lib/components/icons/Link.svelte'; const i18n = getContext('i18n'); @@ -29,6 +31,7 @@ export let copyLinkHandler: Function; export let hideHandler: Function; + export let pinModelHandler: Function; export let deleteHandler: Function; export let onClose: Function; @@ -124,6 +127,27 @@
+ { + pinModelHandler(model?.id); + }} + > + {#if ($settings?.pinnedModels ?? []).includes(model?.id)} + + {:else} + + {/if} + +
+ {#if ($settings?.pinnedModels ?? []).includes(model?.id)} + {$i18n.t('Hide from Sidebar')} + {:else} + {$i18n.t('Keep in Sidebar')} + {/if} +
+
+ { From 87e8d39a9035a3e5f02b959d223098553ef2e726 Mon Sep 17 00:00:00 2001 From: Shirasawa <764798966@qq.com> Date: Mon, 29 Dec 2025 04:47:37 +0800 Subject: [PATCH 043/254] feat: Dynamically load xlsx to speed up page loading (#20203) --- src/lib/apis/files/index.ts | 2 +- .../components/common/FileItemModal.svelte | 28 ++++++------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/lib/apis/files/index.ts b/src/lib/apis/files/index.ts index 07042c4ade..44af669fa1 100644 --- a/src/lib/apis/files/index.ts +++ b/src/lib/apis/files/index.ts @@ -252,7 +252,7 @@ export const getFileContentById = async (id: string) => { }) .then(async (res) => { if (!res.ok) throw await res.json(); - return await res.blob(); + return await res.arrayBuffer(); }) .catch((err) => { error = err.detail; diff --git a/src/lib/components/common/FileItemModal.svelte b/src/lib/components/common/FileItemModal.svelte index 33a9d3b3f4..709d622624 100644 --- a/src/lib/components/common/FileItemModal.svelte +++ b/src/lib/components/common/FileItemModal.svelte @@ -1,12 +1,12 @@
{#if completed} -
+
+
{$i18n.t('Sync Complete!')}
+
+ {$i18n.t('Your usage stats have been successfully synced.')} +
+ -
- +
+ +
+
+ {:else if error} +
+
{$i18n.t('Sync Failed')}
+
+ {errorMessage || $i18n.t('There was an error syncing your stats. Please try again.')}
-
- {$i18n.t('Sync Complete!')} +
+
- -
- {$i18n.t('Your usage stats have been successfully synced with the Open WebUI Community.')} -
- -
{:else} -
-
{$i18n.t('Sync Usage Stats')}
+
+
{$i18n.t('Sync Usage Stats')}
+ {#if eventData?.lastSyncedChatUpdatedAt} +
+ + + +
+ {/if} + {#if syncing}
{downloading ? $i18n.t('Downloading stats...') : $i18n.t('Syncing stats...')}
-
{Math.round((processedItemsCount / total) * 100) || 0}%
+
+ {#if total > 0} + {processedItemsCount}/{total} + {:else} + {processedItemsCount} + {/if} +
-
-
+
+ {#if total > 0} +
+ {:else} +
+ {/if}
{/if} @@ -297,11 +449,10 @@
@@ -311,12 +462,7 @@ class="px-4 py-2 rounded-full text-sm font-medium bg-gray-100 hover:bg-gray-200 dark:bg-gray-800 dark:hover:bg-gray-700 text-gray-900 dark:text-gray-100 transition disabled:cursor-not-allowed" on:click={() => { if (syncing) { - cancelDownload(); - if (downloading) { - cancelDownload(); - } else { - syncing = false; - } + cancelOperation(); } else { show = false; } @@ -327,9 +473,7 @@
{#if selectedTab === 'leaderboard'} - {:else if selectedTab === 'feedbacks'} + {:else if selectedTab === 'feedback'} {/if}
diff --git a/src/lib/components/admin/Evaluations/Feedbacks.svelte b/src/lib/components/admin/Evaluations/Feedbacks.svelte index 3782e7614f..d3ae05f9df 100644 --- a/src/lib/components/admin/Evaluations/Feedbacks.svelte +++ b/src/lib/components/admin/Evaluations/Feedbacks.svelte @@ -179,7 +179,7 @@
{#if (items ?? []).length === 0}
- {$i18n.t('No feedbacks found')} + {$i18n.t('No feedback found')}
{:else} Date: Wed, 31 Dec 2025 15:44:02 -0500 Subject: [PATCH 087/254] fix: resolve duplicate key and null message errors in chat (#20268) * fix: resolve duplicate key and null message errors in chat * fix: resolve duplicate key and null message errors in chat * chore: visitedIds -> visitedMessageIds --- src/lib/components/chat/Chat.svelte | 8 +++++--- src/lib/components/chat/Messages.svelte | 8 ++++++++ src/lib/components/chat/Overview/View.svelte | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index a423b1694a..2b50beb4d3 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1103,7 +1103,7 @@ if (history.currentId) { for (const message of Object.values(history.messages)) { - if (message.role === 'assistant') { + if (message && message.role === 'assistant') { message.done = true; } } @@ -2084,8 +2084,10 @@ const responseMessage = history.messages[history.currentId]; // Set all response messages to done - for (const messageId of history.messages[responseMessage.parentId].childrenIds) { - history.messages[messageId].done = true; + if (responseMessage.parentId && history.messages[responseMessage.parentId]) { + for (const messageId of history.messages[responseMessage.parentId].childrenIds) { + history.messages[messageId].done = true; + } } history.messages[history.currentId] = responseMessage; diff --git a/src/lib/components/chat/Messages.svelte b/src/lib/components/chat/Messages.svelte index a019648a25..20579689a5 100644 --- a/src/lib/components/chat/Messages.svelte +++ b/src/lib/components/chat/Messages.svelte @@ -77,7 +77,15 @@ let _messages = []; let message = history.messages[history.currentId]; + const visitedMessageIds = new Set(); + while (message && (messagesCount !== null ? _messages.length <= messagesCount : true)) { + if (visitedMessageIds.has(message.id)) { + console.warn('Circular dependency detected in message history', message.id); + break; + } + visitedMessageIds.add(message.id); + _messages.unshift({ ...message }); message = message.parentId !== null ? history.messages[message.parentId] : null; } diff --git a/src/lib/components/chat/Overview/View.svelte b/src/lib/components/chat/Overview/View.svelte index dc1276abec..b3164e6e78 100644 --- a/src/lib/components/chat/Overview/View.svelte +++ b/src/lib/components/chat/Overview/View.svelte @@ -75,6 +75,8 @@ Object.keys(history.messages).forEach((id) => { const message = history.messages[id]; + if (!message) return; + const level = message.parentId ? (positionMap.get(message.parentId)?.level ?? -1) + 1 : 0; if (!layerWidths[level]) layerWidths[level] = 0; @@ -88,6 +90,8 @@ // Adjust positions based on siblings count to centralize vertical spacing Object.keys(history.messages).forEach((id) => { const pos = positionMap.get(id); + if (!pos) return; + const x = direction === 'vertical' ? pos.position * siblingOffset : pos.level * levelOffset; const y = direction === 'vertical' ? pos.level * levelOffset : pos.position * siblingOffset; From 431632d5303da1b7e7db4d442c7c0de30d9322de Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Wed, 31 Dec 2025 21:48:31 +0100 Subject: [PATCH 088/254] fix: normalize local CrossEncoder reranking scores for relevance threshold (#20228) * Update utils.py * Update retrieval.py * Update utils.py * Update retrieval.py * add env var * rename to SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION --- backend/open_webui/env.py | 7 +++++++ backend/open_webui/routers/retrieval.py | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index a5184aa4d5..95349d6e62 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -762,6 +762,13 @@ else: except Exception: SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS = None +# Whether to apply sigmoid normalization to CrossEncoder reranking scores. +# When enabled (default), scores are normalized to 0-1 range for proper +# relevance threshold behavior with MS MARCO models. +SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION = ( + os.environ.get("SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION", "True").lower() == "true" +) + #################################### # OFFLINE_MODE #################################### diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 2fc7ca2ef9..f35c6b43b6 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -112,6 +112,7 @@ from open_webui.env import ( SENTENCE_TRANSFORMERS_MODEL_KWARGS, SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND, SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS, + SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION, ) from open_webui.constants import ERROR_MESSAGES @@ -190,6 +191,7 @@ def get_rf( raise Exception(ERROR_MESSAGES.DEFAULT(e)) else: import sentence_transformers + import torch try: rf = sentence_transformers.CrossEncoder( @@ -198,6 +200,11 @@ def get_rf( trust_remote_code=RAG_RERANKING_MODEL_TRUST_REMOTE_CODE, backend=SENTENCE_TRANSFORMERS_CROSS_ENCODER_BACKEND, model_kwargs=SENTENCE_TRANSFORMERS_CROSS_ENCODER_MODEL_KWARGS, + activation_fn=( + torch.nn.Sigmoid() + if SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION + else None + ), ) except Exception as e: log.error(f"CrossEncoder: {e}") From dfc5dad63167eabb7fb027e63c324675b23f2e9d Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 01:27:07 +0400 Subject: [PATCH 089/254] enh: REQUESTS_VERIFY --- backend/open_webui/env.py | 7 ++++++- backend/open_webui/retrieval/loaders/main.py | 4 ++-- backend/open_webui/retrieval/models/external.py | 3 ++- backend/open_webui/retrieval/utils.py | 6 +++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 95349d6e62..e3459870e2 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -669,6 +669,8 @@ except ValueError: WEBSOCKET_SERVER_PING_INTERVAL = 25 +REQUESTS_VERIFY = os.environ.get("REQUESTS_VERIFY", "True").lower() == "true" + AIOHTTP_CLIENT_TIMEOUT = os.environ.get("AIOHTTP_CLIENT_TIMEOUT", "") if AIOHTTP_CLIENT_TIMEOUT == "": @@ -766,7 +768,10 @@ else: # When enabled (default), scores are normalized to 0-1 range for proper # relevance threshold behavior with MS MARCO models. SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION = ( - os.environ.get("SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION", "True").lower() == "true" + os.environ.get( + "SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION", "True" + ).lower() + == "true" ) #################################### diff --git a/backend/open_webui/retrieval/loaders/main.py b/backend/open_webui/retrieval/loaders/main.py index b0bc1dd068..2b83e44283 100644 --- a/backend/open_webui/retrieval/loaders/main.py +++ b/backend/open_webui/retrieval/loaders/main.py @@ -30,7 +30,7 @@ from open_webui.retrieval.loaders.datalab_marker import DatalabMarkerLoader from open_webui.retrieval.loaders.mineru import MinerULoader -from open_webui.env import GLOBAL_LOG_LEVEL +from open_webui.env import GLOBAL_LOG_LEVEL, REQUESTS_VERIFY logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) log = logging.getLogger(__name__) @@ -114,7 +114,7 @@ class TikaLoader: endpoint += "/" endpoint += "tika/text" - r = requests.put(endpoint, data=data, headers=headers) + r = requests.put(endpoint, data=data, headers=headers, verify=REQUESTS_VERIFY) if r.ok: raw_metadata = r.json() diff --git a/backend/open_webui/retrieval/models/external.py b/backend/open_webui/retrieval/models/external.py index d567bf4fe5..095143d20d 100644 --- a/backend/open_webui/retrieval/models/external.py +++ b/backend/open_webui/retrieval/models/external.py @@ -4,7 +4,7 @@ from typing import Optional, List, Tuple from urllib.parse import quote -from open_webui.env import ENABLE_FORWARD_USER_INFO_HEADERS +from open_webui.env import ENABLE_FORWARD_USER_INFO_HEADERS, REQUESTS_VERIFY from open_webui.retrieval.models.base_reranker import BaseReranker from open_webui.utils.headers import include_user_info_headers @@ -55,6 +55,7 @@ class ExternalReranker(BaseReranker): headers=headers, json=payload, timeout=self.timeout, + verify=REQUESTS_VERIFY, ) r.raise_for_status() diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index bb2c3ef12f..772f37fbec 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -42,6 +42,7 @@ from open_webui.retrieval.loaders.youtube import YoutubeLoader from open_webui.env import ( OFFLINE_MODE, ENABLE_FORWARD_USER_INFO_HEADERS, + AIOHTTP_CLIENT_SESSION_SSL, ) from open_webui.config import ( RAG_EMBEDDING_QUERY_PREFIX, @@ -762,7 +763,10 @@ async def agenerate_ollama_batch_embeddings( async with aiohttp.ClientSession(trust_env=True) as session: async with session.post( - f"{url}/api/embed", headers=headers, json=form_data + f"{url}/api/embed", + headers=headers, + json=form_data, + ssl=AIOHTTP_CLIENT_SESSION_SSL, ) as r: r.raise_for_status() data = await r.json() From bf2b2962399e341926bdbf9e0a82101f31a90b23 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 01:37:38 +0400 Subject: [PATCH 090/254] fix: oauth server_metadata_url issue Co-Authored-By: Shamray Alexander <843002+imsamurai@users.noreply.github.com> --- backend/open_webui/utils/oauth.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index ef90c74c24..d30eec3a73 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -579,24 +579,27 @@ class OAuthClientManager: def get_client(self, client_id): if client_id not in self.clients: self.ensure_client_from_config(client_id) + client = self.clients.get(client_id) return client["client"] if client else None def get_client_info(self, client_id): if client_id not in self.clients: self.ensure_client_from_config(client_id) + client = self.clients.get(client_id) return client["client_info"] if client else None def get_server_metadata_url(self, client_id): - if client_id in self.clients: - client = self.clients[client_id] - return ( - client._server_metadata_url - if hasattr(client, "_server_metadata_url") - else None - ) - return None + client = self.get_client(client_id) + if not client: + return None + + return ( + client._server_metadata_url + if hasattr(client, "_server_metadata_url") + else None + ) async def get_oauth_token( self, user_id: str, client_id: str, force_refresh: bool = False @@ -1161,7 +1164,9 @@ class OAuthManager: else: user_oauth_groups = [] - user_current_groups: list[GroupModel] = Groups.get_groups_by_member_id(user.id, db=db) + user_current_groups: list[GroupModel] = Groups.get_groups_by_member_id( + user.id, db=db + ) all_available_groups: list[GroupModel] = Groups.get_all_groups(db=db) # Create groups if they don't exist and creation is enabled From fdae5644e36972384b3e2513e3074f95f9f7381f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 01:51:37 +0400 Subject: [PATCH 091/254] refac --- backend/open_webui/env.py | 5 +++++ backend/open_webui/utils/logger.py | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index e3459870e2..24b7656015 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -790,6 +790,11 @@ if OFFLINE_MODE: #################################### # AUDIT LOGGING #################################### + + +ENABLE_AUDIT_STDOUT = os.getenv("ENABLE_AUDIT_STDOUT", "False").lower() == "true" +ENABLE_AUDIT_LOGS_FILE = os.getenv("ENABLE_AUDIT_LOGS_FILE", "True").lower() == "true" + # Where to store log file # Defaults to the DATA_DIR/audit.log. To set AUDIT_LOGS_FILE_PATH you need to # provide the whole path, like: /app/audit.log diff --git a/backend/open_webui/utils/logger.py b/backend/open_webui/utils/logger.py index 540527bf82..4af3064235 100644 --- a/backend/open_webui/utils/logger.py +++ b/backend/open_webui/utils/logger.py @@ -6,11 +6,13 @@ from typing import TYPE_CHECKING from loguru import logger from opentelemetry import trace from open_webui.env import ( - AUDIT_UVICORN_LOGGER_NAMES, + ENABLE_AUDIT_STDOUT, + ENABLE_AUDIT_LOGS_FILE, + AUDIT_LOGS_FILE_PATH, AUDIT_LOG_FILE_ROTATION_SIZE, AUDIT_LOG_LEVEL, - AUDIT_LOGS_FILE_PATH, GLOBAL_LOG_LEVEL, + AUDIT_UVICORN_LOGGER_NAMES, ENABLE_OTEL, ENABLE_OTEL_LOGS, ) @@ -130,9 +132,11 @@ def start_logger(): sys.stdout, level=GLOBAL_LOG_LEVEL, format=stdout_format, - filter=lambda record: "auditable" not in record["extra"], + filter=lambda record: ( + "auditable" not in record["extra"] if ENABLE_AUDIT_STDOUT else True + ), ) - if AUDIT_LOG_LEVEL != "NONE": + if AUDIT_LOG_LEVEL != "NONE" and ENABLE_AUDIT_LOGS_FILE: try: logger.add( AUDIT_LOGS_FILE_PATH, From b619a157bc54c5bc44d223d2ae3acb9ce4ac6a6c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 01:58:53 +0400 Subject: [PATCH 092/254] refac/fix: rtl support Co-Authored-By: lif <19658300+majiayu000@users.noreply.github.com> --- src/app.css | 4 ++-- src/lib/components/common/RichTextInput.svelte | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/app.css b/src/app.css index 897dbdc3b7..8d2d6972f4 100644 --- a/src/app.css +++ b/src/app.css @@ -628,7 +628,7 @@ input[type='number'] { /* Table styling for tiptap editors */ .tiptap table { - @apply w-full text-sm text-left text-gray-500 dark:text-gray-400 max-w-full; + @apply w-full text-sm text-start text-gray-500 dark:text-gray-400 max-w-full; } .tiptap thead { @@ -641,7 +641,7 @@ input[type='number'] { } .tiptap th { - @apply cursor-pointer text-left text-xs text-gray-700 dark:text-gray-400 font-semibold uppercase bg-gray-50 dark:bg-gray-850; + @apply cursor-pointer text-start text-xs text-gray-700 dark:text-gray-400 font-semibold uppercase bg-gray-50 dark:bg-gray-850; } .tiptap td { diff --git a/src/lib/components/common/RichTextInput.svelte b/src/lib/components/common/RichTextInput.svelte index 688eb289e6..f7447551f8 100644 --- a/src/lib/components/common/RichTextInput.svelte +++ b/src/lib/components/common/RichTextInput.svelte @@ -750,7 +750,7 @@ }) ] : []), - ...(richText && showFormattingToolbar + ...(richText && showFormattingToolbar ? [ BubbleMenu.configure({ element: bubbleMenuElement, @@ -1179,5 +1179,6 @@
From 89ad1c68d1aadf849960b5e202aa4651096b05f5 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 02:07:22 +0400 Subject: [PATCH 093/254] enh: FIRECRAWL_TIMEOUT --- backend/open_webui/config.py | 6 ++++++ backend/open_webui/main.py | 2 ++ backend/open_webui/retrieval/web/utils.py | 12 ++++++++++-- backend/open_webui/routers/retrieval.py | 4 ++++ .../components/admin/Settings/WebSearch.svelte | 18 ++++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 08a30815b9..8294e51668 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -3320,6 +3320,12 @@ FIRECRAWL_API_BASE_URL = PersistentConfig( os.environ.get("FIRECRAWL_API_BASE_URL", "https://api.firecrawl.dev"), ) +FIRECRAWL_TIMEOUT = PersistentConfig( + "FIRECRAWL_TIMEOUT", + "rag.web.loader.firecrawl_timeout", + os.environ.get("FIRECRAWL_TIMEOUT", ""), +) + EXTERNAL_WEB_SEARCH_URL = PersistentConfig( "EXTERNAL_WEB_SEARCH_URL", "rag.web.search.external_web_search_url", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 68c90c7eea..952ff7f2e1 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -208,6 +208,7 @@ from open_webui.config import ( PLAYWRIGHT_TIMEOUT, FIRECRAWL_API_BASE_URL, FIRECRAWL_API_KEY, + FIRECRAWL_TIMEOUT, WEB_LOADER_ENGINE, WEB_LOADER_CONCURRENT_REQUESTS, WEB_LOADER_TIMEOUT, @@ -987,6 +988,7 @@ app.state.config.PLAYWRIGHT_WS_URL = PLAYWRIGHT_WS_URL app.state.config.PLAYWRIGHT_TIMEOUT = PLAYWRIGHT_TIMEOUT app.state.config.FIRECRAWL_API_BASE_URL = FIRECRAWL_API_BASE_URL app.state.config.FIRECRAWL_API_KEY = FIRECRAWL_API_KEY +app.state.config.FIRECRAWL_TIMEOUT = FIRECRAWL_TIMEOUT app.state.config.TAVILY_EXTRACT_DEPTH = TAVILY_EXTRACT_DEPTH app.state.EMBEDDING_FUNCTION = None diff --git a/backend/open_webui/retrieval/web/utils.py b/backend/open_webui/retrieval/web/utils.py index eb01976e95..6c1ea4b1bf 100644 --- a/backend/open_webui/retrieval/web/utils.py +++ b/backend/open_webui/retrieval/web/utils.py @@ -36,6 +36,7 @@ from open_webui.config import ( WEB_LOADER_TIMEOUT, FIRECRAWL_API_BASE_URL, FIRECRAWL_API_KEY, + FIRECRAWL_TIMEOUT, TAVILY_API_KEY, TAVILY_EXTRACT_DEPTH, EXTERNAL_WEB_LOADER_URL, @@ -189,6 +190,7 @@ class SafeFireCrawlLoader(BaseLoader, RateLimitMixin, URLProcessingMixin): continue_on_failure: bool = True, api_key: Optional[str] = None, api_url: Optional[str] = None, + timeout: Optional[int] = None, mode: Literal["crawl", "scrape", "map"] = "scrape", proxy: Optional[Dict[str, str]] = None, params: Optional[Dict] = None, @@ -231,6 +233,7 @@ class SafeFireCrawlLoader(BaseLoader, RateLimitMixin, URLProcessingMixin): self.continue_on_failure = continue_on_failure self.api_key = api_key self.api_url = api_url + self.timeout = timeout self.mode = mode self.params = params or {} @@ -253,7 +256,7 @@ class SafeFireCrawlLoader(BaseLoader, RateLimitMixin, URLProcessingMixin): ignore_invalid_urls=True, remove_base64_images=True, max_age=300000, # 5 minutes https://docs.firecrawl.dev/features/fast-scraping#common-maxage-values - wait_timeout=len(self.web_paths) * 3, + wait_timeout=self.timeout if self.timeout else len(self.web_paths) * 3, **self.params, ) @@ -294,7 +297,7 @@ class SafeFireCrawlLoader(BaseLoader, RateLimitMixin, URLProcessingMixin): ignore_invalid_urls=True, remove_base64_images=True, max_age=300000, # 5 minutes https://docs.firecrawl.dev/features/fast-scraping#common-maxage-values - wait_timeout=len(self.web_paths) * 3, + wait_timeout=self.timeout if self.timeout else len(self.web_paths) * 3, **self.params, ) @@ -697,6 +700,11 @@ def get_web_loader( WebLoaderClass = SafeFireCrawlLoader web_loader_args["api_key"] = FIRECRAWL_API_KEY.value web_loader_args["api_url"] = FIRECRAWL_API_BASE_URL.value + if FIRECRAWL_TIMEOUT.value: + try: + web_loader_args["timeout"] = int(FIRECRAWL_TIMEOUT.value) + except ValueError: + pass if WEB_LOADER_ENGINE.value == "tavily": WebLoaderClass = SafeTavilyLoader diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index f35c6b43b6..b93ea9ad8f 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -564,6 +564,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): "PLAYWRIGHT_TIMEOUT": request.app.state.config.PLAYWRIGHT_TIMEOUT, "FIRECRAWL_API_KEY": request.app.state.config.FIRECRAWL_API_KEY, "FIRECRAWL_API_BASE_URL": request.app.state.config.FIRECRAWL_API_BASE_URL, + "FIRECRAWL_TIMEOUT": request.app.state.config.FIRECRAWL_TIMEOUT, "TAVILY_EXTRACT_DEPTH": request.app.state.config.TAVILY_EXTRACT_DEPTH, "EXTERNAL_WEB_SEARCH_URL": request.app.state.config.EXTERNAL_WEB_SEARCH_URL, "EXTERNAL_WEB_SEARCH_API_KEY": request.app.state.config.EXTERNAL_WEB_SEARCH_API_KEY, @@ -624,6 +625,7 @@ class WebConfig(BaseModel): PLAYWRIGHT_TIMEOUT: Optional[int] = None FIRECRAWL_API_KEY: Optional[str] = None FIRECRAWL_API_BASE_URL: Optional[str] = None + FIRECRAWL_TIMEOUT: Optional[str] = None TAVILY_EXTRACT_DEPTH: Optional[str] = None EXTERNAL_WEB_SEARCH_URL: Optional[str] = None EXTERNAL_WEB_SEARCH_API_KEY: Optional[str] = None @@ -1123,6 +1125,7 @@ async def update_rag_config( request.app.state.config.FIRECRAWL_API_BASE_URL = ( form_data.web.FIRECRAWL_API_BASE_URL ) + request.app.state.config.FIRECRAWL_TIMEOUT = form_data.web.FIRECRAWL_TIMEOUT request.app.state.config.EXTERNAL_WEB_SEARCH_URL = ( form_data.web.EXTERNAL_WEB_SEARCH_URL ) @@ -1259,6 +1262,7 @@ async def update_rag_config( "PLAYWRIGHT_TIMEOUT": request.app.state.config.PLAYWRIGHT_TIMEOUT, "FIRECRAWL_API_KEY": request.app.state.config.FIRECRAWL_API_KEY, "FIRECRAWL_API_BASE_URL": request.app.state.config.FIRECRAWL_API_BASE_URL, + "FIRECRAWL_TIMEOUT": request.app.state.config.FIRECRAWL_TIMEOUT, "TAVILY_EXTRACT_DEPTH": request.app.state.config.TAVILY_EXTRACT_DEPTH, "EXTERNAL_WEB_SEARCH_URL": request.app.state.config.EXTERNAL_WEB_SEARCH_URL, "EXTERNAL_WEB_SEARCH_API_KEY": request.app.state.config.EXTERNAL_WEB_SEARCH_API_KEY, diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index 6c9035f3c9..dc679bbe8d 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -628,6 +628,24 @@ bind:value={webConfig.FIRECRAWL_API_KEY} />
+ +
+
+ {$i18n.t('Firecrawl Timeout (s)')} +
+ +
+
+ +
+
+
{:else if webConfig.WEB_SEARCH_ENGINE === 'external'}
From 6c7f966f2a00cb423825899db474137701d6a33a Mon Sep 17 00:00:00 2001 From: Jan Kessler Date: Wed, 31 Dec 2025 23:15:24 +0100 Subject: [PATCH 094/254] properly handle async-generator Redis methods in SentinelRedisProx to fix changed YDocManager's remove_user_from_all_documents (#20145) --- backend/open_webui/utils/redis.py | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/open_webui/utils/redis.py b/backend/open_webui/utils/redis.py index da6df2a7f9..2040633a7b 100644 --- a/backend/open_webui/utils/redis.py +++ b/backend/open_webui/utils/redis.py @@ -42,6 +42,38 @@ class SentinelRedisProxy: return orig_attr if self._async_mode: + if inspect.isasyncgenfunction(orig_attr): + + def _wrapped_iter(*args, **kwargs): + async def _iter(): + for i in range(REDIS_SENTINEL_MAX_RETRY_COUNT): + try: + method = getattr(self._master(), item) + async for value in method(*args, **kwargs): + yield value + return + except ( + redis.exceptions.ConnectionError, + redis.exceptions.ReadOnlyError, + ) as e: + if i < REDIS_SENTINEL_MAX_RETRY_COUNT - 1: + log.debug( + "Redis sentinel fail-over (%s). Retry %s/%s", + type(e).__name__, + i + 1, + REDIS_SENTINEL_MAX_RETRY_COUNT, + ) + continue + log.error( + "Redis operation failed after %s retries: %s", + REDIS_SENTINEL_MAX_RETRY_COUNT, + e, + ) + raise e from e + + return _iter() + + return _wrapped_iter async def _wrapped(*args, **kwargs): for i in range(REDIS_SENTINEL_MAX_RETRY_COUNT): From f7f8a263b92289df8d4f8dbc3bae09bd009a5699 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 02:17:47 +0400 Subject: [PATCH 095/254] feat: JINA_API_BASE_URL --- backend/open_webui/config.py | 6 ++++++ backend/open_webui/main.py | 2 ++ .../open_webui/retrieval/web/jina_search.py | 8 ++++++-- backend/open_webui/routers/retrieval.py | 5 +++++ .../components/admin/Settings/WebSearch.svelte | 18 ++++++++++++++++++ 5 files changed, 37 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 8294e51668..b8f92a26c2 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -3186,6 +3186,12 @@ JINA_API_KEY = PersistentConfig( os.getenv("JINA_API_KEY", ""), ) +JINA_API_BASE_URL = PersistentConfig( + "JINA_API_BASE_URL", + "rag.web.search.jina_api_base_url", + os.getenv("JINA_API_BASE_URL", ""), +) + SEARCHAPI_API_KEY = PersistentConfig( "SEARCHAPI_API_KEY", "rag.web.search.searchapi_api_key", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 952ff7f2e1..516056ada9 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -299,6 +299,7 @@ from open_webui.config import ( WEB_SEARCH_DOMAIN_FILTER_LIST, OLLAMA_CLOUD_WEB_SEARCH_API_KEY, JINA_API_KEY, + JINA_API_BASE_URL, SEARCHAPI_API_KEY, SEARCHAPI_ENGINE, SERPAPI_API_KEY, @@ -969,6 +970,7 @@ app.state.config.SEARCHAPI_ENGINE = SEARCHAPI_ENGINE app.state.config.SERPAPI_API_KEY = SERPAPI_API_KEY app.state.config.SERPAPI_ENGINE = SERPAPI_ENGINE app.state.config.JINA_API_KEY = JINA_API_KEY +app.state.config.JINA_API_BASE_URL = JINA_API_BASE_URL app.state.config.BING_SEARCH_V7_ENDPOINT = BING_SEARCH_V7_ENDPOINT app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY = BING_SEARCH_V7_SUBSCRIPTION_KEY app.state.config.EXA_API_KEY = EXA_API_KEY diff --git a/backend/open_webui/retrieval/web/jina_search.py b/backend/open_webui/retrieval/web/jina_search.py index bcc5794027..d1168bb36f 100644 --- a/backend/open_webui/retrieval/web/jina_search.py +++ b/backend/open_webui/retrieval/web/jina_search.py @@ -7,17 +7,21 @@ from yarl import URL log = logging.getLogger(__name__) -def search_jina(api_key: str, query: str, count: int) -> list[SearchResult]: +def search_jina( + api_key: str, query: str, count: int, base_url: str = "" +) -> list[SearchResult]: """ Search using Jina's Search API and return the results as a list of SearchResult objects. Args: + api_key (str): The Jina API key query (str): The query to search for count (int): The number of results to return + base_url (str): Optional custom base URL for the Jina API Returns: list[SearchResult]: A list of search results """ - jina_search_endpoint = "https://s.jina.ai/" + jina_search_endpoint = base_url if base_url else "https://s.jina.ai/" headers = { "Accept": "application/json", diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index b93ea9ad8f..6f6baedc91 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -548,6 +548,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): "SERPAPI_API_KEY": request.app.state.config.SERPAPI_API_KEY, "SERPAPI_ENGINE": request.app.state.config.SERPAPI_ENGINE, "JINA_API_KEY": request.app.state.config.JINA_API_KEY, + "JINA_API_BASE_URL": request.app.state.config.JINA_API_BASE_URL, "BING_SEARCH_V7_ENDPOINT": request.app.state.config.BING_SEARCH_V7_ENDPOINT, "BING_SEARCH_V7_SUBSCRIPTION_KEY": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY, "EXA_API_KEY": request.app.state.config.EXA_API_KEY, @@ -609,6 +610,7 @@ class WebConfig(BaseModel): SERPAPI_API_KEY: Optional[str] = None SERPAPI_ENGINE: Optional[str] = None JINA_API_KEY: Optional[str] = None + JINA_API_BASE_URL: Optional[str] = None BING_SEARCH_V7_ENDPOINT: Optional[str] = None BING_SEARCH_V7_SUBSCRIPTION_KEY: Optional[str] = None EXA_API_KEY: Optional[str] = None @@ -1094,6 +1096,7 @@ async def update_rag_config( request.app.state.config.SERPAPI_API_KEY = form_data.web.SERPAPI_API_KEY request.app.state.config.SERPAPI_ENGINE = form_data.web.SERPAPI_ENGINE request.app.state.config.JINA_API_KEY = form_data.web.JINA_API_KEY + request.app.state.config.JINA_API_BASE_URL = form_data.web.JINA_API_BASE_URL request.app.state.config.BING_SEARCH_V7_ENDPOINT = ( form_data.web.BING_SEARCH_V7_ENDPOINT ) @@ -1246,6 +1249,7 @@ async def update_rag_config( "SERPAPI_API_KEY": request.app.state.config.SERPAPI_API_KEY, "SERPAPI_ENGINE": request.app.state.config.SERPAPI_ENGINE, "JINA_API_KEY": request.app.state.config.JINA_API_KEY, + "JINA_API_BASE_URL": request.app.state.config.JINA_API_BASE_URL, "BING_SEARCH_V7_ENDPOINT": request.app.state.config.BING_SEARCH_V7_ENDPOINT, "BING_SEARCH_V7_SUBSCRIPTION_KEY": request.app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY, "EXA_API_KEY": request.app.state.config.EXA_API_KEY, @@ -2027,6 +2031,7 @@ def search_web( request.app.state.config.JINA_API_KEY, query, request.app.state.config.WEB_SEARCH_RESULT_COUNT, + request.app.state.config.JINA_API_BASE_URL, ) elif engine == "bing": return search_bing( diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index dc679bbe8d..4cbd581154 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -469,6 +469,24 @@ {:else if webConfig.WEB_SEARCH_ENGINE === 'jina'}
+
+ {$i18n.t('Jina API Base URL')} +
+ +
+
+ +
+
+
+ +
{$i18n.t('Jina API Key')}
From 4eadf84e1f6f045ae47723d4da5bc98884e4694e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 02:23:42 +0400 Subject: [PATCH 096/254] refac --- backend/open_webui/models/channels.py | 81 +++++++++++++++++++-------- 1 file changed, 58 insertions(+), 23 deletions(-) diff --git a/backend/open_webui/models/channels.py b/backend/open_webui/models/channels.py index 55275688a4..dc13d362d8 100644 --- a/backend/open_webui/models/channels.py +++ b/backend/open_webui/models/channels.py @@ -1,4 +1,3 @@ - import json import time import uuid @@ -386,7 +385,9 @@ class ChannelTable: return query - def get_channels_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[ChannelModel]: + def get_channels_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[ChannelModel]: with get_db_context(db) as db: user_group_ids = [ group.id for group in Groups.get_groups_by_member_id(user_id, db=db) @@ -423,7 +424,9 @@ class ChannelTable: all_channels = membership_channels + standard_channels return [ChannelModel.model_validate(c) for c in all_channels] - def get_dm_channel_by_user_ids(self, user_ids: list[str], db: Optional[Session] = None) -> Optional[ChannelModel]: + def get_dm_channel_by_user_ids( + self, user_ids: list[str], db: Optional[Session] = None + ) -> Optional[ChannelModel]: with get_db_context(db) as db: # Ensure uniqueness in case a list with duplicates is passed unique_user_ids = list(set(user_ids)) @@ -511,7 +514,9 @@ class ChannelTable: db.commit() return result # number of rows deleted - def is_user_channel_manager(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + def is_user_channel_manager( + self, channel_id: str, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: # Check if the user is the creator of the channel # or has a 'manager' role in ChannelMember @@ -569,7 +574,9 @@ class ChannelTable: db.commit() return channel_member - def leave_channel(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + def leave_channel( + self, channel_id: str, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: membership = ( db.query(ChannelMember) @@ -604,7 +611,9 @@ class ChannelTable: ) return ChannelMemberModel.model_validate(membership) if membership else None - def get_members_by_channel_id(self, channel_id: str, db: Optional[Session] = None) -> list[ChannelMemberModel]: + def get_members_by_channel_id( + self, channel_id: str, db: Optional[Session] = None + ) -> list[ChannelMemberModel]: with get_db_context(db) as db: memberships = ( db.query(ChannelMember) @@ -616,7 +625,13 @@ class ChannelTable: for membership in memberships ] - def pin_channel(self, channel_id: str, user_id: str, is_pinned: bool, db: Optional[Session] = None) -> bool: + def pin_channel( + self, + channel_id: str, + user_id: str, + is_pinned: bool, + db: Optional[Session] = None, + ) -> bool: with get_db_context(db) as db: membership = ( db.query(ChannelMember) @@ -635,7 +650,9 @@ class ChannelTable: db.commit() return True - def update_member_last_read_at(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + def update_member_last_read_at( + self, channel_id: str, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: membership = ( db.query(ChannelMember) @@ -655,7 +672,11 @@ class ChannelTable: return True def update_member_active_status( - self, channel_id: str, user_id: str, is_active: bool, db: Optional[Session] = None + self, + channel_id: str, + user_id: str, + is_active: bool, + db: Optional[Session] = None, ) -> bool: with get_db_context(db) as db: membership = ( @@ -675,7 +696,9 @@ class ChannelTable: db.commit() return True - def is_user_channel_member(self, channel_id: str, user_id: str, db: Optional[Session] = None) -> bool: + def is_user_channel_member( + self, channel_id: str, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: membership = ( db.query(ChannelMember) @@ -687,7 +710,9 @@ class ChannelTable: ) return membership is not None - def get_channel_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChannelModel]: + def get_channel_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ChannelModel]: try: with get_db_context(db) as db: channel = db.query(Channel).filter(Channel.id == id).first() @@ -695,7 +720,9 @@ class ChannelTable: except Exception: return None - def get_channels_by_file_id(self, file_id: str, db: Optional[Session] = None) -> list[ChannelModel]: + def get_channels_by_file_id( + self, file_id: str, db: Optional[Session] = None + ) -> list[ChannelModel]: with get_db_context(db) as db: channel_files = ( db.query(ChannelFile).filter(ChannelFile.file_id == file_id).all() @@ -731,7 +758,9 @@ class ChannelTable: return [] # Preload user's group membership - user_group_ids = [g.id for g in Groups.get_groups_by_member_id(user_id, db=db)] + user_group_ids = [ + g.id for g in Groups.get_groups_by_member_id(user_id, db=db) + ] allowed_channels = [] @@ -825,9 +854,9 @@ class ChannelTable: ) def update_channel_by_id( - self, id: str, form_data: ChannelForm + self, id: str, form_data: ChannelForm, db: Optional[Session] = None ) -> Optional[ChannelModel]: - with get_db() as db: + with get_db_context(db) as db: channel = db.query(Channel).filter(Channel.id == id).first() if not channel: return None @@ -846,9 +875,9 @@ class ChannelTable: return ChannelModel.model_validate(channel) if channel else None def add_file_to_channel_by_id( - self, channel_id: str, file_id: str, user_id: str + self, channel_id: str, file_id: str, user_id: str, db: Optional[Session] = None ) -> Optional[ChannelFileModel]: - with get_db() as db: + with get_db_context(db) as db: channel_file = ChannelFileModel( **{ "id": str(uuid.uuid4()), @@ -873,10 +902,14 @@ class ChannelTable: return None def set_file_message_id_in_channel_by_id( - self, channel_id: str, file_id: str, message_id: str + self, + channel_id: str, + file_id: str, + message_id: str, + db: Optional[Session] = None, ) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: channel_file = ( db.query(ChannelFile) .filter_by(channel_id=channel_id, file_id=file_id) @@ -893,9 +926,11 @@ class ChannelTable: except Exception: return False - def remove_file_from_channel_by_id(self, channel_id: str, file_id: str) -> bool: + def remove_file_from_channel_by_id( + self, channel_id: str, file_id: str, db: Optional[Session] = None + ) -> bool: try: - with get_db() as db: + with get_db_context(db) as db: db.query(ChannelFile).filter_by( channel_id=channel_id, file_id=file_id ).delete() @@ -904,8 +939,8 @@ class ChannelTable: except Exception: return False - def delete_channel_by_id(self, id: str): - with get_db() as db: + def delete_channel_by_id(self, id: str, db: Optional[Session] = None) -> bool: + with get_db_context(db) as db: db.query(Channel).filter(Channel.id == id).delete() db.commit() return True From a1036e544d573e3d35e05c1c2472ba762c32431b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 02:51:35 +0400 Subject: [PATCH 097/254] enh: folder_max_file_count --- backend/open_webui/config.py | 6 +++++ backend/open_webui/main.py | 3 +++ backend/open_webui/routers/auths.py | 4 ++++ .../components/admin/Settings/General.svelte | 22 +++++++++++++++++++ .../layout/Sidebar/Folders/FolderModal.svelte | 10 ++++++++- src/lib/stores/index.ts | 1 + 6 files changed, 45 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index b8f92a26c2..9ed61fbb9e 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1543,6 +1543,12 @@ ENABLE_FOLDERS = PersistentConfig( os.environ.get("ENABLE_FOLDERS", "True").lower() == "true", ) +FOLDER_MAX_FILE_COUNT = PersistentConfig( + "FOLDER_MAX_FILE_COUNT", + "folders.max_file_count", + int(os.environ.get("FOLDER_MAX_FILE_COUNT", "100")), +) + ENABLE_CHANNELS = PersistentConfig( "ENABLE_CHANNELS", "channels.enable", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 516056ada9..320e5c5cf3 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -363,6 +363,7 @@ from open_webui.config import ( ENABLE_API_KEYS_ENDPOINT_RESTRICTIONS, API_KEYS_ALLOWED_ENDPOINTS, ENABLE_FOLDERS, + FOLDER_MAX_FILE_COUNT, ENABLE_CHANNELS, ENABLE_NOTES, ENABLE_COMMUNITY_SHARING, @@ -779,6 +780,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_CHANNELS = ENABLE_CHANNELS app.state.config.ENABLE_NOTES = ENABLE_NOTES app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING @@ -1913,6 +1915,7 @@ async def get_app_config(request: Request): { "enable_direct_connections": app.state.config.ENABLE_DIRECT_CONNECTIONS, "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_notes": app.state.config.ENABLE_NOTES, "enable_web_search": app.state.config.ENABLE_WEB_SEARCH, diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index c9e7368507..34cb41727c 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -989,6 +989,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)): "ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING, "ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING, "ENABLE_FOLDERS": request.app.state.config.ENABLE_FOLDERS, + "FOLDER_MAX_FILE_COUNT": request.app.state.config.FOLDER_MAX_FILE_COUNT, "ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS, "ENABLE_NOTES": request.app.state.config.ENABLE_NOTES, "ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS, @@ -1012,6 +1013,7 @@ class AdminConfig(BaseModel): ENABLE_COMMUNITY_SHARING: bool ENABLE_MESSAGE_RATING: bool ENABLE_FOLDERS: bool + FOLDER_MAX_FILE_COUNT: int ENABLE_CHANNELS: bool ENABLE_NOTES: bool ENABLE_USER_WEBHOOKS: bool @@ -1038,6 +1040,7 @@ async def update_admin_config( ) request.app.state.config.ENABLE_FOLDERS = form_data.ENABLE_FOLDERS + request.app.state.config.FOLDER_MAX_FILE_COUNT = form_data.FOLDER_MAX_FILE_COUNT request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES @@ -1082,6 +1085,7 @@ async def update_admin_config( "ENABLE_COMMUNITY_SHARING": request.app.state.config.ENABLE_COMMUNITY_SHARING, "ENABLE_MESSAGE_RATING": request.app.state.config.ENABLE_MESSAGE_RATING, "ENABLE_FOLDERS": request.app.state.config.ENABLE_FOLDERS, + "FOLDER_MAX_FILE_COUNT": request.app.state.config.FOLDER_MAX_FILE_COUNT, "ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS, "ENABLE_NOTES": request.app.state.config.ENABLE_NOTES, "ENABLE_USER_WEBHOOKS": request.app.state.config.ENABLE_USER_WEBHOOKS, diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index 60e66fe351..554951c8d7 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -701,6 +701,28 @@
+ {#if adminConfig.ENABLE_FOLDERS} +
+
+
{$i18n.t('Folder Max File Count')}
+
+ +
+ +
+ +
+ {$i18n.t('Maximum number of files allowed per folder.')} +
+
+ {/if} +
{$i18n.t('Notes')} ({$i18n.t('Beta')}) diff --git a/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte b/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte index cb743b5c71..55c0dbaef8 100644 --- a/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte +++ b/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte @@ -8,7 +8,7 @@ import { toast } from 'svelte-sonner'; import { page } from '$app/stores'; import { goto } from '$app/navigation'; - import { user } from '$lib/stores'; + import { user, config } from '$lib/stores'; import Textarea from '$lib/components/common/Textarea.svelte'; import Knowledge from '$lib/components/workspace/Models/Knowledge.svelte'; @@ -42,6 +42,14 @@ return; } + // Check folder max file count limit + const maxFileCount = $config?.features?.folder_max_file_count ?? null; + if (maxFileCount !== null && (data?.files ?? []).length > maxFileCount) { + toast.error($i18n.t('Maximum number of files per folder is {{max}}.', { max: maxFileCount })); + loading = false; + return; + } + await onSubmit({ name, meta, diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index 7d75c3253a..9932dba052 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -276,6 +276,7 @@ type Config = { enable_autocomplete_generation: boolean; enable_direct_connections: boolean; enable_version_update_check: boolean; + folder_max_file_count?: number; }; oauth: { providers: { From b67796465e565d992da0a43be0d9665a514ab1c2 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 03:03:10 +0400 Subject: [PATCH 098/254] refac --- .../chat/Settings/SyncStatsModal.svelte | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/lib/components/chat/Settings/SyncStatsModal.svelte b/src/lib/components/chat/Settings/SyncStatsModal.svelte index e03888d47b..5adb29b629 100644 --- a/src/lib/components/chat/Settings/SyncStatsModal.svelte +++ b/src/lib/components/chat/Settings/SyncStatsModal.svelte @@ -59,7 +59,6 @@ window.removeEventListener('message', handleMessage); }); - // State let syncing = false; let downloading = false; @@ -78,15 +77,13 @@ let syncMode: 'incremental' | 'full' = 'incremental'; // Reactive progress percentage - $: progressPercent = total > 0 ? Math.min(Math.round((processedItemsCount / total) * 100), 100) : 0; + $: progressPercent = + total > 0 ? Math.min(Math.round((processedItemsCount / total) * 100), 100) : 0; // Helper to send postMessage to opener const postToOpener = (message: object) => { if (window.opener) { - window.opener.postMessage( - { ...message, requestId: eventData?.requestId ?? null }, - '*' - ); + window.opener.postMessage({ ...message, requestId: eventData?.requestId ?? null }, '*'); } }; @@ -120,6 +117,8 @@ } syncing = false; downloading = false; + + postToOpener({ type: 'sync:error', error: 'User cancelled the operation' }); }; // Sync stats to opener window @@ -157,11 +156,7 @@ searchParams.updated_at = eventData.lastSyncedChatUpdatedAt; } - const res = await exportChatStats( - localStorage.token, - page, - searchParams - ).catch((err) => { + const res = await exportChatStats(localStorage.token, page, searchParams).catch((err) => { throw new Error(err?.detail || err?.message || 'Failed to export chat stats'); }); @@ -211,16 +206,12 @@ try { // Get total count first (no filters for download - get all) - const initialRes = await exportChatStats( - localStorage.token, - 1, - {} - ).catch(() => null); + const initialRes = await exportChatStats(localStorage.token, 1, {}).catch(() => null); if (initialRes?.total) { total = initialRes.total; } - + // Allow UI to show the total await tick(); @@ -235,7 +226,9 @@ localStorage.token, searchParams.updated_at ).catch((err) => { - throw new Error(err?.detail || 'Failed to connect to the server. Please check your connection.'); + throw new Error( + err?.detail || 'Failed to connect to the server. Please check your connection.' + ); }); if (!res) { @@ -404,16 +397,23 @@ {#if eventData?.lastSyncedChatUpdatedAt}
- +
@@ -428,8 +428,6 @@
{#if total > 0} {processedItemsCount}/{total} - {:else} - {processedItemsCount} {/if}
@@ -440,7 +438,9 @@ style="width: {progressPercent}%" >
{:else} -
+
{/if}
From c144122f608759c2b79472e1f6948a7c1600a3d1 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 03:10:09 +0400 Subject: [PATCH 099/254] refac/fix: reply to message recursion issue --- backend/open_webui/models/messages.py | 81 +++++++++++++++++++++------ 1 file changed, 65 insertions(+), 16 deletions(-) diff --git a/backend/open_webui/models/messages.py b/backend/open_webui/models/messages.py index 8fe37e58ea..c0e2007b2d 100644 --- a/backend/open_webui/models/messages.py +++ b/backend/open_webui/models/messages.py @@ -138,7 +138,11 @@ class MessageResponse(MessageReplyToResponse): class MessageTable: def insert_new_message( - self, form_data: MessageForm, channel_id: str, user_id: str, db: Optional[Session] = None + self, + form_data: MessageForm, + channel_id: str, + user_id: str, + db: Optional[Session] = None, ) -> Optional[MessageModel]: with get_db_context(db) as db: channel_member = Channels.join_channel(channel_id, user_id) @@ -170,20 +174,30 @@ class MessageTable: db.refresh(result) return MessageModel.model_validate(result) if result else None - def get_message_by_id(self, id: str, db: Optional[Session] = None) -> Optional[MessageResponse]: + def get_message_by_id( + self, + id: str, + include_thread_replies: Optional[bool] = True, + db: Optional[Session] = None, + ) -> Optional[MessageResponse]: with get_db_context(db) as db: message = db.get(Message, id) if not message: return None reply_to_message = ( - self.get_message_by_id(message.reply_to_id, db=db) + self.get_message_by_id( + message.reply_to_id, include_thread_replies=False, db=db + ) if message.reply_to_id else None ) reactions = self.get_reactions_by_message_id(id, db=db) - thread_replies = self.get_thread_replies_by_message_id(id, db=db) + + thread_replies = [] + if include_thread_replies: + thread_replies = self.get_thread_replies_by_message_id(id, db=db) user = Users.get_user_by_id(message.user_id, db=db) return MessageResponse.model_validate( @@ -201,7 +215,9 @@ class MessageTable: } ) - def get_thread_replies_by_message_id(self, id: str, db: Optional[Session] = None) -> list[MessageReplyToResponse]: + def get_thread_replies_by_message_id( + self, id: str, db: Optional[Session] = None + ) -> list[MessageReplyToResponse]: with get_db_context(db) as db: all_messages = ( db.query(Message) @@ -213,7 +229,9 @@ class MessageTable: messages = [] for message in all_messages: reply_to_message = ( - self.get_message_by_id(message.reply_to_id, db=db) + self.get_message_by_id( + message.reply_to_id, include_thread_replies=False, db=db + ) if message.reply_to_id else None ) @@ -231,7 +249,9 @@ class MessageTable: ) return messages - def get_reply_user_ids_by_message_id(self, id: str, db: Optional[Session] = None) -> list[str]: + def get_reply_user_ids_by_message_id( + self, id: str, db: Optional[Session] = None + ) -> list[str]: with get_db_context(db) as db: return [ message.user_id @@ -239,7 +259,11 @@ class MessageTable: ] def get_messages_by_channel_id( - self, channel_id: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None + self, + channel_id: str, + skip: int = 0, + limit: int = 50, + db: Optional[Session] = None, ) -> list[MessageReplyToResponse]: with get_db_context(db) as db: all_messages = ( @@ -254,7 +278,9 @@ class MessageTable: messages = [] for message in all_messages: reply_to_message = ( - self.get_message_by_id(message.reply_to_id, db=db) + self.get_message_by_id( + message.reply_to_id, include_thread_replies=False, db=db + ) if message.reply_to_id else None ) @@ -273,7 +299,12 @@ class MessageTable: return messages def get_messages_by_parent_id( - self, channel_id: str, parent_id: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None + self, + channel_id: str, + parent_id: str, + skip: int = 0, + limit: int = 50, + db: Optional[Session] = None, ) -> list[MessageReplyToResponse]: with get_db_context(db) as db: message = db.get(Message, parent_id) @@ -297,7 +328,9 @@ class MessageTable: messages = [] for message in all_messages: reply_to_message = ( - self.get_message_by_id(message.reply_to_id, db=db) + self.get_message_by_id( + message.reply_to_id, include_thread_replies=False, db=db + ) if message.reply_to_id else None ) @@ -315,7 +348,9 @@ class MessageTable: ) return messages - def get_last_message_by_channel_id(self, channel_id: str, db: Optional[Session] = None) -> Optional[MessageModel]: + def get_last_message_by_channel_id( + self, channel_id: str, db: Optional[Session] = None + ) -> Optional[MessageModel]: with get_db_context(db) as db: message = ( db.query(Message) @@ -326,7 +361,11 @@ class MessageTable: return MessageModel.model_validate(message) if message else None def get_pinned_messages_by_channel_id( - self, channel_id: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None + self, + channel_id: str, + skip: int = 0, + limit: int = 50, + db: Optional[Session] = None, ) -> list[MessageModel]: with get_db_context(db) as db: all_messages = ( @@ -359,7 +398,11 @@ class MessageTable: return MessageModel.model_validate(message) if message else None def update_is_pinned_by_id( - self, id: str, is_pinned: bool, pinned_by: Optional[str] = None, db: Optional[Session] = None + self, + id: str, + is_pinned: bool, + pinned_by: Optional[str] = None, + db: Optional[Session] = None, ) -> Optional[MessageModel]: with get_db_context(db) as db: message = db.get(Message, id) @@ -371,7 +414,11 @@ class MessageTable: return MessageModel.model_validate(message) if message else None def get_unread_message_count( - self, channel_id: str, user_id: str, last_read_at: Optional[int] = None, db: Optional[Session] = None + self, + channel_id: str, + user_id: str, + last_read_at: Optional[int] = None, + db: Optional[Session] = None, ) -> int: with get_db_context(db) as db: query = db.query(Message).filter( @@ -410,7 +457,9 @@ class MessageTable: db.refresh(result) return MessageReactionModel.model_validate(result) if result else None - def get_reactions_by_message_id(self, id: str, db: Optional[Session] = None) -> list[Reactions]: + def get_reactions_by_message_id( + self, id: str, db: Optional[Session] = None + ) -> list[Reactions]: with get_db_context(db) as db: # JOIN User so all user info is fetched in one query results = ( From f9818438529ce721075d0215a277b7d12efd0906 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 13:45:37 +0400 Subject: [PATCH 100/254] refac --- src/lib/components/channel/Thread.svelte | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib/components/channel/Thread.svelte b/src/lib/components/channel/Thread.svelte index c1c6e2e304..48028bcc23 100644 --- a/src/lib/components/channel/Thread.svelte +++ b/src/lib/components/channel/Thread.svelte @@ -223,6 +223,7 @@ bind:replyToMessage bind:chatInputElement id={threadId} + {channel} disabled={!channel?.write_access} placeholder={!channel?.write_access ? $i18n.t('You do not have permission to send messages in this thread.') From 89565c58c6ae6b5b129559ef68b5a0c18c110765 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 14:01:18 +0400 Subject: [PATCH 101/254] refac/fix: oauth discovery urls Co-Authored-By: jamie-dit <80016430+jamie-dit@users.noreply.github.com> --- backend/open_webui/utils/oauth.py | 64 +++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/utils/oauth.py b/backend/open_webui/utils/oauth.py index d30eec3a73..c849eb25a8 100644 --- a/backend/open_webui/utils/oauth.py +++ b/backend/open_webui/utils/oauth.py @@ -246,10 +246,66 @@ def get_parsed_and_base_url(server_url) -> tuple[urllib.parse.ParseResult, str]: return parsed, base_url -def get_discovery_urls(server_url) -> list[str]: - parsed, base_url = get_parsed_and_base_url(server_url) +async def get_authorization_server_discovery_urls(server_url: str) -> list[str]: + """ + https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization + """ - urls = [] + authorization_servers = [] + try: + async with aiohttp.ClientSession(trust_env=True) as session: + async with session.post( + server_url, + json={"jsonrpc": "2.0", "method": "initialize", "params": {}, "id": 1}, + headers={"Content-Type": "application/json"}, + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + if response.status == 401: + match = re.search( + r'resource_metadata="([^"]+)"', + response.headers.get("WWW-Authenticate", ""), + ) + if match: + resource_metadata_url = match.group(1) + log.debug( + f"Found resource_metadata URL: {resource_metadata_url}" + ) + + # 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() + + # Step 3: Extract authorization_servers + servers = resource_metadata.get( + "authorization_servers", [] + ) + if servers: + authorization_servers = servers + log.debug( + f"Discovered authorization servers: {servers}" + ) + 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", + ] + ) + + return discovery_urls + + +async def get_discovery_urls(server_url) -> list[str]: + urls = await get_authorization_server_discovery_urls(server_url) + parsed, base_url = get_parsed_and_base_url(server_url) if parsed.path and parsed.path != "/": # Generate discovery URLs based on https://modelcontextprotocol.io/specification/draft/basic/authorization#authorization-server-metadata-discovery @@ -303,7 +359,7 @@ async def get_oauth_client_info_with_dynamic_client_registration( ) # Attempt to fetch OAuth server metadata to get registration endpoint & scopes - discovery_urls = get_discovery_urls(oauth_server_url) + discovery_urls = await get_discovery_urls(oauth_server_url) for url in discovery_urls: async with aiohttp.ClientSession(trust_env=True) as session: async with session.get( From d3ee3fd23e762c9d83fe1da5636d03259e186e57 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 14:10:11 +0400 Subject: [PATCH 102/254] refac --- backend/open_webui/config.py | 2 +- backend/open_webui/routers/auths.py | 8 +++-- .../components/admin/Settings/General.svelte | 34 ++++++++++--------- .../layout/Sidebar/Folders/FolderModal.svelte | 4 ++- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 9ed61fbb9e..dac65f0ccb 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1546,7 +1546,7 @@ ENABLE_FOLDERS = PersistentConfig( FOLDER_MAX_FILE_COUNT = PersistentConfig( "FOLDER_MAX_FILE_COUNT", "folders.max_file_count", - int(os.environ.get("FOLDER_MAX_FILE_COUNT", "100")), + os.environ.get("FOLDER_MAX_FILE_COUNT", ""), ) ENABLE_CHANNELS = PersistentConfig( diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 34cb41727c..fb0c141379 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -1013,7 +1013,7 @@ class AdminConfig(BaseModel): ENABLE_COMMUNITY_SHARING: bool ENABLE_MESSAGE_RATING: bool ENABLE_FOLDERS: bool - FOLDER_MAX_FILE_COUNT: int + FOLDER_MAX_FILE_COUNT: Optional[int | str] = None ENABLE_CHANNELS: bool ENABLE_NOTES: bool ENABLE_USER_WEBHOOKS: bool @@ -1040,7 +1040,11 @@ async def update_admin_config( ) request.app.state.config.ENABLE_FOLDERS = form_data.ENABLE_FOLDERS - request.app.state.config.FOLDER_MAX_FILE_COUNT = form_data.FOLDER_MAX_FILE_COUNT + request.app.state.config.FOLDER_MAX_FILE_COUNT = ( + int(form_data.FOLDER_MAX_FILE_COUNT) + if form_data.FOLDER_MAX_FILE_COUNT + else None + ) request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index 554951c8d7..0b56de20e8 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -334,22 +334,22 @@ - {#if adminConfig.SHOW_ADMIN_DETAILS} -
-
-
{$i18n.t('Admin Contact Email')}
-
+ {#if adminConfig.SHOW_ADMIN_DETAILS} +
+
+
{$i18n.t('Admin Contact Email')}
+
-
- +
+ +
-
- {/if} + {/if}
@@ -704,14 +704,16 @@ {#if adminConfig.ENABLE_FOLDERS}
-
{$i18n.t('Folder Max File Count')}
+
+ {$i18n.t('Folder Max File Count')} +
diff --git a/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte b/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte index 55c0dbaef8..48bbaa08a4 100644 --- a/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte +++ b/src/lib/components/layout/Sidebar/Folders/FolderModal.svelte @@ -45,7 +45,9 @@ // Check folder max file count limit const maxFileCount = $config?.features?.folder_max_file_count ?? null; if (maxFileCount !== null && (data?.files ?? []).length > maxFileCount) { - toast.error($i18n.t('Maximum number of files per folder is {{max}}.', { max: maxFileCount })); + toast.error( + $i18n.t('Maximum number of files per folder is {{max}}.', { max: maxFileCount ?? 0 }) + ); loading = false; return; } From e4a5b06ca68303512678b4d2dc296bc78b9f983f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 1 Jan 2026 16:06:42 +0400 Subject: [PATCH 103/254] enh: embedding_batch_size for local embedding engine --- backend/open_webui/retrieval/utils.py | 4 ++- .../admin/Settings/Documents.svelte | 32 +++++++++---------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index 772f37fbec..c83c2d1207 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -795,7 +795,9 @@ def get_embedding_function( return await asyncio.to_thread( ( lambda query, prefix=None: embedding_function.encode( - query, **({"prompt": prefix} if prefix else {}) + query, + batch_size=int(embedding_batch_size), + **({"prompt": prefix} if prefix else {}), ).tolist() ), query, diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index dfed23dc45..650ce8b055 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -950,24 +950,24 @@
- {#if RAG_EMBEDDING_ENGINE === 'ollama' || RAG_EMBEDDING_ENGINE === 'openai' || RAG_EMBEDDING_ENGINE === 'azure_openai'} -
-
- {$i18n.t('Embedding Batch Size')} -
- -
- -
+
+
+ {$i18n.t('Embedding Batch Size')}
+
+ +
+
+ + {#if RAG_EMBEDDING_ENGINE === 'ollama' || RAG_EMBEDDING_ENGINE === 'openai' || RAG_EMBEDDING_ENGINE === 'azure_openai'}
Date: Thu, 1 Jan 2026 16:09:29 +0400 Subject: [PATCH 104/254] refac: deprecate generate image action button --- .../chat/Messages/ResponseMessage.svelte | 90 ------------------- 1 file changed, 90 deletions(-) diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 51699dea15..7c22735606 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -170,7 +170,6 @@ let speakingIdx: number | undefined; let loadingSpeech = false; - let generatingImage = false; let showRateComment = false; @@ -390,28 +389,6 @@ await tick(); }; - const generateImage = async (message: MessageType) => { - generatingImage = true; - const res = await imageGenerations(localStorage.token, message.content).catch((error) => { - toast.error(`${error}`); - }); - console.log(res); - - if (res) { - const files = res.map((image) => ({ - type: 'image', - url: `${image.url}` - })); - - saveMessage(message.id, { - ...message, - files: files - }); - } - - generatingImage = false; - }; - let feedbackLoading = false; const feedbackHandler = async (rating: number | null = null, details: object | null = null) => { @@ -1092,73 +1069,6 @@ {/if} - {#if $config?.features.enable_image_generation && ($user?.role === 'admin' || $user?.permissions?.features?.image_generation) && !readOnly} - - - - {/if} - {#if message.usage} Date: Fri, 2 Jan 2026 16:56:13 +0400 Subject: [PATCH 105/254] refac --- src/lib/components/chat/Settings/SyncStatsModal.svelte | 5 +++++ src/routes/+layout.svelte | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/lib/components/chat/Settings/SyncStatsModal.svelte b/src/lib/components/chat/Settings/SyncStatsModal.svelte index 5adb29b629..0fcedcb1de 100644 --- a/src/lib/components/chat/Settings/SyncStatsModal.svelte +++ b/src/lib/components/chat/Settings/SyncStatsModal.svelte @@ -51,6 +51,11 @@ } }; + // Watch for modal visibility changes to notify opener + $: if (show && window.opener) { + window.opener.postMessage('loaded', '*'); + } + onMount(() => { window.addEventListener('message', handleMessage); }); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index c7bb8c5c50..25c14101c3 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -835,9 +835,9 @@ loaded = true; } - // Notify opener window that the app has loaded - if (window.opener ?? false) { - window.opener.postMessage('loaded', '*'); + // Auto-show SyncStatsModal when opened with ?sync=true (from community) + if ((window.opener ?? false) && $page.url.searchParams.get('sync') === 'true') { + showSyncStatsModal = true; } return () => { From cfecca8edadce6be0093c7da78637d630bee4ee3 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Sat, 3 Jan 2026 09:10:03 -0500 Subject: [PATCH 106/254] fix: handle undefined file.url in UserMessage to prevent TypeError (#20343) Add optional chaining to file.url.startsWith() calls to safely handle cases where file.url is undefined, preventing 'can't access property startsWith' TypeError in user messages with file attachments. --- src/lib/components/chat/Messages/UserMessage.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index fd2b3fb27a..7f83ad6db3 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -194,7 +194,7 @@ > {#each message.files as file} {@const fileUrl = - file.url.startsWith('data') || file.url.startsWith('http') + file.url?.startsWith('data') || file.url?.startsWith('http') ? file.url : `${WEBUI_API_BASE_URL}/files/${file.url}${file?.content_type ? '/content' : ''}`}
From bf42535d12b921dd2ee4984697bab688071a8796 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Sat, 3 Jan 2026 09:11:13 -0500 Subject: [PATCH 107/254] feat: add support for passing 'steps' in image generation requests (#20337) --- backend/open_webui/routers/images.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/routers/images.py b/backend/open_webui/routers/images.py index 11e192e6ba..7f1b0b9bde 100644 --- a/backend/open_webui/routers/images.py +++ b/backend/open_webui/routers/images.py @@ -463,6 +463,7 @@ class CreateImageForm(BaseModel): prompt: str size: Optional[str] = None n: int = 1 + steps: Optional[int] = None negative_prompt: Optional[str] = None @@ -706,8 +707,12 @@ async def image_generations( "n": form_data.n, } - if request.app.state.config.IMAGE_STEPS is not None: - data["steps"] = request.app.state.config.IMAGE_STEPS + if request.app.state.config.IMAGE_STEPS is not None or form_data.steps is not None: + data["steps"] = ( + form_data.steps + if form_data.steps is not None + else request.app.state.config.IMAGE_STEPS + ) if form_data.negative_prompt is not None: data["negative_prompt"] = form_data.negative_prompt @@ -765,8 +770,12 @@ async def image_generations( "height": height, } - if request.app.state.config.IMAGE_STEPS is not None: - data["steps"] = request.app.state.config.IMAGE_STEPS + if request.app.state.config.IMAGE_STEPS is not None or form_data.steps is not None: + data["steps"] = ( + form_data.steps + if form_data.steps is not None + else request.app.state.config.IMAGE_STEPS + ) if form_data.negative_prompt is not None: data["negative_prompt"] = form_data.negative_prompt From 8712446cc16ebf967715c134b2840bbc7ccf13f2 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Sat, 3 Jan 2026 09:13:19 -0500 Subject: [PATCH 108/254] fix: resolve undefined knowledge base name in file reference tooltip (#20333) --- backend/open_webui/models/knowledge.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/models/knowledge.py b/backend/open_webui/models/knowledge.py index 348f0de64b..724936d469 100644 --- a/backend/open_webui/models/knowledge.py +++ b/backend/open_webui/models/knowledge.py @@ -279,7 +279,7 @@ class KnowledgeTable: with get_db_context(db) as db: # Base query: join Knowledge → KnowledgeFile → File query = ( - db.query(File, User) + db.query(File, User, Knowledge) .join(KnowledgeFile, File.id == KnowledgeFile.file_id) .join(Knowledge, KnowledgeFile.knowledge_id == Knowledge.id) .outerjoin(User, User.id == KnowledgeFile.user_id) @@ -309,7 +309,7 @@ class KnowledgeTable: rows = query.all() items = [] - for file, user in rows: + for file, user, knowledge in rows: items.append( FileUserResponse( **FileModel.model_validate(file).model_dump(), @@ -320,6 +320,7 @@ class KnowledgeTable: if user else None ), + collection=KnowledgeModel.model_validate(knowledge).model_dump(), ) ) From a2f8e41fbcb294c203fc111934b300d64af84dfe Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:14:25 +0100 Subject: [PATCH 109/254] chore: dep bump (#20315) * dep bump * update --- backend/requirements-min.txt | 4 ++-- backend/requirements.txt | 12 ++++++------ pyproject.toml | 12 ++++++------ 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/requirements-min.txt b/backend/requirements-min.txt index 91a718052b..115d1bc92f 100644 --- a/backend/requirements-min.txt +++ b/backend/requirements-min.txt @@ -2,7 +2,7 @@ # WIP: use this as a reference to build a minimal docker image fastapi==0.128.0 -uvicorn[standard]==0.37.0 +uvicorn[standard]==0.40.0 pydantic==2.12.5 python-multipart==0.0.21 itsdangerous==2.2.0 @@ -43,7 +43,7 @@ openai langchain==1.2.0 langchain-community==0.4.1 -langchain-classic==1.0.0 +langchain-classic==1.0.1 langchain-text-splitters==1.1.0 fake-useragent==2.2.0 diff --git a/backend/requirements.txt b/backend/requirements.txt index 8c59569384..3369e68ede 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,5 +1,5 @@ fastapi==0.128.0 -uvicorn[standard]==0.37.0 +uvicorn[standard]==0.40.0 pydantic==2.12.5 python-multipart==0.0.21 itsdangerous==2.2.0 @@ -51,7 +51,7 @@ langchain-text-splitters==1.1.0 fake-useragent==2.2.0 chromadb==1.4.0 -weaviate-client==4.19.0 +weaviate-client==4.19.2 opensearch-py==3.1.0 transformers==4.57.3 @@ -64,10 +64,10 @@ ftfy==6.3.1 chardet==5.2.0 pypdf==6.5.0 fpdf2==2.8.5 -pymdown-extensions==10.19.1 +pymdown-extensions==10.20 docx2txt==0.9 python-pptx==1.0.2 -unstructured==0.18.21 +unstructured==0.18.24 msoffcrypto-tool==5.4.2 nltk==3.9.2 Markdown==3.10 @@ -115,9 +115,9 @@ psycopg2-binary==2.9.11 pgvector==0.4.2 PyMySQL==1.1.2 -boto3==1.42.17 +boto3==1.42.19 -pymilvus==2.6.5 +pymilvus==2.6.6 qdrant-client==1.16.2 playwright==1.57.0 # Caution: version must match docker-compose.playwright.yaml - Update the docker-compose.yaml if necessary elasticsearch==9.2.1 diff --git a/pyproject.toml b/pyproject.toml index a2f0d95f35..a397ebe702 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ authors = [ license = { file = "LICENSE" } dependencies = [ "fastapi==0.128.0", - "uvicorn[standard]==0.37.0", + "uvicorn[standard]==0.40.0", "pydantic==2.12.5", "python-multipart==0.0.21", "itsdangerous==2.2.0", @@ -60,7 +60,7 @@ dependencies = [ "chromadb==1.4.0", "opensearch-py==3.1.0", "PyMySQL==1.1.2", - "boto3==1.42.17", + "boto3==1.42.19", "transformers==4.57.3", "sentence-transformers==5.2.0", @@ -72,10 +72,10 @@ dependencies = [ "chardet==5.2.0", "pypdf==6.5.0", "fpdf2==2.8.5", - "pymdown-extensions==10.19.1", + "pymdown-extensions==10.20", "docx2txt==0.9", "python-pptx==1.0.2", - "unstructured==0.18.21", + "unstructured==0.18.24", "msoffcrypto-tool==5.4.2", "nltk==3.9.2", "Markdown==3.10", @@ -150,8 +150,8 @@ all = [ "qdrant-client==1.16.2", - "weaviate-client==4.19.0", - "pymilvus==2.6.5", + "weaviate-client==4.19.2", + "pymilvus==2.6.6", "pinecone==6.0.2", "oracledb==3.4.1", "colbert-ai==0.2.22", From 1c82506bfdbff7fc0840cabe9f200bd3f42df5ae Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Sat, 3 Jan 2026 15:31:59 +0100 Subject: [PATCH 110/254] fix: Missing field for entering the Mineru Cloud API key (#20328) * Update Documents.svelte * Update Documents.svelte --- 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 650ce8b055..99916b2036 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -666,6 +666,13 @@ />
+
+ +
+
From bd07ef87abbbed199a25db2cc0c25588d0f50b57 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 3 Jan 2026 18:43:12 +0400 Subject: [PATCH 111/254] refac --- backend/open_webui/utils/plugin.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/utils/plugin.py b/backend/open_webui/utils/plugin.py index 5407a7cec8..965b0a688f 100644 --- a/backend/open_webui/utils/plugin.py +++ b/backend/open_webui/utils/plugin.py @@ -7,7 +7,7 @@ import types import tempfile import logging -from open_webui.env import PIP_OPTIONS, PIP_PACKAGE_INDEX_OPTIONS +from open_webui.env import PIP_OPTIONS, PIP_PACKAGE_INDEX_OPTIONS, OFFLINE_MODE from open_webui.models.functions import Functions from open_webui.models.tools import Tools @@ -264,6 +264,10 @@ def get_function_module_from_cache(request, function_id, load_from_db=True): def install_frontmatter_requirements(requirements: str): + if OFFLINE_MODE: + log.info("Offline mode enabled, skipping installation of requirements.") + return + if requirements: try: req_list = [req.strip() for req in requirements.split(",")] From e55bf2c2ac391caed871d41f0484820091081908 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 3 Jan 2026 18:47:12 +0400 Subject: [PATCH 112/254] refac --- backend/open_webui/env.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 24b7656015..f5253d287b 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -428,12 +428,14 @@ PASSWORD_VALIDATION_REGEX_PATTERN = os.environ.get( "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$", ) + try: + PASSWORD_VALIDATION_REGEX_PATTERN = rf"{PASSWORD_VALIDATION_REGEX_PATTERN}" PASSWORD_VALIDATION_REGEX_PATTERN = re.compile(PASSWORD_VALIDATION_REGEX_PATTERN) except Exception as e: log.error(f"Invalid PASSWORD_VALIDATION_REGEX_PATTERN: {e}") PASSWORD_VALIDATION_REGEX_PATTERN = re.compile( - "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$" + r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$" ) From c32435958073cf002d87e78544baa88bc4e15d7f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 3 Jan 2026 19:47:29 +0400 Subject: [PATCH 113/254] feat: chunk min size target for md header splitter Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com> --- backend/open_webui/config.py | 7 ++ backend/open_webui/main.py | 3 + backend/open_webui/routers/retrieval.py | 90 ++++++++++++++++++- .../admin/Settings/Documents.svelte | 41 +++++++-- 4 files changed, 134 insertions(+), 7 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index dac65f0ccb..a18b0612f3 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -2886,6 +2886,13 @@ TIKTOKEN_ENCODING_NAME = PersistentConfig( CHUNK_SIZE = PersistentConfig( "CHUNK_SIZE", "rag.chunk_size", int(os.environ.get("CHUNK_SIZE", "1000")) ) + +CHUNK_MIN_SIZE_TARGET = PersistentConfig( + "CHUNK_MIN_SIZE_TARGET", + "rag.chunk_min_size_target", + int(os.environ.get("CHUNK_MIN_SIZE_TARGET", "0")), +) + CHUNK_OVERLAP = PersistentConfig( "CHUNK_OVERLAP", "rag.chunk_overlap", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 320e5c5cf3..37a6589fe6 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -253,6 +253,7 @@ from open_webui.config import ( RAG_OLLAMA_BASE_URL, RAG_OLLAMA_API_KEY, CHUNK_OVERLAP, + CHUNK_MIN_SIZE_TARGET, CHUNK_SIZE, CONTENT_EXTRACTION_ENGINE, DATALAB_MARKER_API_KEY, @@ -900,8 +901,10 @@ app.state.config.ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER = ( app.state.config.TIKTOKEN_ENCODING_NAME = TIKTOKEN_ENCODING_NAME app.state.config.CHUNK_SIZE = CHUNK_SIZE +app.state.config.CHUNK_MIN_SIZE_TARGET = CHUNK_MIN_SIZE_TARGET app.state.config.CHUNK_OVERLAP = CHUNK_OVERLAP + app.state.config.RAG_EMBEDDING_ENGINE = RAG_EMBEDDING_ENGINE app.state.config.RAG_EMBEDDING_MODEL = RAG_EMBEDDING_MODEL app.state.config.RAG_EMBEDDING_BATCH_SIZE = RAG_EMBEDDING_BATCH_SIZE diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 6f6baedc91..b6743992fa 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -505,6 +505,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): "TEXT_SPLITTER": request.app.state.config.TEXT_SPLITTER, "ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER": request.app.state.config.ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER, "CHUNK_SIZE": request.app.state.config.CHUNK_SIZE, + "CHUNK_MIN_SIZE_TARGET": request.app.state.config.CHUNK_MIN_SIZE_TARGET, "CHUNK_OVERLAP": request.app.state.config.CHUNK_OVERLAP, # File upload settings "FILE_MAX_SIZE": request.app.state.config.FILE_MAX_SIZE, @@ -699,6 +700,7 @@ class ConfigForm(BaseModel): TEXT_SPLITTER: Optional[str] = None ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER: Optional[bool] = None CHUNK_SIZE: Optional[int] = None + CHUNK_MIN_SIZE_TARGET: Optional[int] = None CHUNK_OVERLAP: Optional[int] = None # File upload settings @@ -1006,6 +1008,11 @@ async def update_rag_config( if form_data.CHUNK_SIZE is not None else request.app.state.config.CHUNK_SIZE ) + request.app.state.config.CHUNK_MIN_SIZE_TARGET = ( + form_data.CHUNK_MIN_SIZE_TARGET + if form_data.CHUNK_MIN_SIZE_TARGET is not None + else request.app.state.config.CHUNK_MIN_SIZE_TARGET + ) request.app.state.config.CHUNK_OVERLAP = ( form_data.CHUNK_OVERLAP if form_data.CHUNK_OVERLAP is not None @@ -1205,6 +1212,7 @@ async def update_rag_config( # Chunking settings "TEXT_SPLITTER": request.app.state.config.TEXT_SPLITTER, "CHUNK_SIZE": request.app.state.config.CHUNK_SIZE, + "CHUNK_MIN_SIZE_TARGET": request.app.state.config.CHUNK_MIN_SIZE_TARGET, "ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER": request.app.state.config.ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER, "CHUNK_OVERLAP": request.app.state.config.CHUNK_OVERLAP, # File upload settings @@ -1286,6 +1294,85 @@ async def update_rag_config( #################################### +def can_merge_chunks(a: Document, b: Document) -> bool: + if a.metadata.get("source") != b.metadata.get("source"): + return False + + a_file_id = a.metadata.get("file_id") + b_file_id = b.metadata.get("file_id") + + if a_file_id is not None and b_file_id is not None: + return a_file_id == b_file_id + + return True + + +def merge_docs_to_target_size( + request: Request, + chunks: list[Document], +) -> list[Document]: + """ + Best-effort normalization of chunk sizes. + + Attempts to grow small chunks up to a desired minimum size, + without exceeding the maximum size or crossing source/file + boundaries. + """ + min_chunk_size_target = request.app.state.config.CHUNK_MIN_SIZE_TARGET + max_chunk_size = request.app.state.config.CHUNK_SIZE + + if min_chunk_size_target <= 0: + return chunks + + measure_chunk_size = len + if request.app.state.config.TEXT_SPLITTER == "token": + encoding = tiktoken.get_encoding( + str(request.app.state.config.TIKTOKEN_ENCODING_NAME) + ) + measure_chunk_size = lambda text: len(encoding.encode(text)) + + processed_chunks: list[Document] = [] + + current_chunk: Document | None = None + current_content: str = "" + + for next_chunk in chunks: + if current_chunk is None: + current_chunk = next_chunk + current_content = next_chunk.page_content + continue # First chunk initialization + + proposed_content = f"{current_content}\n\n{next_chunk.page_content}" + + can_absorb = ( + can_merge_chunks(current_chunk, next_chunk) + and measure_chunk_size(current_content) < min_chunk_size_target + and measure_chunk_size(proposed_content) <= max_chunk_size + ) + + if can_absorb: + current_content = proposed_content + else: + processed_chunks.append( + Document( + page_content=current_content, + metadata={**current_chunk.metadata}, + ) + ) + current_chunk = next_chunk + current_content = next_chunk.page_content + + if current_chunk is not None: + processed_chunks.append( + Document( + page_content=current_content, + metadata={**current_chunk.metadata}, + ) + ) + + return processed_chunks + + def save_docs_to_vector_db( request: Request, docs, @@ -1332,7 +1419,6 @@ def save_docs_to_vector_db( if split: if request.app.state.config.ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER: log.info("Using markdown header text splitter") - # Define headers to split on - covering most common markdown header levels markdown_splitter = MarkdownHeaderTextSplitter( headers_to_split_on=[ @@ -1361,6 +1447,8 @@ def save_docs_to_vector_db( ) docs = split_docs + if request.app.state.config.CHUNK_MIN_SIZE_TARGET > 0: + docs = merge_docs_to_target_size(request, docs) if request.app.state.config.TEXT_SPLITTER in ["", "character"]: text_splitter = RecursiveCharacterTextSplitter( diff --git a/src/lib/components/admin/Settings/Documents.svelte b/src/lib/components/admin/Settings/Documents.svelte index 99916b2036..732d824692 100644 --- a/src/lib/components/admin/Settings/Documents.svelte +++ b/src/lib/components/admin/Settings/Documents.svelte @@ -666,12 +666,12 @@ />
-
- -
+
+ +
@@ -798,6 +798,35 @@
+ + {#if RAGConfig.ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER} +
+
+
+
+ + {$i18n.t('Chunk Min Size Target')} + +
+
+ +
+
+
+
+ {/if} {/if}
From dc2c2f229536ea0819de0d5d952314edda4bc712 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 3 Jan 2026 19:48:37 +0400 Subject: [PATCH 114/254] refac --- backend/open_webui/routers/retrieval.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index b6743992fa..cb018471ed 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -1344,13 +1344,13 @@ def merge_docs_to_target_size( proposed_content = f"{current_content}\n\n{next_chunk.page_content}" - can_absorb = ( + can_merge = ( can_merge_chunks(current_chunk, next_chunk) and measure_chunk_size(current_content) < min_chunk_size_target and measure_chunk_size(proposed_content) <= max_chunk_size ) - if can_absorb: + if can_merge: current_content = proposed_content else: processed_chunks.append( From e754940c031f9689fb4f6edb3625aa06aeb53377 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 03:05:10 +0400 Subject: [PATCH 115/254] refac --- src/lib/components/chat/Chat.svelte | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 2b50beb4d3..22276ca107 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -889,15 +889,8 @@ const initNewChat = async () => { console.log('initNewChat'); - if ($user?.role !== 'admin') { - if ($user?.permissions?.chat?.temporary_enforced) { - await temporaryChatEnabled.set(true); - } - - if (!$user?.permissions?.chat?.temporary) { - await temporaryChatEnabled.set(false); - return; - } + if ($user?.role !== 'admin' && $user?.permissions?.chat?.temporary_enforced) { + await temporaryChatEnabled.set(true); } if ($settings?.temporaryChatByDefault ?? false) { @@ -909,6 +902,10 @@ } } + if ($user?.role !== 'admin' && !$user?.permissions?.chat?.temporary) { + await temporaryChatEnabled.set(false); + } + const availableModels = $models .filter((m) => !(m?.info?.meta?.hidden ?? false)) .map((m) => m.id); @@ -1738,7 +1735,11 @@ ) ); - if (hasImages && !(model.info?.meta?.capabilities?.vision ?? true) && !imageGenerationEnabled) { + if ( + hasImages && + !(model.info?.meta?.capabilities?.vision ?? true) && + !imageGenerationEnabled + ) { toast.error( $i18n.t('Model {{modelName}} is not vision capable', { modelName: model.name ?? model.id From 614cb5642090b336899e3d2d8182d3893decb2e1 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 5 Jan 2026 00:05:56 +0100 Subject: [PATCH 116/254] feat: Add configurable DDGS backend selection with UI support (#20366) * init * Update WebSearch.svelte * reorder --- backend/open_webui/config.py | 6 ++++ backend/open_webui/main.py | 2 ++ .../open_webui/retrieval/web/duckduckgo.py | 4 ++- backend/open_webui/routers/retrieval.py | 4 +++ .../admin/Settings/WebSearch.svelte | 30 +++++++++++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index a18b0612f3..b56ad0552f 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -3193,6 +3193,12 @@ SERPLY_API_KEY = PersistentConfig( os.getenv("SERPLY_API_KEY", ""), ) +DDGS_BACKEND = PersistentConfig( + "DDGS_BACKEND", + "rag.web.search.ddgs_backend", + os.getenv("DDGS_BACKEND", "auto"), +) + JINA_API_KEY = PersistentConfig( "JINA_API_KEY", "rag.web.search.jina_api_key", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 37a6589fe6..6a1d79e721 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -312,6 +312,7 @@ from open_webui.config import ( YACY_PASSWORD, SERPER_API_KEY, SERPLY_API_KEY, + DDGS_BACKEND, SERPSTACK_API_KEY, SERPSTACK_HTTPS, TAVILY_API_KEY, @@ -969,6 +970,7 @@ app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS app.state.config.SERPER_API_KEY = SERPER_API_KEY app.state.config.SERPLY_API_KEY = SERPLY_API_KEY +app.state.config.DDGS_BACKEND = DDGS_BACKEND app.state.config.TAVILY_API_KEY = TAVILY_API_KEY app.state.config.SEARCHAPI_API_KEY = SEARCHAPI_API_KEY app.state.config.SEARCHAPI_ENGINE = SEARCHAPI_ENGINE diff --git a/backend/open_webui/retrieval/web/duckduckgo.py b/backend/open_webui/retrieval/web/duckduckgo.py index 0303b4e303..7528418cdb 100644 --- a/backend/open_webui/retrieval/web/duckduckgo.py +++ b/backend/open_webui/retrieval/web/duckduckgo.py @@ -13,12 +13,14 @@ def search_duckduckgo( count: int, filter_list: Optional[list[str]] = None, concurrent_requests: Optional[int] = None, + backend: Optional[str] = "auto", ) -> list[SearchResult]: """ Search using DuckDuckGo's Search API and return the results as a list of SearchResult objects. Args: query (str): The query to search for count (int): The number of results to return + backend (str): The search backend to use (auto, duckduckgo, google, brave, etc.) Returns: list[SearchResult]: A list of search results @@ -32,7 +34,7 @@ def search_duckduckgo( # Use the ddgs.text() method to perform the search try: search_results = ddgs.text( - query, safesearch="moderate", max_results=count, backend="lite" + query, safesearch="moderate", max_results=count, backend=backend ) except RatelimitException as e: log.error(f"RatelimitException: {e}") diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index cb018471ed..2d17e7553f 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -543,6 +543,7 @@ async def get_rag_config(request: Request, user=Depends(get_admin_user)): "SERPSTACK_HTTPS": request.app.state.config.SERPSTACK_HTTPS, "SERPER_API_KEY": request.app.state.config.SERPER_API_KEY, "SERPLY_API_KEY": request.app.state.config.SERPLY_API_KEY, + "DDGS_BACKEND": request.app.state.config.DDGS_BACKEND, "TAVILY_API_KEY": request.app.state.config.TAVILY_API_KEY, "SEARCHAPI_API_KEY": request.app.state.config.SEARCHAPI_API_KEY, "SEARCHAPI_ENGINE": request.app.state.config.SEARCHAPI_ENGINE, @@ -605,6 +606,7 @@ class WebConfig(BaseModel): SERPSTACK_HTTPS: Optional[bool] = None SERPER_API_KEY: Optional[str] = None SERPLY_API_KEY: Optional[str] = None + DDGS_BACKEND: Optional[str] = None TAVILY_API_KEY: Optional[str] = None SEARCHAPI_API_KEY: Optional[str] = None SEARCHAPI_ENGINE: Optional[str] = None @@ -1097,6 +1099,7 @@ async def update_rag_config( request.app.state.config.SERPSTACK_HTTPS = form_data.web.SERPSTACK_HTTPS request.app.state.config.SERPER_API_KEY = form_data.web.SERPER_API_KEY request.app.state.config.SERPLY_API_KEY = form_data.web.SERPLY_API_KEY + request.app.state.config.DDGS_BACKEND = form_data.web.DDGS_BACKEND request.app.state.config.TAVILY_API_KEY = form_data.web.TAVILY_API_KEY request.app.state.config.SEARCHAPI_API_KEY = form_data.web.SEARCHAPI_API_KEY request.app.state.config.SEARCHAPI_ENGINE = form_data.web.SEARCHAPI_ENGINE @@ -2071,6 +2074,7 @@ def search_web( request.app.state.config.WEB_SEARCH_RESULT_COUNT, request.app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST, concurrent_requests=request.app.state.config.WEB_SEARCH_CONCURRENT_REQUESTS, + backend=request.app.state.config.DDGS_BACKEND, ) elif engine == "tavily": if request.app.state.config.TAVILY_API_KEY: diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index 4cbd581154..68a343e5f6 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -697,7 +697,37 @@
{/if} + + {#if webConfig.WEB_SEARCH_ENGINE === 'duckduckgo'} +
+
+
+ {$i18n.t('DDGS Backend')} +
+ +
+
+ +
+
+
+
{/if} + {/if} {#if webConfig.ENABLE_WEB_SEARCH}
From 2bb13d5dbc6e233856e8aa26143222ceda8f6c11 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 03:46:40 +0400 Subject: [PATCH 117/254] refac: get_db_context --- backend/open_webui/internal/db.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index e4e4e0d2f8..ee83586596 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -164,7 +164,7 @@ get_db = contextmanager(get_session) @contextmanager def get_db_context(db: Optional[Session] = None): - if db: + if isinstance(db, Session): yield db else: with get_db() as session: From b55a46ae99c32068ed306a5ecdaafa9f75504cd7 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 03:46:46 +0400 Subject: [PATCH 118/254] refac --- backend/open_webui/utils/models.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/utils/models.py b/backend/open_webui/utils/models.py index 6ef3c16091..b3a332adee 100644 --- a/backend/open_webui/utils/models.py +++ b/backend/open_webui/utils/models.py @@ -337,7 +337,7 @@ async def get_all_models(request, refresh: bool = False, user: UserModel = None) return models -def check_model_access(user, model): +def check_model_access(user, model, db=None): if model.get("arena"): if not has_access( user.id, @@ -345,16 +345,17 @@ def check_model_access(user, model): access_control=model.get("info", {}) .get("meta", {}) .get("access_control", {}), + db=db, ): raise Exception("Model not found") else: - model_info = Models.get_model_by_id(model.get("id")) + model_info = Models.get_model_by_id(model.get("id"), db=db) if not model_info: raise Exception("Model not found") elif not ( user.id == model_info.user_id or has_access( - user.id, type="read", access_control=model_info.access_control + user.id, type="read", access_control=model_info.access_control, db=db ) ): raise Exception("Model not found") @@ -373,7 +374,9 @@ def get_filtered_models(models, user, db=None): } filtered_models = [] - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user.id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user.id, db=db) + } for model in models: if model.get("arena"): if has_access( From 1f059fe7307eb7cda6c9d3af5423ed6c67da3aa6 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 5 Jan 2026 01:36:13 +0100 Subject: [PATCH 119/254] feat: Prompts Atomic PR of #20243 (#20368) * feat: Add read-only access support for Prompts - Backend: Add write_access field to PromptAccessResponse - Backend: Update /prompts/list to return prompts with write_access - Frontend: Display Read Only badge in Prompts list - Frontend: Disable inputs and save button when no write access * feat: Add read-only visual indicators for Prompts workspace * fix: Return write_access from getPromptByCommand endpoint - Backend returns write_access directly in response - Frontend extracts write_access from getPromptByCommand response - Remove inefficient getPromptList call in edit page * fix: Align Read Only badge to right in Prompts.svelte - Title and command stay on left - Badge pushed to right by justify-between * fix: Use PromptAccessResponse in get_prompt_by_command endpoint fix: Use PromptAccessResponse in get_prompt_by_command endpoint - Return PromptAccessResponse Pydantic model instead of raw dict - Properly type the response with response_model --- backend/open_webui/models/prompts.py | 4 + backend/open_webui/routers/prompts.py | 33 ++++++--- src/lib/components/workspace/Prompts.svelte | 14 +++- .../workspace/Prompts/PromptEditor.svelte | 74 +++++++++++-------- .../(app)/workspace/prompts/edit/+page.svelte | 5 +- 5 files changed, 85 insertions(+), 45 deletions(-) diff --git a/backend/open_webui/models/prompts.py b/backend/open_webui/models/prompts.py index eefb74de53..89c49ccc80 100644 --- a/backend/open_webui/models/prompts.py +++ b/backend/open_webui/models/prompts.py @@ -64,6 +64,10 @@ class PromptUserResponse(PromptModel): user: Optional[UserResponse] = None +class PromptAccessResponse(PromptUserResponse): + write_access: Optional[bool] = False + + class PromptForm(BaseModel): command: str title: str diff --git a/backend/open_webui/routers/prompts.py b/backend/open_webui/routers/prompts.py index 70f9f71e5b..645cfe83ab 100644 --- a/backend/open_webui/routers/prompts.py +++ b/backend/open_webui/routers/prompts.py @@ -4,6 +4,7 @@ from fastapi import APIRouter, Depends, HTTPException, status, Request from open_webui.models.prompts import ( PromptForm, PromptUserResponse, + PromptAccessResponse, PromptModel, Prompts, ) @@ -31,14 +32,24 @@ async def get_prompts(user=Depends(get_verified_user), db: Session = Depends(get return prompts -@router.get("/list", response_model=list[PromptUserResponse]) +@router.get("/list", response_model=list[PromptAccessResponse]) async def get_prompt_list(user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: prompts = Prompts.get_prompts(db=db) else: - prompts = Prompts.get_prompts_by_user_id(user.id, "write", db=db) + prompts = Prompts.get_prompts_by_user_id(user.id, "read", db=db) - return prompts + return [ + PromptAccessResponse( + **prompt.model_dump(), + write_access=( + (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) + or user.id == prompt.user_id + or has_access(user.id, "write", prompt.access_control, db=db) + ), + ) + for prompt in prompts + ] ############################ @@ -87,7 +98,7 @@ async def create_new_prompt( ############################ -@router.get("/command/{command}", response_model=Optional[PromptModel]) +@router.get("/command/{command}", response_model=Optional[PromptAccessResponse]) async def get_prompt_by_command(command: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): prompt = Prompts.get_prompt_by_command(f"/{command}", db=db) @@ -97,15 +108,17 @@ async def get_prompt_by_command(command: str, user=Depends(get_verified_user), d or prompt.user_id == user.id or has_access(user.id, "read", prompt.access_control, db=db) ): - return prompt - else: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + return PromptAccessResponse( + **prompt.model_dump(), + write_access=( + (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) + or user.id == prompt.user_id + or has_access(user.id, "write", prompt.access_control, db=db) + ), ) else: raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, + status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.NOT_FOUND, ) diff --git a/src/lib/components/workspace/Prompts.svelte b/src/lib/components/workspace/Prompts.svelte index 446c29f7ee..c95dd1dbae 100644 --- a/src/lib/components/workspace/Prompts.svelte +++ b/src/lib/components/workspace/Prompts.svelte @@ -26,6 +26,7 @@ import XMark from '../icons/XMark.svelte'; import GarbageBin from '../icons/GarbageBin.svelte'; import ViewSelector from './common/ViewSelector.svelte'; + import Badge from '$lib/components/common/Badge.svelte'; let shiftKey = false; @@ -327,11 +328,16 @@ href={`/workspace/prompts/edit?command=${encodeURIComponent(prompt.command)}`} >
-
-
{prompt.title}
-
- {prompt.command} +
+
+
{prompt.title}
+
+ {prompt.command} +
+ {#if !prompt.write_access} + + {/if}
diff --git a/src/lib/components/workspace/Prompts/PromptEditor.svelte b/src/lib/components/workspace/Prompts/PromptEditor.svelte index 806beacaac..379dc6c765 100644 --- a/src/lib/components/workspace/Prompts/PromptEditor.svelte +++ b/src/lib/components/workspace/Prompts/PromptEditor.svelte @@ -15,6 +15,7 @@ export let edit = false; export let prompt = null; export let clone = false; + export let write_access = true; const i18n = getContext('i18n'); @@ -40,6 +41,10 @@ } const submitHandler = async () => { + if (!write_access) { + toast.error($i18n.t('You do not have permission to edit this prompt.')); + return; + } loading = true; if (validateCommandString(command)) { @@ -111,23 +116,30 @@ placeholder={$i18n.t('Title')} bind:value={title} required + disabled={!write_access} /> -
- -
+
+ {$i18n.t('Access')} +
+ +
+ {:else} +
+ {$i18n.t('Read Only')} +
+ {/if}
@@ -138,7 +150,7 @@ bind:value={command} on:input={handleCommandInput} required - disabled={edit} + disabled={edit || !write_access} />
@@ -158,6 +170,7 @@ bind:value={content} rows={6} required + disabled={!write_access} />
@@ -181,21 +194,22 @@
- + + +
diff --git a/src/routes/(app)/workspace/prompts/edit/+page.svelte b/src/routes/(app)/workspace/prompts/edit/+page.svelte index 9a317cc7c5..7148b4a30c 100644 --- a/src/routes/(app)/workspace/prompts/edit/+page.svelte +++ b/src/routes/(app)/workspace/prompts/edit/+page.svelte @@ -12,6 +12,8 @@ import PromptEditor from '$lib/components/workspace/Prompts/PromptEditor.svelte'; let prompt = null; + let write_access = true; + const onSubmit = async (_prompt) => { console.log(_prompt); const prompt = await updatePromptByCommand(localStorage.token, _prompt).catch((error) => { @@ -38,6 +40,7 @@ }); if (_prompt) { + write_access = _prompt.write_access ?? true; prompt = { title: _prompt.title, command: _prompt.command, @@ -54,5 +57,5 @@ {#if prompt} - + {/if} From 5c1d52231a3997a17381c48639bd7e339262cf7c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 04:45:17 +0400 Subject: [PATCH 120/254] feat: native function calling for built-in tools --- backend/open_webui/tools/__init__.py | 6 + backend/open_webui/tools/builtin.py | 241 +++++++++++++++++++++++++ backend/open_webui/utils/middleware.py | 42 ++++- backend/open_webui/utils/tools.py | 54 ++++++ 4 files changed, 333 insertions(+), 10 deletions(-) create mode 100644 backend/open_webui/tools/__init__.py create mode 100644 backend/open_webui/tools/builtin.py diff --git a/backend/open_webui/tools/__init__.py b/backend/open_webui/tools/__init__.py new file mode 100644 index 0000000000..112324b569 --- /dev/null +++ b/backend/open_webui/tools/__init__.py @@ -0,0 +1,6 @@ +""" +Open WebUI Tools Package. + +This package contains built-in tools that are automatically available +when native function calling is enabled. +""" diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py new file mode 100644 index 0000000000..922f9a10e2 --- /dev/null +++ b/backend/open_webui/tools/builtin.py @@ -0,0 +1,241 @@ +""" +Built-in tools for Open WebUI. + +These tools are automatically available when native function calling is enabled. +""" + +import json +import logging +import time +from typing import Optional + +from fastapi import Request + +from open_webui.models.users import UserModel +from open_webui.routers.retrieval import search_web +from open_webui.retrieval.utils import get_content_from_url +from open_webui.routers.images import image_generations, image_edits, CreateImageForm, EditImageForm +from open_webui.routers.memories import query_memory, add_memory, QueryMemoryForm, AddMemoryForm + +log = logging.getLogger(__name__) + + +async def web_search( + query: str, + count: int = 5, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search the web for information on a given topic. + + :param query: The search query to look up + :param count: Number of results to return (default: 5) + :return: JSON with search results containing title, link, and snippet for each result + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + try: + engine = __request__.app.state.config.WEB_SEARCH_ENGINE + user = UserModel(**__user__) if __user__ else None + + results = search_web(__request__, engine, query, user) + + # Limit results + results = results[:count] if results else [] + + return json.dumps( + [{"title": r.title, "link": r.link, "snippet": r.snippet} for r in results], + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"web_search error: {e}") + return json.dumps({"error": str(e)}) + + +async def fetch_url( + url: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Fetch and extract the main text content from a web page URL. + + :param url: The URL to fetch content from + :return: The extracted text content from the page + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + try: + content, _ = get_content_from_url(__request__, url) + + # Truncate if too long (avoid overwhelming context) + max_length = 50000 + if len(content) > max_length: + content = content[:max_length] + "\n\n[Content truncated...]" + + return content + except Exception as e: + log.exception(f"fetch_url error: {e}") + return json.dumps({"error": str(e)}) + + +async def generate_image( + prompt: str, + __request__: Request = None, + __user__: dict = None, + __event_emitter__: callable = None, +) -> str: + """ + Generate an image based on a text prompt. + + :param prompt: A detailed description of the image to generate + :return: Confirmation that the image was generated, or an error message + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + try: + user = UserModel(**__user__) if __user__ else None + + images = await image_generations( + request=__request__, + form_data=CreateImageForm(prompt=prompt), + user=user, + ) + + # Emit the images to the UI if event emitter is available + if __event_emitter__ and images: + await __event_emitter__( + { + "type": "files", + "data": { + "files": [ + {"type": "image", "url": img["url"]} + for img in images + ] + }, + } + ) + + return json.dumps({"status": "success", "images": images}, ensure_ascii=False) + except Exception as e: + log.exception(f"generate_image error: {e}") + return json.dumps({"error": str(e)}) + + +async def edit_image( + prompt: str, + image_url: str, + __request__: Request = None, + __user__: dict = None, + __event_emitter__: callable = None, +) -> str: + """ + Edit an existing image based on a text prompt. + + :param prompt: A description of the changes to make to the image + :param image_url: The URL of the image to edit + :return: Confirmation that the image was edited, or an error message + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + try: + user = UserModel(**__user__) if __user__ else None + + images = await image_edits( + request=__request__, + form_data=EditImageForm(prompt=prompt, image=image_url), + user=user, + ) + + # Emit the images to the UI if event emitter is available + if __event_emitter__ and images: + await __event_emitter__( + { + "type": "files", + "data": { + "files": [ + {"type": "image", "url": img["url"]} + for img in images + ] + }, + } + ) + + return json.dumps({"status": "success", "images": images}, ensure_ascii=False) + except Exception as e: + log.exception(f"edit_image error: {e}") + return json.dumps({"error": str(e)}) + + +async def memory_query( + query: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search the user's stored memories for relevant information. + + :param query: The search query to find relevant memories + :return: JSON with matching memories and their dates + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + try: + user = UserModel(**__user__) if __user__ else None + + results = await query_memory( + __request__, + QueryMemoryForm(content=query, k=5), + user, + ) + + if results and hasattr(results, "documents") and results.documents: + memories = [] + for doc_idx, doc in enumerate(results.documents[0]): + created_at = "Unknown" + if results.metadatas and results.metadatas[0][doc_idx].get("created_at"): + created_at = time.strftime( + "%Y-%m-%d", time.localtime(results.metadatas[0][doc_idx]["created_at"]) + ) + memories.append({"date": created_at, "content": doc}) + return json.dumps(memories, ensure_ascii=False) + else: + return json.dumps([]) + except Exception as e: + log.exception(f"memory_query error: {e}") + return json.dumps({"error": str(e)}) + + +async def memory_add( + content: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Store a new memory for the user. + + :param content: The memory content to store + :return: Confirmation that the memory was stored + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + try: + user = UserModel(**__user__) if __user__ else None + + memory = await add_memory( + __request__, + AddMemoryForm(content=content), + user, + ) + + return json.dumps({"status": "success", "id": memory.id}, ensure_ascii=False) + except Exception as e: + log.exception(f"memory_add 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 510529ad3c..15414aa002 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -44,6 +44,7 @@ from open_webui.routers.retrieval import ( process_web_search, SearchForm, ) +from open_webui.utils.tools import get_builtin_tools from open_webui.routers.images import ( image_generations, CreateImageForm, @@ -1305,7 +1306,8 @@ async def process_chat_payload(request, form_data, user, metadata, model): except Exception as e: raise Exception(f"{e}") - features = form_data.pop("features", None) + features = form_data.pop("features", None) or {} + extra_params["__features__"] = features if features: if "voice" in features and features["voice"]: if request.app.state.config.VOICE_MODE_PROMPT_TEMPLATE != None: @@ -1320,19 +1322,25 @@ async def process_chat_payload(request, form_data, user, metadata, model): ) if "memory" in features and features["memory"]: - form_data = await chat_memory_handler( - request, form_data, extra_params, user - ) + # Skip forced memory injection when native FC is enabled - model can use memory tools + if metadata.get("params", {}).get("function_calling") != "native": + form_data = await chat_memory_handler( + request, form_data, extra_params, user + ) if "web_search" in features and features["web_search"]: - form_data = await chat_web_search_handler( - request, form_data, extra_params, user - ) + # Skip forced RAG web search when native FC is enabled - model can use web_search tool + if metadata.get("params", {}).get("function_calling") != "native": + form_data = await chat_web_search_handler( + request, form_data, extra_params, user + ) if "image_generation" in features and features["image_generation"]: - form_data = await chat_image_generation_handler( - request, form_data, extra_params, user - ) + # Skip forced image generation when native FC is enabled - model can use generate_image tool + if metadata.get("params", {}).get("function_calling") != "native": + form_data = await chat_image_generation_handler( + request, form_data, extra_params, user + ) if "code_interpreter" in features and features["code_interpreter"]: form_data["messages"] = add_or_update_user_message( @@ -1543,6 +1551,20 @@ async def process_chat_payload(request, form_data, user, metadata, model): if mcp_clients: metadata["mcp_clients"] = mcp_clients + # Always inject builtin tools for native function calling based on enabled features + if metadata.get("params", {}).get("function_calling") == "native": + builtin_tools = get_builtin_tools( + request, + { + **extra_params, + "__event_emitter__": event_emitter, + }, + features, + ) + for name, tool_dict in builtin_tools.items(): + if name not in tools_dict: + tools_dict[name] = tool_dict + if tools_dict: if metadata.get("params", {}).get("function_calling") == "native": # If the function calling is native, then call the tools function calling handler diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index f517e89999..4379d9f4d4 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -43,6 +43,10 @@ from open_webui.env import ( AIOHTTP_CLIENT_TIMEOUT_TOOL_SERVER_DATA, AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL, ) +from open_webui.tools.builtin import ( + web_search, fetch_url, generate_image, edit_image, + memory_query, memory_add +) import copy @@ -320,6 +324,56 @@ async def get_tools( return tools_dict +def get_builtin_tools(request: Request, extra_params: dict, features: dict = None) -> dict[str, dict]: + """ + Get built-in tools for native function calling. + Only returns tools when BOTH the global config is enabled AND the feature is enabled for this chat. + """ + tools_dict = {} + builtin_functions = [] + features = features or {} + + # Add web search tools if enabled globally AND for this chat + if (getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) + and features.get("web_search")): + builtin_functions.extend([web_search, fetch_url]) + + # Add image generation/edit tools if enabled globally AND for this chat + if (getattr(request.app.state.config, "ENABLE_IMAGE_GENERATION", False) + and features.get("image_generation")): + builtin_functions.append(generate_image) + if (getattr(request.app.state.config, "ENABLE_IMAGE_EDIT", False) + and features.get("image_generation")): + builtin_functions.append(edit_image) + + # Add memory tools if enabled for this chat + if features.get("memory"): + builtin_functions.extend([memory_query, memory_add]) + + for func in builtin_functions: + callable = get_async_tool_function_and_apply_extra_params( + func, + { + "__request__": request, + "__user__": extra_params.get("__user__", {}), + "__event_emitter__": extra_params.get("__event_emitter__"), + }, + ) + + # Generate spec from function + pydantic_model = convert_function_to_pydantic_model(func) + spec = convert_pydantic_model_to_openai_function_spec(pydantic_model) + + tools_dict[func.__name__] = { + "tool_id": f"builtin:{func.__name__}", + "callable": callable, + "spec": spec, + "type": "builtin", + } + + return tools_dict + + def parse_description(docstring: str | None) -> str: """ Parse a function's docstring to extract the description. From 6b5643c78666f511af86a9018b0de55caa7d906f Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 5 Jan 2026 01:45:48 +0100 Subject: [PATCH 121/254] feat: Add read-only access support for Knowledge Bases (#20371) - Backend: Add BYPASS_ADMIN_ACCESS_CONTROL check to write_access calculation - Frontend: Knowledge already has Read Only badge and disabled inputs --- backend/open_webui/routers/knowledge.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index aa85e59f20..5d2167c2cd 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -81,6 +81,7 @@ async def get_knowledge_bases( **knowledge_base.model_dump(), write_access=( user.id == knowledge_base.user_id + or (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) or has_access( user.id, "write", knowledge_base.access_control, db=db ) @@ -127,6 +128,7 @@ async def search_knowledge_bases( **knowledge_base.model_dump(), write_access=( user.id == knowledge_base.user_id + or (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) or has_access( user.id, "write", knowledge_base.access_control, db=db ) @@ -303,6 +305,7 @@ async def get_knowledge_by_id( **knowledge.model_dump(), write_access=( user.id == knowledge.user_id + or (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) or has_access(user.id, "write", knowledge.access_control, db=db) ), ) From ca514cd3eda2524b8da472ef17c0ccb216bac2e8 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 05:32:56 +0400 Subject: [PATCH 122/254] refac: group share to settings --- backend/open_webui/models/groups.py | 106 +++++++++++++----- backend/open_webui/routers/groups.py | 7 +- .../admin/Users/Groups/General.svelte | 26 +++-- 3 files changed, 102 insertions(+), 37 deletions(-) diff --git a/backend/open_webui/models/groups.py b/backend/open_webui/models/groups.py index 1ceb8f1ec0..053125a6d0 100644 --- a/backend/open_webui/models/groups.py +++ b/backend/open_webui/models/groups.py @@ -159,40 +159,70 @@ class GroupTable: if filter: if "query" in filter: query = query.filter(Group.name.ilike(f"%{filter['query']}%")) - if "member_id" in filter: - query = query.join( - GroupMember, GroupMember.group_id == Group.id - ).filter(GroupMember.user_id == filter["member_id"]) + # When share filter is present, member check is handled in the share logic if "share" in filter: share_value = filter["share"] - json_share = Group.data["config"]["share"].as_boolean() + member_id = filter.get("member_id") + json_share = Group.data["config"]["share"] + json_share_bool = json_share.as_boolean() + json_share_str = json_share.as_string() if share_value: - query = query.filter( - or_( - Group.data.is_(None), - json_share.is_(None), - json_share == True, - ) + # Groups open to anyone: data is null, share is null, or share is true + anyone_can_share = or_( + Group.data.is_(None), + json_share_bool.is_(None), + json_share_bool == True, ) + + if member_id: + # Also include member-only groups where user is a member + member_groups_subq = ( + db.query(GroupMember.group_id) + .filter(GroupMember.user_id == member_id) + .subquery() + ) + members_only_and_is_member = and_( + json_share_str == "members", + Group.id.in_(member_groups_subq), + ) + query = query.filter( + or_(anyone_can_share, members_only_and_is_member) + ) + else: + query = query.filter(anyone_can_share) else: query = query.filter( - and_(Group.data.isnot(None), json_share == False) + and_(Group.data.isnot(None), json_share_bool == False) ) + + else: + # Only apply member_id filter when share filter is NOT present + if "member_id" in filter: + query = query.join( + GroupMember, GroupMember.group_id == Group.id + ).filter(GroupMember.user_id == filter["member_id"]) + groups = query.order_by(Group.updated_at.desc()).all() return [ GroupResponse.model_validate( { **GroupModel.model_validate(group).model_dump(), - "member_count": self.get_group_member_count_by_id(group.id, db=db), + "member_count": self.get_group_member_count_by_id( + group.id, db=db + ), } ) for group in groups ] def search_groups( - self, filter: Optional[dict] = None, skip: int = 0, limit: int = 30, db: Optional[Session] = None + self, + filter: Optional[dict] = None, + skip: int = 0, + limit: int = 30, + db: Optional[Session] = None, ) -> GroupListResponse: with get_db_context(db) as db: query = db.query(Group) @@ -228,7 +258,9 @@ class GroupTable: "total": total, } - def get_groups_by_member_id(self, user_id: str, db: Optional[Session] = None) -> list[GroupModel]: + def get_groups_by_member_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[GroupModel]: with get_db_context(db) as db: return [ GroupModel.model_validate(group) @@ -239,7 +271,9 @@ class GroupTable: .all() ] - def get_group_by_id(self, id: str, db: Optional[Session] = None) -> Optional[GroupModel]: + def get_group_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[GroupModel]: try: with get_db_context(db) as db: group = db.query(Group).filter_by(id=id).first() @@ -247,7 +281,9 @@ class GroupTable: except Exception: return None - def get_group_user_ids_by_id(self, id: str, db: Optional[Session] = None) -> Optional[list[str]]: + def get_group_user_ids_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[list[str]]: with get_db_context(db) as db: members = ( db.query(GroupMember.user_id).filter(GroupMember.group_id == id).all() @@ -258,7 +294,9 @@ class GroupTable: return [m[0] for m in members] - def get_group_user_ids_by_ids(self, group_ids: list[str], db: Optional[Session] = None) -> dict[str, list[str]]: + def get_group_user_ids_by_ids( + self, group_ids: list[str], db: Optional[Session] = None + ) -> dict[str, list[str]]: with get_db_context(db) as db: members = ( db.query(GroupMember.group_id, GroupMember.user_id) @@ -275,7 +313,9 @@ class GroupTable: return group_user_ids - def set_group_user_ids_by_id(self, group_id: str, user_ids: list[str], db: Optional[Session] = None) -> None: + def set_group_user_ids_by_id( + self, group_id: str, user_ids: list[str], db: Optional[Session] = None + ) -> None: with get_db_context(db) as db: # Delete existing members db.query(GroupMember).filter(GroupMember.group_id == group_id).delete() @@ -296,7 +336,9 @@ class GroupTable: db.add_all(new_members) db.commit() - def get_group_member_count_by_id(self, id: str, db: Optional[Session] = None) -> int: + def get_group_member_count_by_id( + self, id: str, db: Optional[Session] = None + ) -> int: with get_db_context(db) as db: count = ( db.query(func.count(GroupMember.user_id)) @@ -306,7 +348,11 @@ class GroupTable: return count if count else 0 def update_group_by_id( - self, id: str, form_data: GroupUpdateForm, overwrite: bool = False, db: Optional[Session] = None + self, + id: str, + form_data: GroupUpdateForm, + overwrite: bool = False, + db: Optional[Session] = None, ) -> Optional[GroupModel]: try: with get_db_context(db) as db: @@ -341,7 +387,9 @@ class GroupTable: except Exception: return False - def remove_user_from_all_groups(self, user_id: str, db: Optional[Session] = None) -> bool: + def remove_user_from_all_groups( + self, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: try: # Find all groups the user belongs to @@ -401,7 +449,9 @@ class GroupTable: continue return new_groups - def sync_groups_by_group_names(self, user_id: str, group_names: list[str], db: Optional[Session] = None) -> bool: + def sync_groups_by_group_names( + self, user_id: str, group_names: list[str], db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: try: now = int(time.time()) @@ -462,7 +512,10 @@ class GroupTable: return False def add_users_to_group( - self, id: str, user_ids: Optional[list[str]] = None, db: Optional[Session] = None + self, + id: str, + user_ids: Optional[list[str]] = None, + db: Optional[Session] = None, ) -> Optional[GroupModel]: try: with get_db_context(db) as db: @@ -500,7 +553,10 @@ class GroupTable: return None def remove_users_from_group( - self, id: str, user_ids: Optional[list[str]] = None, db: Optional[Session] = None + self, + id: str, + user_ids: Optional[list[str]] = None, + db: Optional[Session] = None, ) -> Optional[GroupModel]: try: with get_db_context(db) as db: diff --git a/backend/open_webui/routers/groups.py b/backend/open_webui/routers/groups.py index f1c567fe81..cc0cb8f5a3 100755 --- a/backend/open_webui/routers/groups.py +++ b/backend/open_webui/routers/groups.py @@ -39,11 +39,12 @@ async def get_groups( ): filter = {} + + # Admins can share to all groups regardless of share setting if user.role != "admin": filter["member_id"] = user.id - - if share is not None: - filter["share"] = share + if share is not None: + filter["share"] = share groups = Groups.get_groups(filter=filter, db=db) diff --git a/src/lib/components/admin/Users/Groups/General.svelte b/src/lib/components/admin/Users/Groups/General.svelte index 745611ec1f..1922f00138 100644 --- a/src/lib/components/admin/Users/Groups/General.svelte +++ b/src/lib/components/admin/Users/Groups/General.svelte @@ -2,7 +2,6 @@ import { getContext } from 'svelte'; import Textarea from '$lib/components/common/Textarea.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte'; - import Switch from '$lib/components/common/Switch.svelte'; const i18n = getContext('i18n'); @@ -73,21 +72,30 @@
- {$i18n.t('Allow Group Sharing')} + {$i18n.t('Who can share to this group')}
- { - if (data?.config?.share) { - data.config.share = e.detail; + const value = e.target.value; + let shareValue; + if (value === 'false') { + shareValue = false; + } else if (value === 'true') { + shareValue = true; } else { - data.config = { ...(data?.config ?? {}), share: e.detail }; + shareValue = value; } + data.config = { ...(data?.config ?? {}), share: shareValue }; }} - /> + > + + + +
From 3f577c0c3fbfd9f09c02940e4ae474f987149277 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 17:34:29 +0400 Subject: [PATCH 123/254] refac: notes organization issue --- src/lib/components/notes/Notes.svelte | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/lib/components/notes/Notes.svelte b/src/lib/components/notes/Notes.svelte index 3d0ceb60b7..61247b32fd 100644 --- a/src/lib/components/notes/Notes.svelte +++ b/src/lib/components/notes/Notes.svelte @@ -215,22 +215,27 @@ const groupNotes = (res) => { if (!Array.isArray(res)) { - return {}; // or throw new Error("Notes response is not an array") + return []; // Return empty array for invalid input } - // Build the grouped object + // Build the grouped object while tracking order const grouped: Record = {}; + const orderedKeys: string[] = []; + for (const note of res) { const timeRange = getTimeRange(note.updated_at / 1000000000); if (!grouped[timeRange]) { grouped[timeRange] = []; + orderedKeys.push(timeRange); } grouped[timeRange].push({ ...note, timeRange }); } - return grouped; + + // Return as array of [timeRange, notes] to preserve insertion order + return orderedKeys.map(key => [key, grouped[key]] as [string, any[]]); }; let dragged = false; @@ -437,11 +442,11 @@ {#if items !== null && total !== null} {#if (items ?? []).length > 0} - {@const notes = groupNotes(items)} + {@const groupedNotes = groupNotes(items)}
- {#each Object.keys(notes) as timeRange, idx} + {#each groupedNotes as [timeRange, notesList], idx}
@@ -450,11 +455,11 @@ {#if displayOption === null}
- {#each notes[timeRange] as note, idx (note.id)} + {#each notesList as note, idx (note.id)}
@@ -536,11 +541,11 @@
{:else if displayOption === 'grid'}
- {#each notes[timeRange] as note, idx (note.id)} + {#each notesList as note, idx (note.id)}
From e27fb3e291a735c715a089a80e7a49d2c2209096 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 17:44:44 +0400 Subject: [PATCH 124/254] refac --- .../common/RichTextInput/Collaboration.ts | 14 +++++++++++--- src/lib/components/notes/NoteEditor.svelte | 7 +++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/lib/components/common/RichTextInput/Collaboration.ts b/src/lib/components/common/RichTextInput/Collaboration.ts index 087545d527..dc2de6b70c 100644 --- a/src/lib/components/common/RichTextInput/Collaboration.ts +++ b/src/lib/components/common/RichTextInput/Collaboration.ts @@ -131,9 +131,17 @@ export class SocketIOCollaborationProvider { const isEmptyEditor = !this.editor?.getText().trim(); if (isEmptyEditor && this.editor) { if (this.initialContent && (data?.sessions ?? ['']).length === 1) { - const editorYdoc = prosemirrorJSONToYDoc(this.editor.schema, this.initialContent); - if (editorYdoc) { - Y.applyUpdate(this.doc, Y.encodeStateAsUpdate(editorYdoc)); + // Check if initialContent is HTML (string) or JSON (object) + if (typeof this.initialContent === 'string') { + // HTML content - let the editor parse it, then sync to Yjs + this.editor.commands.setContent(this.initialContent); + // The Yjs plugin will automatically sync the content + } else { + // JSON content - use the existing approach + const editorYdoc = prosemirrorJSONToYDoc(this.editor.schema, this.initialContent); + if (editorYdoc) { + Y.applyUpdate(this.doc, Y.encodeStateAsUpdate(editorYdoc)); + } } } } else { diff --git a/src/lib/components/notes/NoteEditor.svelte b/src/lib/components/notes/NoteEditor.svelte index 37620f75e1..390a39f8ab 100644 --- a/src/lib/components/notes/NoteEditor.svelte +++ b/src/lib/components/notes/NoteEditor.svelte @@ -145,6 +145,9 @@ let inputElement = null; + // Computed HTML for editor: fall back to markdown if HTML is missing + $: editorHtml = note?.data?.content?.html || (note?.data?.content?.md ? marked.parse(note.data.content.md) : ''); + const init = async () => { loading = true; const res = await getNoteById(localStorage.token, id).catch((error) => { @@ -154,7 +157,7 @@ messages = []; - if (res) { + if (res) { note = res; files = res.data.files || []; @@ -1154,7 +1157,7 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings, className="input-prose-sm px-0.5 h-[calc(100%-2rem)]" json={true} bind:value={note.data.content.json} - html={note.data?.content?.html} + html={editorHtml} documentId={`note:${note.id}`} collaboration={true} socket={$socket} From 646835d76744ad9b2e67ede0407a61d62e969aab Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 17:45:39 +0400 Subject: [PATCH 125/254] feat: builtin native tools --- backend/open_webui/models/messages.py | 29 + backend/open_webui/tools/builtin.py | 846 +++++++++++++++++++++++++- backend/open_webui/utils/tools.py | 70 ++- 3 files changed, 921 insertions(+), 24 deletions(-) diff --git a/backend/open_webui/models/messages.py b/backend/open_webui/models/messages.py index c0e2007b2d..3a27069f38 100644 --- a/backend/open_webui/models/messages.py +++ b/backend/open_webui/models/messages.py @@ -521,5 +521,34 @@ class MessageTable: db.commit() return True + def search_messages_by_channel_ids( + self, + channel_ids: list[str], + query: str, + start_timestamp: Optional[int] = None, + end_timestamp: Optional[int] = None, + limit: int = 10, + db: Optional[Session] = None, + ) -> list[MessageModel]: + """Search messages in specified channels by content.""" + with get_db_context(db) as db: + query_builder = db.query(Message).filter( + Message.channel_id.in_(channel_ids), + Message.content.ilike(f"%{query}%"), + ) + + if start_timestamp: + query_builder = query_builder.filter(Message.created_at >= start_timestamp) + if end_timestamp: + query_builder = query_builder.filter(Message.created_at <= end_timestamp) + + messages = ( + query_builder + .order_by(Message.created_at.desc()) + .limit(limit) + .all() + ) + return [MessageModel.model_validate(msg) for msg in messages] + Messages = MessageTable() diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 922f9a10e2..de97fb5ec8 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -14,11 +14,128 @@ from fastapi import Request from open_webui.models.users import UserModel from open_webui.routers.retrieval import search_web from open_webui.retrieval.utils import get_content_from_url -from open_webui.routers.images import image_generations, image_edits, CreateImageForm, EditImageForm -from open_webui.routers.memories import query_memory, add_memory, QueryMemoryForm, AddMemoryForm +from open_webui.routers.images import ( + image_generations, + image_edits, + CreateImageForm, + EditImageForm, +) +from open_webui.routers.memories import ( + query_memory, + add_memory, + QueryMemoryForm, + AddMemoryForm, +) +from open_webui.models.notes import Notes +from open_webui.models.chats import Chats +from open_webui.models.channels import Channels, ChannelMember, Channel +from open_webui.models.messages import Messages, Message +from open_webui.models.groups import Groups log = logging.getLogger(__name__) +# ============================================================================= +# TIME UTILITIES +# ============================================================================= + + +async def get_current_timestamp( + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Get the current Unix timestamp in seconds. + + :return: JSON with current_timestamp (seconds) and current_iso (ISO format) + """ + try: + import datetime + + now = datetime.datetime.now(datetime.timezone.utc) + return json.dumps( + { + "current_timestamp": int(now.timestamp()), + "current_iso": now.isoformat(), + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"get_current_timestamp error: {e}") + return json.dumps({"error": str(e)}) + + +async def calculate_timestamp( + days_ago: int = 0, + weeks_ago: int = 0, + months_ago: int = 0, + years_ago: int = 0, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Get the current Unix timestamp, optionally adjusted by days, weeks, months, or years. + Use this to calculate timestamps for date filtering in search functions. + Examples: "last week" = weeks_ago=1, "3 days ago" = days_ago=3, "a year ago" = years_ago=1 + + :param days_ago: Number of days to subtract from current time (default: 0) + :param weeks_ago: Number of weeks to subtract from current time (default: 0) + :param months_ago: Number of months to subtract from current time (default: 0) + :param years_ago: Number of years to subtract from current time (default: 0) + :return: JSON with current_timestamp and calculated_timestamp (both in seconds) + """ + try: + import datetime + from dateutil.relativedelta import relativedelta + + now = datetime.datetime.now(datetime.timezone.utc) + current_ts = int(now.timestamp()) + + # Calculate the adjusted time + total_days = days_ago + (weeks_ago * 7) + adjusted = now - datetime.timedelta(days=total_days) + + # Handle months and years separately (variable length) + if months_ago > 0 or years_ago > 0: + adjusted = adjusted - relativedelta(months=months_ago, years=years_ago) + + adjusted_ts = int(adjusted.timestamp()) + + return json.dumps( + { + "current_timestamp": current_ts, + "current_iso": now.isoformat(), + "calculated_timestamp": adjusted_ts, + "calculated_iso": adjusted.isoformat(), + }, + ensure_ascii=False, + ) + except ImportError: + # Fallback without dateutil + import datetime + + now = datetime.datetime.now(datetime.timezone.utc) + current_ts = int(now.timestamp()) + total_days = days_ago + (weeks_ago * 7) + (months_ago * 30) + (years_ago * 365) + adjusted = now - datetime.timedelta(days=total_days) + adjusted_ts = int(adjusted.timestamp()) + return json.dumps( + { + "current_timestamp": current_ts, + "current_iso": now.isoformat(), + "calculated_timestamp": adjusted_ts, + "calculated_iso": adjusted.isoformat(), + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"calculate_timestamp error: {e}") + return json.dumps({"error": str(e)}) + + +# ============================================================================= +# WEB SEARCH TOOLS +# ============================================================================= + async def web_search( query: str, @@ -70,18 +187,23 @@ async def fetch_url( try: content, _ = get_content_from_url(__request__, url) - + # Truncate if too long (avoid overwhelming context) max_length = 50000 if len(content) > max_length: content = content[:max_length] + "\n\n[Content truncated...]" - + return content except Exception as e: log.exception(f"fetch_url error: {e}") return json.dumps({"error": str(e)}) +# ============================================================================= +# IMAGE GENERATION TOOLS +# ============================================================================= + + async def generate_image( prompt: str, __request__: Request = None, @@ -113,8 +235,7 @@ async def generate_image( "type": "files", "data": { "files": [ - {"type": "image", "url": img["url"]} - for img in images + {"type": "image", "url": img["url"]} for img in images ] }, } @@ -159,8 +280,7 @@ async def edit_image( "type": "files", "data": { "files": [ - {"type": "image", "url": img["url"]} - for img in images + {"type": "image", "url": img["url"]} for img in images ] }, } @@ -172,6 +292,11 @@ async def edit_image( return json.dumps({"error": str(e)}) +# ============================================================================= +# MEMORY TOOLS +# ============================================================================= + + async def memory_query( query: str, __request__: Request = None, @@ -199,9 +324,12 @@ async def memory_query( memories = [] for doc_idx, doc in enumerate(results.documents[0]): created_at = "Unknown" - if results.metadatas and results.metadatas[0][doc_idx].get("created_at"): + if results.metadatas and results.metadatas[0][doc_idx].get( + "created_at" + ): created_at = time.strftime( - "%Y-%m-%d", time.localtime(results.metadatas[0][doc_idx]["created_at"]) + "%Y-%m-%d", + time.localtime(results.metadatas[0][doc_idx]["created_at"]), ) memories.append({"date": created_at, "content": doc}) return json.dumps(memories, ensure_ascii=False) @@ -239,3 +367,701 @@ async def memory_add( except Exception as e: log.exception(f"memory_add error: {e}") return json.dumps({"error": str(e)}) + + +# ============================================================================= +# NOTES TOOLS +# ============================================================================= + + +async def search_notes( + query: str, + count: int = 5, + start_timestamp: Optional[int] = None, + end_timestamp: Optional[int] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search the user's notes by title and content. + + :param query: The search query to find matching notes + :param count: Maximum number of results to return (default: 5) + :param start_timestamp: Only include notes updated after this Unix timestamp (seconds) + :param end_timestamp: Only include notes updated before this Unix timestamp (seconds) + :return: JSON with matching notes containing id, title, and content snippet + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + user_id = __user__.get("id") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + result = Notes.search_notes( + user_id=user_id, + filter={ + "query": query, + "user_id": user_id, + "group_ids": user_group_ids, + "permission": "read", + }, + skip=0, + limit=count * 3, # Fetch more for filtering + ) + + # Convert timestamps to nanoseconds for comparison + start_ts = start_timestamp * 1_000_000_000 if start_timestamp else None + end_ts = end_timestamp * 1_000_000_000 if end_timestamp else None + + notes = [] + for note in result.items: + # Apply date filters (updated_at is in nanoseconds) + if start_ts and note.updated_at < start_ts: + continue + if end_ts and note.updated_at > end_ts: + continue + + # Extract a snippet from the markdown content + content_snippet = "" + if note.data and note.data.get("content", {}).get("md"): + md_content = note.data["content"]["md"] + lower_content = md_content.lower() + lower_query = query.lower() + idx = lower_content.find(lower_query) + if idx != -1: + start = max(0, idx - 50) + end = min(len(md_content), idx + len(query) + 100) + content_snippet = ( + ("..." if start > 0 else "") + + md_content[start:end] + + ("..." if end < len(md_content) else "") + ) + else: + content_snippet = md_content[:150] + ( + "..." if len(md_content) > 150 else "" + ) + + notes.append( + { + "id": note.id, + "title": note.title, + "snippet": content_snippet, + "updated_at": note.updated_at, + } + ) + + if len(notes) >= count: + break + + return json.dumps(notes, ensure_ascii=False) + except Exception as e: + log.exception(f"search_notes error: {e}") + return json.dumps({"error": str(e)}) + + +async def view_note( + note_id: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Get the full content of a note by its ID. + + :param note_id: The ID of the note to retrieve + :return: JSON with the note's id, title, and full markdown content + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + note = Notes.get_note_by_id(note_id) + + if not note: + return json.dumps({"error": "Note not found"}) + + # Check access permission + user_id = __user__.get("id") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + from open_webui.utils.access_control import has_access + + if note.user_id != user_id and not has_access( + user_id, "read", note.access_control, user_group_ids + ): + return json.dumps({"error": "Access denied"}) + + # Extract markdown content + content = "" + if note.data and note.data.get("content", {}).get("md"): + content = note.data["content"]["md"] + + return json.dumps( + { + "id": note.id, + "title": note.title, + "content": content, + "updated_at": note.updated_at, + "created_at": note.created_at, + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"view_note error: {e}") + return json.dumps({"error": str(e)}) + + +async def write_note( + title: str, + content: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Create a new note with the given title and content. + + :param title: The title of the new note + :param content: The markdown content for the note + :return: JSON with success status and new note id + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + from open_webui.models.notes import NoteForm + + user_id = __user__.get("id") + + form = NoteForm( + title=title, + data={"content": {"md": content}}, + access_control={}, # Private by default - only owner can access + ) + + new_note = Notes.insert_new_note(user_id, form) + + if not new_note: + return json.dumps({"error": "Failed to create note"}) + + return json.dumps( + { + "status": "success", + "id": new_note.id, + "title": new_note.title, + "created_at": new_note.created_at, + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"write_note error: {e}") + return json.dumps({"error": str(e)}) + + +async def replace_note_content( + note_id: str, + content: str, + title: Optional[str] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Update the content of a note. Use this to modify task lists, add notes, or update content. + + :param note_id: The ID of the note to update + :param content: The new markdown content for the note + :param title: Optional new title for the note + :return: JSON with success status and updated note info + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + from open_webui.models.notes import NoteUpdateForm + + note = Notes.get_note_by_id(note_id) + + if not note: + return json.dumps({"error": "Note not found"}) + + # Check write permission + user_id = __user__.get("id") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + from open_webui.utils.access_control import has_access + + if note.user_id != user_id and not has_access( + user_id, "write", note.access_control, user_group_ids + ): + return json.dumps({"error": "Write access denied"}) + + # Build update form + update_data = {"data": {"content": {"md": content}}} + if title: + update_data["title"] = title + + form = NoteUpdateForm(**update_data) + updated_note = Notes.update_note_by_id(note_id, form) + + if not updated_note: + return json.dumps({"error": "Failed to update note"}) + + return json.dumps( + { + "status": "success", + "id": updated_note.id, + "title": updated_note.title, + "updated_at": updated_note.updated_at, + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"replace_note_content error: {e}") + return json.dumps({"error": str(e)}) + + +# ============================================================================= +# CHATS TOOLS +# ============================================================================= + + +async def search_chats( + query: str, + count: int = 5, + start_timestamp: Optional[int] = None, + end_timestamp: Optional[int] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search the user's previous chat conversations by title and message content. + + :param query: The search query to find matching chats + :param count: Maximum number of results to return (default: 5) + :param start_timestamp: Only include chats updated after this Unix timestamp (seconds) + :param end_timestamp: Only include chats updated before this Unix timestamp (seconds) + :return: JSON with matching chats containing id, title, updated_at, and content snippet + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + user_id = __user__.get("id") + + chats = Chats.get_chats_by_user_id_and_search_text( + user_id=user_id, + search_text=query, + include_archived=False, + skip=0, + limit=count * 3, # Fetch more for filtering + ) + + results = [] + for chat in chats: + # Apply date filters (updated_at is in seconds) + if start_timestamp and chat.updated_at < start_timestamp: + continue + if end_timestamp and chat.updated_at > end_timestamp: + continue + + # Find a matching message snippet + snippet = "" + messages = chat.chat.get("history", {}).get("messages", {}) + lower_query = query.lower() + + for msg_id, msg in messages.items(): + content = msg.get("content", "") + if isinstance(content, str) and lower_query in content.lower(): + idx = content.lower().find(lower_query) + start = max(0, idx - 50) + end = min(len(content), idx + len(query) + 100) + snippet = ( + ("..." if start > 0 else "") + + content[start:end] + + ("..." if end < len(content) else "") + ) + break + + if not snippet and lower_query in chat.title.lower(): + snippet = f"Title match: {chat.title}" + + results.append( + { + "id": chat.id, + "title": chat.title, + "snippet": snippet, + "updated_at": chat.updated_at, + } + ) + + if len(results) >= count: + break + + return json.dumps(results, ensure_ascii=False) + except Exception as e: + log.exception(f"search_chats error: {e}") + return json.dumps({"error": str(e)}) + + +async def view_chat( + chat_id: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Get the full conversation history of a chat by its ID. + + :param chat_id: The ID of the chat to retrieve + :return: JSON with the chat's id, title, and messages + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + user_id = __user__.get("id") + + chat = Chats.get_chat_by_id_and_user_id(chat_id, user_id) + + if not chat: + return json.dumps({"error": "Chat not found or access denied"}) + + # Extract messages from history + messages = [] + history = chat.chat.get("history", {}) + msg_dict = history.get("messages", {}) + + # Build message chain from currentId + current_id = history.get("currentId") + visited = set() + + while current_id and current_id not in visited: + visited.add(current_id) + msg = msg_dict.get(current_id) + if msg: + messages.append( + { + "role": msg.get("role", ""), + "content": msg.get("content", ""), + } + ) + current_id = msg.get("parentId") if msg else None + + # Reverse to get chronological order + messages.reverse() + + return json.dumps( + { + "id": chat.id, + "title": chat.title, + "messages": messages, + "updated_at": chat.updated_at, + "created_at": chat.created_at, + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"view_chat error: {e}") + return json.dumps({"error": str(e)}) + + +# ============================================================================= +# CHANNELS TOOLS +# ============================================================================= + + +async def search_channels( + query: str, + count: int = 5, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search for channels by name and description that the user has access to. + + :param query: The search query to find matching channels + :param count: Maximum number of results to return (default: 5) + :return: JSON with matching channels containing id, name, description, and type + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + user_id = __user__.get("id") + + # Get all channels the user has access to + all_channels = Channels.get_channels_by_user_id(user_id) + + # Filter by query + lower_query = query.lower() + matching_channels = [] + + for channel in all_channels: + name_match = lower_query in channel.name.lower() if channel.name else False + desc_match = lower_query in (channel.description or "").lower() + + if name_match or desc_match: + matching_channels.append( + { + "id": channel.id, + "name": channel.name, + "description": channel.description or "", + "type": channel.type or "public", + } + ) + + if len(matching_channels) >= count: + break + + return json.dumps(matching_channels, ensure_ascii=False) + except Exception as e: + log.exception(f"search_channels error: {e}") + return json.dumps({"error": str(e)}) + + +async def search_channel_messages( + query: str, + count: int = 10, + start_timestamp: Optional[int] = None, + end_timestamp: Optional[int] = None, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search for messages in channels the user is a member of, including thread replies. + + :param query: The search query to find matching messages + :param count: Maximum number of results to return (default: 10) + :param start_timestamp: Only include messages created after this Unix timestamp (seconds) + :param end_timestamp: Only include messages created before this Unix timestamp (seconds) + :return: JSON with matching messages containing channel info, message content, and thread context + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + user_id = __user__.get("id") + + # Get all channels the user has access to + user_channels = Channels.get_channels_by_user_id(user_id) + channel_ids = [c.id for c in user_channels] + channel_map = {c.id: c for c in user_channels} + + if not channel_ids: + return json.dumps([]) + + # Convert timestamps to nanoseconds (Message.created_at is in nanoseconds) + start_ts = start_timestamp * 1_000_000_000 if start_timestamp else None + end_ts = end_timestamp * 1_000_000_000 if end_timestamp else None + + # Search messages using the model method + matching_messages = Messages.search_messages_by_channel_ids( + channel_ids=channel_ids, + query=query, + start_timestamp=start_ts, + end_timestamp=end_ts, + limit=count, + ) + + results = [] + for msg in matching_messages: + channel = channel_map.get(msg.channel_id) + + # Extract snippet around the match + content = msg.content or "" + lower_query = query.lower() + idx = content.lower().find(lower_query) + if idx != -1: + start = max(0, idx - 50) + end = min(len(content), idx + len(query) + 100) + snippet = ( + ("..." if start > 0 else "") + + content[start:end] + + ("..." if end < len(content) else "") + ) + else: + snippet = content[:150] + ("..." if len(content) > 150 else "") + + results.append( + { + "channel_id": msg.channel_id, + "channel_name": channel.name if channel else "Unknown", + "message_id": msg.id, + "content_snippet": snippet, + "is_thread_reply": msg.parent_id is not None, + "parent_id": msg.parent_id, + "created_at": msg.created_at, + } + ) + + return json.dumps(results, ensure_ascii=False) + except Exception as e: + log.exception(f"search_channel_messages error: {e}") + return json.dumps({"error": str(e)}) + + +async def view_channel_message( + message_id: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Get the full content of a channel message by its ID, including thread replies. + + :param message_id: The ID of the message to retrieve + :return: JSON with the message content, channel info, and thread replies if any + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + user_id = __user__.get("id") + + message = Messages.get_message_by_id(message_id) + + if not message: + return json.dumps({"error": "Message not found"}) + + # Verify user has access to the channel + channel = Channels.get_channel_by_id(message.channel_id) + if not channel: + return json.dumps({"error": "Channel not found"}) + + # Check if user has access to the channel + user_channels = Channels.get_channels_by_user_id(user_id) + channel_ids = [c.id for c in user_channels] + + if message.channel_id not in channel_ids: + return json.dumps({"error": "Access denied"}) + + # Build response with thread information + result = { + "id": message.id, + "channel_id": message.channel_id, + "channel_name": channel.name, + "content": message.content, + "user_id": message.user_id, + "is_thread_reply": message.parent_id is not None, + "parent_id": message.parent_id, + "reply_count": message.reply_count, + "created_at": message.created_at, + "updated_at": message.updated_at, + } + + # Include user info if available + if message.user: + result["user_name"] = message.user.name + + return json.dumps(result, ensure_ascii=False) + except Exception as e: + log.exception(f"view_channel_message error: {e}") + return json.dumps({"error": str(e)}) + + +async def view_channel_thread( + parent_message_id: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Get all messages in a channel thread, including the parent message and all replies. + + :param parent_message_id: The ID of the parent message that started the thread + :return: JSON with the parent message and all thread replies in chronological order + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + user_id = __user__.get("id") + + # Get the parent message + parent_message = Messages.get_message_by_id(parent_message_id) + + if not parent_message: + return json.dumps({"error": "Message not found"}) + + # Verify user has access to the channel + channel = Channels.get_channel_by_id(parent_message.channel_id) + if not channel: + return json.dumps({"error": "Channel not found"}) + + user_channels = Channels.get_channels_by_user_id(user_id) + channel_ids = [c.id for c in user_channels] + + if parent_message.channel_id not in channel_ids: + return json.dumps({"error": "Access denied"}) + + # Get all thread replies + thread_replies = Messages.get_thread_replies_by_message_id(parent_message_id) + + # Build the response + messages = [] + + # Add parent message first + messages.append( + { + "id": parent_message.id, + "content": parent_message.content, + "user_id": parent_message.user_id, + "user_name": parent_message.user.name if parent_message.user else None, + "is_parent": True, + "created_at": parent_message.created_at, + } + ) + + # Add thread replies (reverse to get chronological order) + for reply in reversed(thread_replies): + messages.append( + { + "id": reply.id, + "content": reply.content, + "user_id": reply.user_id, + "user_name": reply.user.name if reply.user else None, + "is_parent": False, + "reply_to_id": reply.reply_to_id, + "created_at": reply.created_at, + } + ) + + return json.dumps( + { + "channel_id": parent_message.channel_id, + "channel_name": channel.name, + "thread_id": parent_message_id, + "message_count": len(messages), + "messages": messages, + }, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"view_channel_thread 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 4379d9f4d4..cd27118098 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -44,8 +44,24 @@ from open_webui.env import ( AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL, ) from open_webui.tools.builtin import ( - web_search, fetch_url, generate_image, edit_image, - memory_query, memory_add + web_search, + fetch_url, + generate_image, + edit_image, + memory_query, + memory_add, + get_current_timestamp, + calculate_timestamp, + search_notes, + search_chats, + search_channels, + search_channel_messages, + view_note, + view_chat, + view_channel_message, + view_channel_thread, + replace_note_content, + write_note, ) import copy @@ -324,7 +340,9 @@ async def get_tools( return tools_dict -def get_builtin_tools(request: Request, extra_params: dict, features: dict = None) -> dict[str, dict]: +def get_builtin_tools( + request: Request, extra_params: dict, features: dict = None +) -> dict[str, dict]: """ Get built-in tools for native function calling. Only returns tools when BOTH the global config is enabled AND the feature is enabled for this chat. @@ -333,23 +351,47 @@ def get_builtin_tools(request: Request, extra_params: dict, features: dict = Non builtin_functions = [] features = features or {} - # Add web search tools if enabled globally AND for this chat - if (getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) - and features.get("web_search")): - builtin_functions.extend([web_search, fetch_url]) + # Time utilities - always available for date calculations + builtin_functions.extend([get_current_timestamp, calculate_timestamp]) - # Add image generation/edit tools if enabled globally AND for this chat - if (getattr(request.app.state.config, "ENABLE_IMAGE_GENERATION", False) - and features.get("image_generation")): - builtin_functions.append(generate_image) - if (getattr(request.app.state.config, "ENABLE_IMAGE_EDIT", False) - and features.get("image_generation")): - builtin_functions.append(edit_image) + # Chats tools - search and fetch user's chat history (always available) + builtin_functions.extend([search_chats, view_chat]) # Add memory tools if enabled for this chat if features.get("memory"): builtin_functions.extend([memory_query, memory_add]) + # Add web search tools if enabled globally AND for this chat + if getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) and features.get( + "web_search" + ): + builtin_functions.extend([web_search, fetch_url]) + + # Add image generation/edit tools if enabled globally AND for this chat + if getattr( + request.app.state.config, "ENABLE_IMAGE_GENERATION", False + ) and features.get("image_generation"): + builtin_functions.append(generate_image) + if getattr(request.app.state.config, "ENABLE_IMAGE_EDIT", False) and features.get( + "image_generation" + ): + builtin_functions.append(edit_image) + + # Notes tools - search, view, create, and update user's notes (if notes enabled globally) + if getattr(request.app.state.config, "ENABLE_NOTES", False): + builtin_functions.extend([search_notes, view_note, write_note, replace_note_content]) + + # Channels tools - search channels and messages (if channels enabled globally) + if getattr(request.app.state.config, "ENABLE_CHANNELS", False): + builtin_functions.extend( + [ + search_channels, + search_channel_messages, + view_channel_thread, + view_channel_message, + ] + ) + for func in builtin_functions: callable = get_async_tool_function_and_apply_extra_params( func, From a3270648d8b8535443d8ce2ea719f8e678e4e358 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 17:50:40 +0400 Subject: [PATCH 126/254] refac --- backend/open_webui/models/notes.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/models/notes.py b/backend/open_webui/models/notes.py index 6f68aaaf4f..425cd9e2cc 100644 --- a/backend/open_webui/models/notes.py +++ b/backend/open_webui/models/notes.py @@ -256,12 +256,12 @@ class NoteTable: if filter: query_key = filter.get("query") if query_key: + # Normalize search by removing hyphens and spaces (e.g., "todo" matches "to-do" and "to do") + normalized_query = query_key.replace("-", "").replace(" ", "") query = query.filter( or_( - Note.title.ilike(f"%{query_key}%"), - cast(Note.data["content"]["md"], Text).ilike( - f"%{query_key}%" - ), + func.replace(func.replace(Note.title, "-", ""), " ", "").ilike(f"%{normalized_query}%"), + func.replace(func.replace(cast(Note.data["content"]["md"], Text), "-", ""), " ", "").ilike(f"%{normalized_query}%"), ) ) From 00af37bb4ed1ea0957c7c84a6a8def3a7998b8ca Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 17:56:41 +0400 Subject: [PATCH 127/254] enh: model gif/webp support --- src/lib/components/workspace/Models/ModelEditor.svelte | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index edf5522ef2..a0a1c7b7b4 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -350,6 +350,15 @@ reader.onload = (event) => { let originalImageUrl = `${event.target?.result}`; + // For animated formats (gif, webp), skip resizing to preserve animation + const fileType = (inputFiles[0] as any)?.['type']; + if (fileType === 'image/gif' || fileType === 'image/webp') { + info.meta.profile_image_url = originalImageUrl; + inputFiles = null; + filesInputElement.value = ''; + return; + } + const img = new Image(); img.src = originalImageUrl; From 9c5773d0afa99ee2ad9be60f00f8694993417038 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Mon, 5 Jan 2026 09:15:00 -0500 Subject: [PATCH 128/254] feat: add chat:message:favorite event for action functions (#20375) * feat: add chat:message:favorite event for action functions * Update Chat.svelte * Update Chat.svelte --- src/lib/components/chat/Chat.svelte | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 22276ca107..011afca87b 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -390,6 +390,9 @@ if (autoScroll) { scrollToBottom('smooth'); } + } else if (type === 'chat:message:favorite') { + // Update message favorite status + message.favorite = data.favorite; } else if (type === 'chat:title') { chatTitle.set(data); currentChatPage.set(1); From d3ab9f4b96eee7f91c9b1355cee055fdabca9730 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 18:21:00 +0400 Subject: [PATCH 129/254] fix: failed hash in files --- backend/open_webui/routers/retrieval.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 2d17e7553f..379cf4da0f 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -1734,10 +1734,10 @@ def process_file( db=db, ) hash = calculate_sha256_string(text_content) - Files.update_file_hash_by_id(file.id, hash, db=db) if request.app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL: Files.update_file_data_by_id(file.id, {"status": "completed"}, db=db) + Files.update_file_hash_by_id(file.id, hash, db=db) return { "status": True, "collection_name": None, @@ -1774,6 +1774,7 @@ def process_file( {"status": "completed"}, db=db, ) + Files.update_file_hash_by_id(file.id, hash, db=db) return { "status": True, From 1d08376860e775049abd1dd5f568ac0c6466c944 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 18:55:44 +0400 Subject: [PATCH 130/254] refac --- backend/open_webui/models/files.py | 2 +- backend/open_webui/routers/retrieval.py | 2 ++ backend/open_webui/utils/middleware.py | 20 ++++++++++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/models/files.py b/backend/open_webui/models/files.py index f734ea62d7..937a117681 100644 --- a/backend/open_webui/models/files.py +++ b/backend/open_webui/models/files.py @@ -257,7 +257,7 @@ class FilesTable: return None def update_file_hash_by_id( - self, id: str, hash: str, db: Optional[Session] = None + self, id: str, hash: Optional[str], db: Optional[Session] = None ) -> Optional[FileModel]: with get_db_context(db) as db: try: diff --git a/backend/open_webui/routers/retrieval.py b/backend/open_webui/routers/retrieval.py index 379cf4da0f..2468553681 100644 --- a/backend/open_webui/routers/retrieval.py +++ b/backend/open_webui/routers/retrieval.py @@ -1794,6 +1794,8 @@ def process_file( {"status": "failed"}, db=db, ) + # Clear the hash so the file can be re-uploaded after fixing the issue + Files.update_file_hash_by_id(file.id, None, db=db) if "No pandoc was found" in str(e): raise HTTPException( diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 15414aa002..07b5a4b5ee 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2721,6 +2721,26 @@ async def process_chat_response( "arguments" ] += delta_arguments + # Emit pending tool calls in real-time + if response_tool_calls: + pending_content_blocks = content_blocks + [ + { + "type": "tool_calls", + "content": response_tool_calls, + "pending": True, + } + ] + await event_emitter( + { + "type": "chat:completion", + "data": { + "content": serialize_content_blocks( + pending_content_blocks + ), + }, + } + ) + image_urls = get_image_urls( delta.get("images", []), request, metadata, user ) From 460ab07f393b0d33dab519e0a8fc7813eea097b6 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 19:26:27 +0400 Subject: [PATCH 131/254] chore: y-protocols dep Co-Authored-By: G30 <50341825+silentoplayz@users.noreply.github.com> Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 17baf5042a..173ddec721 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,6 +99,7 @@ "vite-plugin-static-copy": "^2.2.0", "xlsx": "^0.18.5", "y-prosemirror": "^1.3.7", + "y-protocols": "^1.0.7", "yaml": "^2.7.1", "yjs": "^13.6.27" }, @@ -14865,11 +14866,10 @@ } }, "node_modules/y-protocols": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz", - "integrity": "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.7.tgz", + "integrity": "sha512-YSVsLoXxO67J6eE/nV4AtFtT3QEotZf5sK5BHxFBXso7VDUT3Tx07IfA6hsu5Q5OmBdMkQVmFZ9QOA7fikWvnw==", "license": "MIT", - "peer": true, "dependencies": { "lib0": "^0.2.85" }, diff --git a/package.json b/package.json index f0a599274c..3564f79798 100644 --- a/package.json +++ b/package.json @@ -143,6 +143,7 @@ "vite-plugin-static-copy": "^2.2.0", "xlsx": "^0.18.5", "y-prosemirror": "^1.3.7", + "y-protocols": "^1.0.7", "yaml": "^2.7.1", "yjs": "^13.6.27" }, From bb821ab654e93908a3b4632c359753eeff053264 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 21:49:54 +0400 Subject: [PATCH 132/254] fix: revert model profile image cache --- backend/open_webui/routers/models.py | 68 ++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index 4d31ac2f9e..297d9e5a20 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -97,7 +97,9 @@ async def get_models( @router.get("/base", response_model=list[ModelResponse]) -async def get_base_models(user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def get_base_models( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): return Models.get_base_models(db=db) @@ -107,7 +109,9 @@ async def get_base_models(user=Depends(get_admin_user), db: Session = Depends(ge @router.get("/tags", response_model=list[str]) -async def get_model_tags(user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_model_tags( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: models = Models.get_models(db=db) else: @@ -175,9 +179,16 @@ async def create_new_model( @router.get("/export", response_model=list[ModelModel]) -async def export_models(request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def export_models( + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if user.role != "admin" and not has_permission( - user.id, "workspace.models_export", request.app.state.config.USER_PERMISSIONS, db=db + user.id, + "workspace.models_export", + request.app.state.config.USER_PERMISSIONS, + db=db, ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -207,7 +218,10 @@ async def import_models( db: Session = Depends(get_session), ): if user.role != "admin" and not has_permission( - user.id, "workspace.models_import", request.app.state.config.USER_PERMISSIONS, db=db + user.id, + "workspace.models_import", + request.app.state.config.USER_PERMISSIONS, + db=db, ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -236,7 +250,9 @@ async def import_models( model_data["meta"] = model_data.get("meta", {}) model_data["params"] = model_data.get("params", {}) new_model = ModelForm(**model_data) - Models.insert_new_model(user_id=user.id, form_data=new_model, db=db) + Models.insert_new_model( + user_id=user.id, form_data=new_model, db=db + ) return True else: raise HTTPException(status_code=400, detail="Invalid JSON format") @@ -256,7 +272,10 @@ class SyncModelsForm(BaseModel): @router.post("/sync", response_model=list[ModelModel]) async def sync_models( - request: Request, form_data: SyncModelsForm, user=Depends(get_admin_user), db: Session = Depends(get_session) + request: Request, + form_data: SyncModelsForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): return Models.sync_models(user.id, form_data.models, db=db) @@ -272,7 +291,9 @@ class ModelIdForm(BaseModel): # Note: We're not using the typical url path param here, but instead using a query parameter to allow '/' in the id @router.get("/model", response_model=Optional[ModelResponse]) -async def get_model_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_model_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): model = Models.get_model_by_id(id, db=db) if model: if ( @@ -299,17 +320,17 @@ async def get_model_by_id(id: str, user=Depends(get_verified_user), db: Session @router.get("/model/profile/image") -async def get_model_profile_image(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_model_profile_image( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): model = Models.get_model_by_id(id, db=db) - # Cache-control headers to prevent stale cached images - cache_headers = {"Cache-Control": "no-cache, must-revalidate"} if model: if model.meta.profile_image_url: if model.meta.profile_image_url.startswith("http"): return Response( status_code=status.HTTP_302_FOUND, - headers={"Location": model.meta.profile_image_url, **cache_headers}, + headers={"Location": model.meta.profile_image_url}, ) elif model.meta.profile_image_url.startswith("data:image"): try: @@ -323,15 +344,14 @@ async def get_model_profile_image(id: str, user=Depends(get_verified_user), db: media_type=media_type, headers={ "Content-Disposition": "inline", - **cache_headers, }, ) except Exception as e: pass - return FileResponse(f"{STATIC_DIR}/favicon.png", headers=cache_headers) + return FileResponse(f"{STATIC_DIR}/favicon.png") else: - return FileResponse(f"{STATIC_DIR}/favicon.png", headers=cache_headers) + return FileResponse(f"{STATIC_DIR}/favicon.png") ############################ @@ -340,7 +360,9 @@ async def get_model_profile_image(id: str, user=Depends(get_verified_user), db: @router.post("/model/toggle", response_model=Optional[ModelResponse]) -async def toggle_model_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def toggle_model_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): model = Models.get_model_by_id(id, db=db) if model: if ( @@ -397,7 +419,9 @@ async def update_model_by_id( detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - model = Models.update_model_by_id(form_data.id, ModelForm(**form_data.model_dump()), db=db) + model = Models.update_model_by_id( + form_data.id, ModelForm(**form_data.model_dump()), db=db + ) return model @@ -407,7 +431,11 @@ async def update_model_by_id( @router.post("/model/delete", response_model=bool) -async def delete_model_by_id(form_data: ModelIdForm, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def delete_model_by_id( + form_data: ModelIdForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): model = Models.get_model_by_id(form_data.id, db=db) if not model: raise HTTPException( @@ -430,6 +458,8 @@ async def delete_model_by_id(form_data: ModelIdForm, user=Depends(get_verified_u @router.delete("/delete/all", response_model=bool) -async def delete_all_models(user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def delete_all_models( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): result = Models.delete_all_models(db=db) return result From b1d30673b69571e081abb881d34944cf33cdc67e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 21:54:33 +0400 Subject: [PATCH 133/254] refac --- .../admin/Settings/Evaluations/ArenaModelModal.svelte | 2 +- .../components/chat/Settings/Account/UserProfileImage.svelte | 2 +- src/lib/components/workspace/Models/ModelEditor.svelte | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib/components/admin/Settings/Evaluations/ArenaModelModal.svelte b/src/lib/components/admin/Settings/Evaluations/ArenaModelModal.svelte index 48b9d57d39..ef78d2352e 100644 --- a/src/lib/components/admin/Settings/Evaluations/ArenaModelModal.svelte +++ b/src/lib/components/admin/Settings/Evaluations/ArenaModelModal.svelte @@ -201,7 +201,7 @@ ctx.drawImage(img, offsetX, offsetY, newWidth, newHeight); // Get the base64 representation of the compressed image - const compressedSrc = canvas.toDataURL('image/jpeg'); + const compressedSrc = canvas.toDataURL('image/webp', 0.8); // Display the compressed image profileImageUrl = compressedSrc; diff --git a/src/lib/components/chat/Settings/Account/UserProfileImage.svelte b/src/lib/components/chat/Settings/Account/UserProfileImage.svelte index bda54d0dd1..597af09abb 100644 --- a/src/lib/components/chat/Settings/Account/UserProfileImage.svelte +++ b/src/lib/components/chat/Settings/Account/UserProfileImage.svelte @@ -61,7 +61,7 @@ ctx.drawImage(img, offsetX, offsetY, newWidth, newHeight); // Get the base64 representation of the compressed image - const compressedSrc = canvas.toDataURL('image/jpeg'); + const compressedSrc = canvas.toDataURL('image/webp', 0.8); // Display the compressed image profileImageUrl = compressedSrc; diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index a0a1c7b7b4..af863cc860 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -391,7 +391,7 @@ ctx.drawImage(img, offsetX, offsetY, newWidth, newHeight); // Get the base64 representation of the compressed image - const compressedSrc = canvas.toDataURL(); + const compressedSrc = canvas.toDataURL('image/webp', 0.8); // Display the compressed image info.meta.profile_image_url = compressedSrc; From ab7b97e21f1abfff4655207902444717fb619320 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 22:12:49 +0400 Subject: [PATCH 134/254] refac --- backend/open_webui/routers/models.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index 297d9e5a20..4eb20f595d 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -320,12 +320,14 @@ async def get_model_by_id( @router.get("/model/profile/image") -async def get_model_profile_image( +def get_model_profile_image( id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) ): model = Models.get_model_by_id(id, db=db) if model: + etag = f'"{model.updated_at}"' if model.updated_at else None + if model.meta.profile_image_url: if model.meta.profile_image_url.startswith("http"): return Response( @@ -339,12 +341,14 @@ async def get_model_profile_image( image_buffer = io.BytesIO(image_data) media_type = header.split(";")[0].lstrip("data:") + headers = {"Content-Disposition": "inline"} + if etag: + headers["ETag"] = etag + return StreamingResponse( image_buffer, media_type=media_type, - headers={ - "Content-Disposition": "inline", - }, + headers=headers, ) except Exception as e: pass From f5455d48c438c0eaa7c7c8d920c0b32323f72707 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 5 Jan 2026 19:34:25 +0100 Subject: [PATCH 135/254] Chore: dup bump for NPM and PIP (#20386) * Update pyproject.toml * Update aiohttp version to 3.13.3 * Update aiohttp version to 3.13.3 * Update pyproject.toml * Update requirements.txt * Update package.json --- backend/requirements-min.txt | 2 +- backend/requirements.txt | 6 +++--- package.json | 4 ++-- pyproject.toml | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/requirements-min.txt b/backend/requirements-min.txt index 115d1bc92f..45639dd1db 100644 --- a/backend/requirements-min.txt +++ b/backend/requirements-min.txt @@ -16,7 +16,7 @@ PyJWT[crypto]==2.10.1 authlib==1.6.6 requests==2.32.5 -aiohttp==3.13.2 +aiohttp==3.13.3 async-timeout aiocache aiofiles diff --git a/backend/requirements.txt b/backend/requirements.txt index 3369e68ede..05ad5c475f 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -13,7 +13,7 @@ PyJWT[crypto]==2.10.1 authlib==1.6.6 requests==2.32.5 -aiohttp==3.13.2 +aiohttp==3.13.3 async-timeout aiocache aiofiles @@ -81,7 +81,7 @@ psutil sentencepiece soundfile==0.13.1 -pillow==12.0.0 +pillow==12.1.0 opencv-python-headless==4.12.0.88 rapidocr-onnxruntime==1.4.4 rank-bm25==0.2.2 @@ -115,7 +115,7 @@ psycopg2-binary==2.9.11 pgvector==0.4.2 PyMySQL==1.1.2 -boto3==1.42.19 +boto3==1.42.21 pymilvus==2.6.6 qdrant-client==1.16.2 diff --git a/package.json b/package.json index 3564f79798..5b0054552f 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "tailwindcss": "^4.0.0", "tslib": "^2.4.1", "typescript": "^5.5.4", - "vite": "^5.4.14", + "vite": "^5.4.21", "vitest": "^1.6.1" }, "type": "module", @@ -106,7 +106,7 @@ "i18next-resources-to-backend": "^1.2.0", "idb": "^7.1.1", "js-sha256": "^0.10.1", - "jspdf": "^3.0.0", + "jspdf": "^4.0.0", "katex": "^0.16.22", "kokoro-js": "^1.1.1", "leaflet": "^1.9.4", diff --git a/pyproject.toml b/pyproject.toml index a397ebe702..09b0045e9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ "authlib==1.6.6", "requests==2.32.5", - "aiohttp==3.13.2", + "aiohttp==3.13.3", "async-timeout", "aiocache", "aiofiles", @@ -60,7 +60,7 @@ dependencies = [ "chromadb==1.4.0", "opensearch-py==3.1.0", "PyMySQL==1.1.2", - "boto3==1.42.19", + "boto3==1.42.21", "transformers==4.57.3", "sentence-transformers==5.2.0", @@ -90,7 +90,7 @@ dependencies = [ "soundfile==0.13.1", "azure-ai-documentintelligence==1.0.2", - "pillow==12.0.0", + "pillow==12.1.0", "opencv-python-headless==4.12.0.88", "rapidocr-onnxruntime==1.4.4", "rank-bm25==0.2.2", From 8d568cc8c5d460135134ed1834a12fbd9ec71c83 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 22:41:13 +0400 Subject: [PATCH 136/254] refac --- src/lib/components/icons/Glasses.svelte | 40 +++++++++++++++++++------ 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/lib/components/icons/Glasses.svelte b/src/lib/components/icons/Glasses.svelte index 939924f707..3d05cf70a2 100644 --- a/src/lib/components/icons/Glasses.svelte +++ b/src/lib/components/icons/Glasses.svelte @@ -11,13 +11,35 @@ fill="none" stroke="currentColor" viewBox="0 0 24 24" - > + + + + + + + + + + + + + + + From 8ef0f7743b99167ec16e4b6ec97e913cfced4d13 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Mon, 5 Jan 2026 23:13:05 +0400 Subject: [PATCH 137/254] refac --- backend/open_webui/utils/middleware.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 07b5a4b5ee..a6f39e15f9 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -2723,6 +2723,9 @@ async def process_chat_response( # Emit pending tool calls in real-time if response_tool_calls: + # Flush any pending text first + await flush_pending_delta_data() + pending_content_blocks = content_blocks + [ { "type": "tool_calls", From cd5a38a6942350ebf15ca7180f2eddf30c91f566 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:37:41 +0100 Subject: [PATCH 138/254] feat: Models Atomic PR of #20243 (#20369) * feat: Add read-only access support for Models - Backend: Add write_access field to ModelAccessResponse - Backend: Update /models/list to return ModelAccessListResponse - Frontend: Display Read Only badge in Models list - Frontend: Disable inputs and save button when no write access - Frontend: Hide action buttons for read-only models * fix: Handle ModelAccessListResponse format in getModels API - Backend returns {items, total} instead of {data} - Update getModels API to handle both formats for backward compatibility * fix: Show read-only shared models in workspace list - Backend: Change search_models permission from 'write' to 'read' to include shared models - Backend: Keep user_id filter to only show owned/shared models (not all public) - Frontend: Handle ModelAccessListResponse format in getModels API * fix: Align Read Only badge inline with model name * fix: Correct badge placement and fix syntax error * fix: Resolve badge truncation in Models list - Add w-full to flex container for proper spacing - Wrap Badge in div to prevent truncation - Match Knowledge.svelte badge pattern * fix: Align Read Only badge with Knowledge.svelte pattern - Match Knowledge.svelte structure for badge placement - Actions only show when write_access or admin - Remove w-full from container to prevent right-overflow * fix: Return write_access from getModelById endpoint fix: Return write_access from getModelById endpoint - Use ModelAccessResponse instead of raw dict - Remove inefficient getModels call in edit page * revert * fix * fix * fix --- backend/open_webui/models/models.py | 11 +- backend/open_webui/routers/models.py | 31 +++- src/lib/components/workspace/Models.svelte | 170 +++++++++++---------- 3 files changed, 123 insertions(+), 89 deletions(-) diff --git a/backend/open_webui/models/models.py b/backend/open_webui/models/models.py index adb82755d5..d8ac589d79 100755 --- a/backend/open_webui/models/models.py +++ b/backend/open_webui/models/models.py @@ -130,6 +130,10 @@ class ModelUserResponse(ModelModel): user: Optional[UserResponse] = None +class ModelAccessResponse(ModelUserResponse): + write_access: Optional[bool] = False + + class ModelResponse(ModelModel): pass @@ -139,6 +143,11 @@ class ModelListResponse(BaseModel): total: int +class ModelAccessListResponse(BaseModel): + items: list[ModelAccessResponse] + total: int + + class ModelForm(BaseModel): id: str base_model_id: Optional[str] = None @@ -292,7 +301,7 @@ class ModelsTable: db, query, filter, - permission="write", + permission="read", ) tag = filter.get("tag") diff --git a/backend/open_webui/routers/models.py b/backend/open_webui/routers/models.py index 4eb20f595d..a1f642bbce 100644 --- a/backend/open_webui/routers/models.py +++ b/backend/open_webui/routers/models.py @@ -11,6 +11,8 @@ from open_webui.models.models import ( ModelModel, ModelResponse, ModelListResponse, + ModelAccessListResponse, + ModelAccessResponse, Models, ) @@ -51,7 +53,7 @@ PAGE_ITEM_COUNT = 30 @router.get( - "/list", response_model=ModelListResponse + "/list", response_model=ModelAccessListResponse ) # do NOT use "/" as path, conflicts with main.py async def get_models( query: Optional[str] = None, @@ -88,7 +90,21 @@ async def get_models( filter["user_id"] = user.id - return Models.search_models(user.id, filter=filter, skip=skip, limit=limit, db=db) + result = Models.search_models(user.id, filter=filter, skip=skip, limit=limit, db=db) + return ModelAccessListResponse( + items=[ + ModelAccessResponse( + **model.model_dump(), + write_access=( + (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) + or user.id == model.user_id + or has_access(user.id, "write", model.access_control, db=db) + ), + ) + for model in result.items + ], + total=result.total, + ) ########################### @@ -290,7 +306,7 @@ class ModelIdForm(BaseModel): # Note: We're not using the typical url path param here, but instead using a query parameter to allow '/' in the id -@router.get("/model", response_model=Optional[ModelResponse]) +@router.get("/model", response_model=Optional[ModelAccessResponse]) async def get_model_by_id( id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) ): @@ -301,7 +317,14 @@ async def get_model_by_id( or model.user_id == user.id or has_access(user.id, "read", model.access_control, db=db) ): - return model + return ModelAccessResponse( + **model.model_dump(), + write_access=( + (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) + or user.id == model.user_id + or has_access(user.id, "write", model.access_control, db=db) + ), + ) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, diff --git a/src/lib/components/workspace/Models.svelte b/src/lib/components/workspace/Models.svelte index 10e8c70a81..42e0549d9b 100644 --- a/src/lib/components/workspace/Models.svelte +++ b/src/lib/components/workspace/Models.svelte @@ -44,6 +44,7 @@ import ViewSelector from './common/ViewSelector.svelte'; import TagSelector from './common/TagSelector.svelte'; import Pagination from '../common/Pagination.svelte'; + import Badge from '$lib/components/common/Badge.svelte'; let shiftKey = false; @@ -457,14 +458,10 @@
{ - if ( - $user?.role === 'admin' || - model.user_id === $user?.id || - model.access_control.write.group_ids.some((wg) => groupIds.includes(wg)) - ) { + if (model.write_access) { goto(`/workspace/models/edit?id=${encodeURIComponent(model.id)}`); } }} @@ -499,91 +496,95 @@ -
-
-
-
-
- {#if shiftKey} - - - +
+ {#if !model.write_access} +
+ +
+ {/if} - - - - {:else} - { - goto( - `/workspace/models/edit?id=${encodeURIComponent(model.id)}` - ); - }} - shareHandler={() => { - shareModelHandler(model); - }} - cloneHandler={() => { - cloneModelHandler(model); - }} - exportHandler={() => { - exportModelHandler(model); - }} - hideHandler={() => { + {#if model.write_access || $user?.role === 'admin'} +
+
+ {#if shiftKey} + +
+ {#if model?.meta?.hidden} + + {:else} + + {/if} + + + + + + + {:else} + { + goto( + `/workspace/models/edit?id=${encodeURIComponent(model.id)}` + ); + }} + shareHandler={() => { + shareModelHandler(model); + }} + cloneHandler={() => { + cloneModelHandler(model); + }} + exportHandler={() => { + exportModelHandler(model); + }} + hideHandler={() => { + hideModelHandler(model); + }} + pinModelHandler={() => { + pinModelHandler(model.id); + }} + copyLinkHandler={() => { + copyLinkHandler(model); + }} + deleteHandler={() => { + selectedModel = model; + showModelDeleteConfirm = true; + }} + onClose={() => {}} + > +
+ +
+
+ {/if}
+ {/if} + {#if model.write_access} + {/if}
From 713a65ee31c70e8c117cbb44f341a22e81a5c390 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:58:53 +0100 Subject: [PATCH 139/254] fix: inject full context knowledge into system message for KV prefix caching (#20317) * Update middleware.py * Update middleware.py * env var * address * upd --- backend/open_webui/env.py | 4 ++++ backend/open_webui/utils/middleware.py | 32 ++++++++++++++++++-------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index f5253d287b..51f62b7ff1 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -356,6 +356,10 @@ ENABLE_REALTIME_CHAT_SAVE = ( ENABLE_QUERIES_CACHE = os.environ.get("ENABLE_QUERIES_CACHE", "False").lower() == "true" +RAG_SYSTEM_CONTEXT = ( + os.environ.get("RAG_SYSTEM_CONTEXT", "False").lower() == "true" +) + #################################### # REDIS #################################### diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index a6f39e15f9..b7b7dc18bd 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -119,6 +119,7 @@ from open_webui.env import ( BYPASS_MODEL_ACCESS_CONTROL, ENABLE_REALTIME_CHAT_SAVE, ENABLE_QUERIES_CACHE, + RAG_SYSTEM_CONTEXT, ) from open_webui.constants import TASKS @@ -1622,15 +1623,28 @@ async def process_chat_payload(request, form_data, user, metadata, model): raise Exception("No user message found") if context_string != "": - form_data["messages"] = add_or_update_user_message( - rag_template( - request.app.state.config.RAG_TEMPLATE, - context_string, - prompt, - ), - form_data["messages"], - append=False, - ) + if RAG_SYSTEM_CONTEXT: + # Inject into system message for KV prefix caching + form_data["messages"] = add_or_update_system_message( + rag_template( + request.app.state.config.RAG_TEMPLATE, + context_string, + prompt, + ), + form_data["messages"], + append=True, + ) + else: + # Inject into user message + form_data["messages"] = add_or_update_user_message( + rag_template( + request.app.state.config.RAG_TEMPLATE, + context_string, + prompt, + ), + form_data["messages"], + append=False, + ) # If there are citations, add them to the data_items sources = [ From de9cff6b4ef4c2260854b02881b2a0dbda843f00 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 00:01:07 +0400 Subject: [PATCH 140/254] refac --- src/routes/(app)/workspace/models/edit/+page.svelte | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/routes/(app)/workspace/models/edit/+page.svelte b/src/routes/(app)/workspace/models/edit/+page.svelte index 1ff9652c6f..d05ff37030 100644 --- a/src/routes/(app)/workspace/models/edit/+page.svelte +++ b/src/routes/(app)/workspace/models/edit/+page.svelte @@ -25,6 +25,11 @@ if (!model) { goto('/workspace/models'); } + + if (!model?.write_access) { + toast.error($i18n.t('You do not have permission to edit this model')); + goto('/workspace/models'); + } } else { goto('/workspace/models'); } From 4cf901f519c687d9070b27cd95fd0d96cb91bc7c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 00:05:52 +0400 Subject: [PATCH 141/254] refac --- .../workspace/Prompts/PromptEditor.svelte | 26 +++++++++---------- .../(app)/workspace/prompts/edit/+page.svelte | 6 ++--- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/lib/components/workspace/Prompts/PromptEditor.svelte b/src/lib/components/workspace/Prompts/PromptEditor.svelte index 379dc6c765..39103f5527 100644 --- a/src/lib/components/workspace/Prompts/PromptEditor.svelte +++ b/src/lib/components/workspace/Prompts/PromptEditor.svelte @@ -15,7 +15,7 @@ export let edit = false; export let prompt = null; export let clone = false; - export let write_access = true; + export let disabled = true; const i18n = getContext('i18n'); @@ -41,7 +41,7 @@ } const submitHandler = async () => { - if (!write_access) { + if (disabled) { toast.error($i18n.t('You do not have permission to edit this prompt.')); return; } @@ -116,10 +116,14 @@ placeholder={$i18n.t('Title')} bind:value={title} required - disabled={!write_access} + {disabled} /> - {#if write_access} + {#if disabled} +
+ {$i18n.t('Read Only')} +
+ {:else}
- {:else} -
- {$i18n.t('Read Only')} -
{/if}
@@ -150,7 +150,7 @@ bind:value={command} on:input={handleCommandInput} required - disabled={edit || !write_access} + disabled={edit || disabled} />
@@ -170,7 +170,7 @@ bind:value={content} rows={6} required - disabled={!write_access} + readonly={disabled} />
@@ -194,13 +194,13 @@
- +
{/each} From 119fc21257853a72297788d5135d0df346b69d5e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 01:42:49 +0400 Subject: [PATCH 143/254] refac --- backend/open_webui/tools/builtin.py | 56 +++++++++++++++++++++++++---- backend/open_webui/utils/tools.py | 11 +++--- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index de97fb5ec8..83cf67cd17 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -2,6 +2,8 @@ Built-in tools for Open WebUI. These tools are automatically available when native function calling is enabled. + +IMPORTANT: DO NOT IMPORT THIS MODULE DIRECTLY IN OTHER PARTS OF THE CODEBASE. """ import json @@ -22,9 +24,11 @@ from open_webui.routers.images import ( ) from open_webui.routers.memories import ( query_memory, - add_memory, + add_memory as _add_memory, + update_memory_by_id, QueryMemoryForm, AddMemoryForm, + MemoryUpdateModel, ) from open_webui.models.notes import Notes from open_webui.models.chats import Chats @@ -297,7 +301,7 @@ async def edit_image( # ============================================================================= -async def memory_query( +async def search_memories( query: str, __request__: Request = None, __user__: dict = None, @@ -323,6 +327,9 @@ async def memory_query( if results and hasattr(results, "documents") and results.documents: memories = [] for doc_idx, doc in enumerate(results.documents[0]): + memory_id = None + if results.ids and results.ids[0]: + memory_id = results.ids[0][doc_idx] created_at = "Unknown" if results.metadatas and results.metadatas[0][doc_idx].get( "created_at" @@ -331,16 +338,16 @@ async def memory_query( "%Y-%m-%d", time.localtime(results.metadatas[0][doc_idx]["created_at"]), ) - memories.append({"date": created_at, "content": doc}) + memories.append({"id": memory_id, "date": created_at, "content": doc}) return json.dumps(memories, ensure_ascii=False) else: return json.dumps([]) except Exception as e: - log.exception(f"memory_query error: {e}") + log.exception(f"search_memories error: {e}") return json.dumps({"error": str(e)}) -async def memory_add( +async def add_memory( content: str, __request__: Request = None, __user__: dict = None, @@ -357,7 +364,7 @@ async def memory_add( try: user = UserModel(**__user__) if __user__ else None - memory = await add_memory( + memory = await _add_memory( __request__, AddMemoryForm(content=content), user, @@ -365,7 +372,42 @@ async def memory_add( return json.dumps({"status": "success", "id": memory.id}, ensure_ascii=False) except Exception as e: - log.exception(f"memory_add error: {e}") + log.exception(f"add_memory error: {e}") + return json.dumps({"error": str(e)}) + + +async def replace_memory_content( + memory_id: str, + content: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Update the content of an existing memory by its ID. + + :param memory_id: The ID of the memory to update + :param content: The new content for the memory + :return: Confirmation that the memory was updated + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + try: + user = UserModel(**__user__) if __user__ else None + + memory = await update_memory_by_id( + memory_id=memory_id, + request=__request__, + form_data=MemoryUpdateModel(content=content), + user=user, + ) + + return json.dumps( + {"status": "success", "id": memory.id, "content": memory.content}, + ensure_ascii=False, + ) + except Exception as e: + log.exception(f"replace_memory_content 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 cd27118098..8793feae3e 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -48,8 +48,9 @@ from open_webui.tools.builtin import ( fetch_url, generate_image, edit_image, - memory_query, - memory_add, + search_memories, + add_memory, + replace_memory_content, get_current_timestamp, calculate_timestamp, search_notes, @@ -359,7 +360,7 @@ def get_builtin_tools( # Add memory tools if enabled for this chat if features.get("memory"): - builtin_functions.extend([memory_query, memory_add]) + builtin_functions.extend([search_memories, add_memory, replace_memory_content]) # Add web search tools if enabled globally AND for this chat if getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) and features.get( @@ -379,7 +380,9 @@ def get_builtin_tools( # Notes tools - search, view, create, and update user's notes (if notes enabled globally) if getattr(request.app.state.config, "ENABLE_NOTES", False): - builtin_functions.extend([search_notes, view_note, write_note, replace_note_content]) + builtin_functions.extend( + [search_notes, view_note, write_note, replace_note_content] + ) # Channels tools - search channels and messages (if channels enabled globally) if getattr(request.app.state.config, "ENABLE_CHANNELS", False): From 619f2604660ad59c3ebbf8b0252de7b68e9c9c3e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 01:53:00 +0400 Subject: [PATCH 144/254] refac --- backend/open_webui/tools/builtin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 83cf67cd17..165b5b69c7 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -9,6 +9,7 @@ IMPORTANT: DO NOT IMPORT THIS MODULE DIRECTLY IN OTHER PARTS OF THE CODEBASE. import json import logging import time +import asyncio from typing import Optional from fastapi import Request @@ -190,7 +191,7 @@ async def fetch_url( return json.dumps({"error": "Request context not available"}) try: - content, _ = get_content_from_url(__request__, url) + content, _ = await asyncio.to_thread(get_content_from_url, __request__, url) # Truncate if too long (avoid overwhelming context) max_length = 50000 From 2543252bb08a4c4c0da65041330452246f5da410 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 02:00:30 +0400 Subject: [PATCH 145/254] refac --- backend/open_webui/tools/builtin.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 165b5b69c7..e5dc9f4233 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -245,6 +245,15 @@ async def generate_image( }, } ) + # Return a message indicating the image is already displayed + return json.dumps( + { + "status": "success", + "message": "The image has been successfully generated and is already visible to the user in the chat. You do not need to display or embed the image again - just acknowledge that it has been created.", + "images": images, + }, + ensure_ascii=False, + ) return json.dumps({"status": "success", "images": images}, ensure_ascii=False) except Exception as e: @@ -290,6 +299,15 @@ async def edit_image( }, } ) + # Return a message indicating the image is already displayed + return json.dumps( + { + "status": "success", + "message": "The edited image has been successfully generated and is already visible to the user in the chat. You do not need to display or embed the image again - just acknowledge that it has been created.", + "images": images, + }, + ensure_ascii=False, + ) return json.dumps({"status": "success", "images": images}, ensure_ascii=False) except Exception as e: From 5921a19519e117947db7cd79b638e96045017412 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 02:19:57 +0400 Subject: [PATCH 146/254] refac --- backend/open_webui/models/chats.py | 161 ++++++++++++++++++------- backend/open_webui/tools/builtin.py | 54 ++++++--- backend/open_webui/utils/middleware.py | 2 + backend/open_webui/utils/tools.py | 2 + 4 files changed, 160 insertions(+), 59 deletions(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index ea48044bc4..12359eec9f 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -281,7 +281,9 @@ class ChatTable: return changed - def insert_new_chat(self, user_id: str, form_data: ChatForm, db: Optional[Session] = None) -> Optional[ChatModel]: + def insert_new_chat( + self, user_id: str, form_data: ChatForm, db: Optional[Session] = None + ) -> Optional[ChatModel]: with get_db_context(db) as db: id = str(uuid.uuid4()) chat = ChatModel( @@ -332,7 +334,10 @@ class ChatTable: return chat def import_chats( - self, user_id: str, chat_import_forms: list[ChatImportForm], db: Optional[Session] = None + self, + user_id: str, + chat_import_forms: list[ChatImportForm], + db: Optional[Session] = None, ) -> list[ChatModel]: with get_db_context(db) as db: chats = [] @@ -345,7 +350,9 @@ class ChatTable: db.commit() return [ChatModel.model_validate(chat) for chat in chats] - def update_chat_by_id(self, id: str, chat: dict, db: Optional[Session] = None) -> Optional[ChatModel]: + def update_chat_by_id( + self, id: str, chat: dict, db: Optional[Session] = None + ) -> Optional[ChatModel]: try: with get_db_context(db) as db: chat_item = db.get(Chat, id) @@ -466,25 +473,28 @@ class ChatTable: def add_message_files_by_id_and_message_id( self, id: str, message_id: str, files: list[dict] ) -> list[dict]: - chat = self.get_chat_by_id(id) - if chat is None: - return None + with get_db_context() as db: + chat = self.get_chat_by_id(id, db=db) + if chat is None: + return None - chat = chat.chat - history = chat.get("history", {}) + chat = chat.chat + history = chat.get("history", {}) - message_files = [] + message_files = [] - if message_id in history.get("messages", {}): - message_files = history["messages"][message_id].get("files", []) - message_files = message_files + files - history["messages"][message_id]["files"] = message_files + if message_id in history.get("messages", {}): + message_files = history["messages"][message_id].get("files", []) + message_files = message_files + files + history["messages"][message_id]["files"] = message_files - chat["history"] = history - self.update_chat_by_id(id, chat) - return message_files + chat["history"] = history + self.update_chat_by_id(id, chat, db=db) + return message_files - def insert_shared_chat_by_chat_id(self, chat_id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + def insert_shared_chat_by_chat_id( + self, chat_id: str, db: Optional[Session] = None + ) -> Optional[ChatModel]: with get_db_context(db) as db: # Get the existing chat to share chat = db.get(Chat, chat_id) @@ -522,7 +532,9 @@ class ChatTable: db.commit() return shared_chat if (shared_result and result) else None - def update_shared_chat_by_chat_id(self, chat_id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + def update_shared_chat_by_chat_id( + self, chat_id: str, db: Optional[Session] = None + ) -> Optional[ChatModel]: try: with get_db_context(db) as db: chat = db.get(Chat, chat_id) @@ -546,7 +558,9 @@ class ChatTable: except Exception: return None - def delete_shared_chat_by_chat_id(self, chat_id: str, db: Optional[Session] = None) -> bool: + def delete_shared_chat_by_chat_id( + self, chat_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(Chat).filter_by(user_id=f"shared-{chat_id}").delete() @@ -556,7 +570,9 @@ class ChatTable: except Exception: return False - def unarchive_all_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + def unarchive_all_chats_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(Chat).filter_by(user_id=user_id).update({"archived": False}) @@ -578,7 +594,9 @@ class ChatTable: except Exception: return None - def toggle_chat_pinned_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + def toggle_chat_pinned_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ChatModel]: try: with get_db_context(db) as db: chat = db.get(Chat, id) @@ -590,7 +608,9 @@ class ChatTable: except Exception: return None - def toggle_chat_archive_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + def toggle_chat_archive_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ChatModel]: try: with get_db_context(db) as db: chat = db.get(Chat, id) @@ -603,7 +623,9 @@ class ChatTable: except Exception: return None - def archive_all_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + def archive_all_chats_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(Chat).filter_by(user_id=user_id).update({"archived": True}) @@ -740,7 +762,11 @@ class ChatTable: ] def get_chat_list_by_chat_ids( - self, chat_ids: list[str], skip: int = 0, limit: int = 50, db: Optional[Session] = None + self, + chat_ids: list[str], + skip: int = 0, + limit: int = 50, + db: Optional[Session] = None, ) -> list[ChatModel]: with get_db_context(db) as db: all_chats = ( @@ -752,7 +778,9 @@ class ChatTable: ) return [ChatModel.model_validate(chat) for chat in all_chats] - def get_chat_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + def get_chat_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ChatModel]: try: with get_db_context(db) as db: chat_item = db.get(Chat, id) @@ -767,7 +795,9 @@ class ChatTable: except Exception: return None - def get_chat_by_share_id(self, id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + def get_chat_by_share_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ChatModel]: try: with get_db_context(db) as db: # it is possible that the shared link was deleted. hence, @@ -781,7 +811,9 @@ class ChatTable: except Exception: return None - def get_chat_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> Optional[ChatModel]: + def get_chat_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> Optional[ChatModel]: try: with get_db_context(db) as db: chat = db.query(Chat).filter_by(id=id, user_id=user_id).first() @@ -789,7 +821,9 @@ class ChatTable: except Exception: return None - def get_chats(self, skip: int = 0, limit: int = 50, db: Optional[Session] = None) -> list[ChatModel]: + def get_chats( + self, skip: int = 0, limit: int = 50, db: Optional[Session] = None + ) -> list[ChatModel]: with get_db_context(db) as db: all_chats = ( db.query(Chat) @@ -844,7 +878,9 @@ class ChatTable: } ) - def get_pinned_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[ChatModel]: + def get_pinned_chats_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[ChatModel]: with get_db_context(db) as db: all_chats = ( db.query(Chat) @@ -853,7 +889,9 @@ class ChatTable: ) return [ChatModel.model_validate(chat) for chat in all_chats] - def get_archived_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[ChatModel]: + def get_archived_chats_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[ChatModel]: with get_db_context(db) as db: all_chats = ( db.query(Chat) @@ -1074,7 +1112,12 @@ class ChatTable: return [ChatModel.model_validate(chat) for chat in all_chats] def get_chats_by_folder_id_and_user_id( - self, folder_id: str, user_id: str, skip: int = 0, limit: int = 60, db: Optional[Session] = None + self, + folder_id: str, + user_id: str, + skip: int = 0, + limit: int = 60, + db: Optional[Session] = None, ) -> list[ChatModel]: with get_db_context(db) as db: query = db.query(Chat).filter_by(folder_id=folder_id, user_id=user_id) @@ -1121,14 +1164,21 @@ class ChatTable: except Exception: return None - def get_chat_tags_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> list[TagModel]: + def get_chat_tags_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> list[TagModel]: with get_db_context(db) as db: chat = db.get(Chat, id) tags = chat.meta.get("tags", []) return [Tags.get_tag_by_name_and_user_id(tag, user_id) for tag in tags] def get_chat_list_by_user_id_and_tag_name( - self, user_id: str, tag_name: str, skip: int = 0, limit: int = 50, db: Optional[Session] = None + self, + user_id: str, + tag_name: str, + skip: int = 0, + limit: int = 50, + db: Optional[Session] = None, ) -> list[ChatModel]: with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id) @@ -1181,7 +1231,9 @@ class ChatTable: except Exception: return None - def count_chats_by_tag_name_and_user_id(self, tag_name: str, user_id: str, db: Optional[Session] = None) -> int: + def count_chats_by_tag_name_and_user_id( + self, tag_name: str, user_id: str, db: Optional[Session] = None + ) -> int: with get_db_context(db) as db: # Assuming `get_db()` returns a session object query = db.query(Chat).filter_by(user_id=user_id, archived=False) @@ -1217,7 +1269,9 @@ class ChatTable: return count - def count_chats_by_folder_id_and_user_id(self, folder_id: str, user_id: str, db: Optional[Session] = None) -> int: + def count_chats_by_folder_id_and_user_id( + self, folder_id: str, user_id: str, db: Optional[Session] = None + ) -> int: with get_db_context(db) as db: query = db.query(Chat).filter_by(user_id=user_id) @@ -1246,7 +1300,9 @@ class ChatTable: except Exception: return False - def delete_all_tags_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: + def delete_all_tags_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: chat = db.get(Chat, id) @@ -1270,7 +1326,9 @@ class ChatTable: except Exception: return False - def delete_chat_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: + def delete_chat_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(Chat).filter_by(id=id, user_id=user_id).delete() @@ -1280,7 +1338,9 @@ class ChatTable: except Exception: return False - def delete_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + def delete_chats_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: self.delete_shared_chats_by_user_id(user_id, db=db) @@ -1305,7 +1365,11 @@ class ChatTable: return False def move_chats_by_user_id_and_folder_id( - self, user_id: str, folder_id: str, new_folder_id: Optional[str], db: Optional[Session] = None + self, + user_id: str, + folder_id: str, + new_folder_id: Optional[str], + db: Optional[Session] = None, ) -> bool: try: with get_db_context(db) as db: @@ -1318,7 +1382,9 @@ class ChatTable: except Exception: return False - def delete_shared_chats_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + def delete_shared_chats_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: chats_by_user = db.query(Chat).filter_by(user_id=user_id).all() @@ -1332,7 +1398,12 @@ class ChatTable: return False def insert_chat_files( - self, chat_id: str, message_id: str, file_ids: list[str], user_id: str, db: Optional[Session] = None + self, + chat_id: str, + message_id: str, + file_ids: list[str], + user_id: str, + db: Optional[Session] = None, ) -> Optional[list[ChatFileModel]]: if not file_ids: return None @@ -1398,7 +1469,9 @@ class ChatTable: ChatFileModel.model_validate(chat_file) for chat_file in all_chat_files ] - def delete_chat_file(self, chat_id: str, file_id: str, db: Optional[Session] = None) -> bool: + def delete_chat_file( + self, chat_id: str, file_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(ChatFile).filter_by(chat_id=chat_id, file_id=file_id).delete() @@ -1407,7 +1480,9 @@ class ChatTable: except Exception: return False - def get_shared_chats_by_file_id(self, file_id: str, db: Optional[Session] = None) -> list[ChatModel]: + def get_shared_chats_by_file_id( + self, file_id: str, db: Optional[Session] = None + ) -> list[ChatModel]: with get_db_context(db) as db: # Join Chat and ChatFile tables to get shared chats associated with the file_id all_chats = ( diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index e5dc9f4233..11069ae014 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -214,6 +214,8 @@ async def generate_image( __request__: Request = None, __user__: dict = None, __event_emitter__: callable = None, + __chat_id__: str = None, + __message_id__: str = None, ) -> str: """ Generate an image based on a text prompt. @@ -233,15 +235,24 @@ async def generate_image( user=user, ) + # Prepare file entries for the images + image_files = [{"type": "image", "url": img["url"]} for img in images] + + # Persist files to DB if chat context is available + if __chat_id__ and __message_id__ and images: + image_files = Chats.add_message_files_by_id_and_message_id( + __chat_id__, + __message_id__, + image_files, + ) + # Emit the images to the UI if event emitter is available - if __event_emitter__ and images: + if __event_emitter__ and image_files: await __event_emitter__( { - "type": "files", + "type": "chat:message:files", "data": { - "files": [ - {"type": "image", "url": img["url"]} for img in images - ] + "files": image_files, }, } ) @@ -263,17 +274,19 @@ async def generate_image( async def edit_image( prompt: str, - image_url: str, + image_urls: list[str], __request__: Request = None, __user__: dict = None, __event_emitter__: callable = None, + __chat_id__: str = None, + __message_id__: str = None, ) -> str: """ - Edit an existing image based on a text prompt. + Edit existing images based on a text prompt. - :param prompt: A description of the changes to make to the image - :param image_url: The URL of the image to edit - :return: Confirmation that the image was edited, or an error message + :param prompt: A description of the changes to make to the images + :param image_urls: A list of URLs of the images to edit + :return: Confirmation that the images were edited, or an error message """ if __request__ is None: return json.dumps({"error": "Request context not available"}) @@ -283,19 +296,28 @@ async def edit_image( images = await image_edits( request=__request__, - form_data=EditImageForm(prompt=prompt, image=image_url), + form_data=EditImageForm(prompt=prompt, image=image_urls), user=user, ) + # Prepare file entries for the images + image_files = [{"type": "image", "url": img["url"]} for img in images] + + # Persist files to DB if chat context is available + if __chat_id__ and __message_id__ and images: + image_files = Chats.add_message_files_by_id_and_message_id( + __chat_id__, + __message_id__, + image_files, + ) + # Emit the images to the UI if event emitter is available - if __event_emitter__ and images: + if __event_emitter__ and image_files: await __event_emitter__( { - "type": "files", + "type": "chat:message:files", "data": { - "files": [ - {"type": "image", "url": img["url"]} for img in images - ] + "files": image_files, }, } ) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index b7b7dc18bd..c379467fca 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1198,6 +1198,8 @@ async def process_chat_payload(request, form_data, user, metadata, model): "__oauth_token__": oauth_token, "__request__": request, "__model__": model, + "__chat_id__": metadata.get("chat_id"), + "__message_id__": metadata.get("message_id"), } # Initialize events to store additional event to be sent to the client # Initialize contexts and citation diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 8793feae3e..4027a0a831 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -402,6 +402,8 @@ def get_builtin_tools( "__request__": request, "__user__": extra_params.get("__user__", {}), "__event_emitter__": extra_params.get("__event_emitter__"), + "__chat_id__": extra_params.get("__chat_id__"), + "__message_id__": extra_params.get("__message_id__"), }, ) From c87031e9a6ee7ceb9c65f5571795d02a0420fd40 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 6 Jan 2026 00:00:48 +0100 Subject: [PATCH 147/254] feat: Tools Atomic PR of #20243 (#20370) * feat: Add read-only access support for Tools - Backend: Add write_access field to ToolAccessResponse - Backend: Update /tools/list to return tools with write_access - Frontend: Display Read Only badge in Tools list - Frontend: Disable inputs and save button when no write access - Frontend: Add readOnly prop to CodeEditor component * Update Tools.svelte * fix: Return write_access from getToolById endpoint fix: Return write_access from getToolById endpoint - Use ToolAccessResponse instead of raw dict - Remove inefficient getToolList call in edit page * refactor: Rename write_access to disabled in ToolkitEditor - Rename prop from write_access to disabled - Invert logic where needed - Update edit page to pass disabled instead of write_access * rem * Update +page.svelte * fix * Update ToolkitEditor.svelte * Update CodeEditor.svelte * Update ToolkitEditor.svelte --- backend/open_webui/models/tools.py | 4 + backend/open_webui/routers/tools.py | 29 ++++-- src/lib/components/workspace/Tools.svelte | 105 +++++++++++++++------- 3 files changed, 102 insertions(+), 36 deletions(-) diff --git a/backend/open_webui/models/tools.py b/backend/open_webui/models/tools.py index cbd17cf5a7..ab62c658c3 100644 --- a/backend/open_webui/models/tools.py +++ b/backend/open_webui/models/tools.py @@ -97,6 +97,10 @@ class ToolUserResponse(ToolResponse): model_config = ConfigDict(extra="allow") +class ToolAccessResponse(ToolUserResponse): + write_access: Optional[bool] = False + + class ToolForm(BaseModel): id: str name: str diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index fd99b15815..d919debc38 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -17,6 +17,7 @@ from open_webui.models.tools import ( ToolModel, ToolResponse, ToolUserResponse, + ToolAccessResponse, Tools, ) from open_webui.utils.plugin import ( @@ -157,13 +158,24 @@ async def get_tools(request: Request, user=Depends(get_verified_user), db: Sessi ############################ -@router.get("/list", response_model=list[ToolUserResponse]) +@router.get("/list", response_model=list[ToolAccessResponse]) async def get_tool_list(user=Depends(get_verified_user), db: Session = Depends(get_session)): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: tools = Tools.get_tools(db=db) else: - tools = Tools.get_tools_by_user_id(user.id, "write", db=db) - return tools + tools = Tools.get_tools_by_user_id(user.id, "read", db=db) + + return [ + ToolAccessResponse( + **tool.model_dump(), + write_access=( + (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) + or user.id == tool.user_id + or has_access(user.id, "write", tool.access_control, db=db) + ), + ) + for tool in tools + ] ############################ @@ -338,7 +350,7 @@ async def create_new_tools( ############################ -@router.get("/id/{id}", response_model=Optional[ToolModel]) +@router.get("/id/{id}", response_model=Optional[ToolAccessResponse]) async def get_tools_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): tools = Tools.get_tool_by_id(id, db=db) @@ -348,7 +360,14 @@ async def get_tools_by_id(id: str, user=Depends(get_verified_user), db: Session or tools.user_id == user.id or has_access(user.id, "read", tools.access_control, db=db) ): - return tools + return ToolAccessResponse( + **tools.model_dump(), + write_access=( + (user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL) + or user.id == tools.user_id + or has_access(user.id, "write", tools.access_control, db=db) + ), + ) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, diff --git a/src/lib/components/workspace/Tools.svelte b/src/lib/components/workspace/Tools.svelte index 865c1f56cb..d179896936 100644 --- a/src/lib/components/workspace/Tools.svelte +++ b/src/lib/components/workspace/Tools.svelte @@ -37,6 +37,7 @@ import AddToolMenu from './Tools/AddToolMenu.svelte'; import ImportModal from '../ImportModal.svelte'; import ViewSelector from './common/ViewSelector.svelte'; + import Badge from '$lib/components/common/Badge.svelte'; let shiftKey = false; let loaded = false; @@ -357,45 +358,86 @@ {#each filteredItems as tool}
- -
-
- -
-
- {tool.name} -
- {#if tool?.meta?.manifest?.version} -
- v{tool?.meta?.manifest?.version ?? ''} + {#if tool.write_access} + +
+
+ +
+
+ {tool.name}
- {/if} + {#if tool?.meta?.manifest?.version} +
+ v{tool?.meta?.manifest?.version ?? ''} +
+ {/if} +
+
+
+
+ + {$i18n.t('By {{name}}', { + name: capitalizeFirstLetter( + tool?.user?.name ?? tool?.user?.email ?? $i18n.t('Deleted User') + ) + })} + +
- - -
-
- - {$i18n.t('By {{name}}', { - name: capitalizeFirstLetter( - tool?.user?.name ?? tool?.user?.email ?? $i18n.t('Deleted User') - ) - })} +
+
+
+ {:else} +
+
+
+
+ +
+
+ {tool.name} +
+ {#if tool?.meta?.manifest?.version} +
+ v{tool?.meta?.manifest?.version ?? ''} +
+ {/if} +
+ +
+
+
+ + {$i18n.t('By {{name}}', { + name: capitalizeFirstLetter( + tool?.user?.name ?? tool?.user?.email ?? $i18n.t('Deleted User') + ) + })} + +
- + {/if} + {#if tool.write_access}
{#if shiftKey} @@ -484,6 +526,7 @@ {/if}
+ {/if}
{/each} From 1cfbb823ec512b84e6700af2a22a558bf740277b Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 03:04:09 +0400 Subject: [PATCH 148/254] chore: lock sync --- package-lock.json | 88 ++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 46 deletions(-) diff --git a/package-lock.json b/package-lock.json index 173ddec721..4aeae8b4a2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,7 @@ "i18next-resources-to-backend": "^1.2.0", "idb": "^7.1.1", "js-sha256": "^0.10.1", - "jspdf": "^3.0.0", + "jspdf": "^4.0.0", "katex": "^0.16.22", "kokoro-js": "^1.1.1", "leaflet": "^1.9.4", @@ -129,7 +129,7 @@ "tailwindcss": "^4.0.0", "tslib": "^2.4.1", "typescript": "^5.5.4", - "vite": "^5.4.14", + "vite": "^5.4.21", "vitest": "^1.6.1" }, "engines": { @@ -218,13 +218,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } @@ -4219,6 +4216,12 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/pako": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz", + "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==", + "license": "MIT" + }, "node_modules/@types/raf": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", @@ -4901,18 +4904,6 @@ "node": ">= 4.0.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -5184,18 +5175,6 @@ "node": "10.* || >= 12.*" } }, - "node_modules/btoa": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", - "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", - "license": "(MIT OR Apache-2.0)", - "bin": { - "btoa": "bin/btoa.js" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/buffer": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", @@ -7650,6 +7629,23 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-png": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz", + "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==", + "license": "MIT", + "dependencies": { + "@types/pako": "^2.0.3", + "iobuffer": "^5.3.2", + "pako": "^2.1.0" + } + }, + "node_modules/fast-png/node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -8650,6 +8646,12 @@ "node": ">=12" } }, + "node_modules/iobuffer": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz", + "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==", + "license": "MIT" + }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -9015,14 +9017,13 @@ } }, "node_modules/jspdf": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.1.tgz", - "integrity": "sha512-qaGIxqxetdoNnFQQXxTKUD9/Z7AloLaw94fFsOiJMxbfYdBbrBuhWmbzI8TVjrw7s3jBY1PFHofBKMV/wZPapg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-4.0.0.tgz", + "integrity": "sha512-w12U97Z6edKd2tXDn3LzTLg7C7QLJlx0BPfM3ecjK2BckUl9/81vZ+r5gK4/3KQdhAcEZhENUxRhtgYBj75MqQ==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.26.7", - "atob": "^2.1.2", - "btoa": "^1.2.1", + "@babel/runtime": "^7.28.4", + "fast-png": "^6.2.0", "fflate": "^0.8.1" }, "optionalDependencies": { @@ -11383,11 +11384,6 @@ "node": ">=8.10.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, "node_modules/remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -13762,9 +13758,9 @@ } }, "node_modules/vite": { - "version": "5.4.19", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", - "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", "license": "MIT", "dependencies": { "esbuild": "^0.21.3", From 927a765641a4020d4e697c91d8818beb354c69d5 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 03:24:08 +0400 Subject: [PATCH 149/254] refac --- backend/open_webui/routers/images.py | 24 ++++++++++++++++++------ backend/open_webui/utils/middleware.py | 2 ++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/backend/open_webui/routers/images.py b/backend/open_webui/routers/images.py index 7f1b0b9bde..d454e73366 100644 --- a/backend/open_webui/routers/images.py +++ b/backend/open_webui/routers/images.py @@ -707,7 +707,10 @@ async def image_generations( "n": form_data.n, } - if request.app.state.config.IMAGE_STEPS is not None or form_data.steps is not None: + if ( + request.app.state.config.IMAGE_STEPS is not None + or form_data.steps is not None + ): data["steps"] = ( form_data.steps if form_data.steps is not None @@ -770,7 +773,10 @@ async def image_generations( "height": height, } - if request.app.state.config.IMAGE_STEPS is not None or form_data.steps is not None: + if ( + request.app.state.config.IMAGE_STEPS is not None + or form_data.steps is not None + ): data["steps"] = ( form_data.steps if form_data.steps is not None @@ -856,6 +862,9 @@ async def image_edits( try: async def load_url_image(data): + if data.startswith("data:"): + return data + if data.startswith("http://") or data.startswith("https://"): r = await asyncio.to_thread(requests.get, data) r.raise_for_status() @@ -863,10 +872,14 @@ async def image_edits( image_data = base64.b64encode(r.content).decode("utf-8") return f"data:{r.headers['content-type']};base64,{image_data}" - elif data.startswith("/api/v1/files"): - file_id = data.split("/api/v1/files/")[1].split("/content")[0] - file_response = await get_file_content_by_id(file_id, user) + else: + file_id = None + if data.startswith("/api/v1/files"): + file_id = data.split("/api/v1/files/")[1].split("/content")[0] + else: + file_id = data + file_response = await get_file_content_by_id(file_id, user) if isinstance(file_response, FileResponse): file_path = file_response.path @@ -876,7 +889,6 @@ async def image_edits( mime_type, _ = mimetypes.guess_type(file_path) return f"data:{mime_type};base64,{image_data}" - return data # Load image(s) from URL(s) if necessary diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index c379467fca..412c33842a 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -726,6 +726,8 @@ def get_images_from_messages(message_list): for file in message.get("files", []): if file.get("type") == "image": message_images.append(file.get("url")) + elif file.get("content_type", "").startswith("image/"): + message_images.append(file.get("url")) if message_images: images.append(message_images) From 1148d1c927d096e14917b6d762789fca3188f281 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 03:25:39 +0400 Subject: [PATCH 150/254] fix/refac: images --- src/lib/components/chat/Chat.svelte | 2 +- src/lib/components/chat/Messages/ResponseMessage.svelte | 2 +- src/lib/components/chat/Messages/UserMessage.svelte | 2 +- src/lib/components/common/Collapsible.svelte | 2 +- src/lib/components/notes/NoteEditor.svelte | 8 +++++--- src/lib/components/notes/NoteEditor/Controls.svelte | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 011afca87b..1177100234 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -1734,7 +1734,7 @@ // Skip this check if image generation is enabled, as images may be for editing or are generated outputs in the history const hasImages = createMessagesList(_history, parentId).some((message) => message.files?.some( - (file) => file.type === 'image' || file?.content_type?.startsWith('image/') + (file) => file.type === 'image' || (file?.content_type ?? '').startsWith('image/') ) ); diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index 7c22735606..d2056554dc 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -649,7 +649,7 @@ > {#each message.files as file}
- {#if file.type === 'image'} + {#if file.type === 'image' || (file?.content_type ?? '').startsWith('image/')} {:else} 0}
{#each editedFiles as file, fileIdx} - {#if file.type === 'image'} + {#if file.type === 'image' || (file?.content_type ?? '').startsWith('image/')}
{/if} {:else if typeof file === 'object'} - {#if file.type === 'image' && file.url} + {#if (file.type === 'image' || (file?.content_type ?? '').startsWith('image/')) && file.url} { loading = true; @@ -157,7 +159,7 @@ messages = []; - if (res) { + if (res) { note = res; files = res.data.files || []; @@ -780,7 +782,7 @@ Provide the enhanced notes in markdown format. Use markdown syntax for headings, await tick(); for (const file of files) { - if (file.type === 'image') { + if (file.type === 'image' || (file?.content_type ?? '').startsWith('image/')) { const e = new CustomEvent('data', { files: files }); const img = document.getElementById(`image:${file.id}`); diff --git a/src/lib/components/notes/NoteEditor/Controls.svelte b/src/lib/components/notes/NoteEditor/Controls.svelte index 675056ee41..3d80425f76 100644 --- a/src/lib/components/notes/NoteEditor/Controls.svelte +++ b/src/lib/components/notes/NoteEditor/Controls.svelte @@ -68,7 +68,7 @@ {/each}
- {#each files.filter((file) => file.type === 'image') as file, fileIdx} + {#each files.filter((file) => file.type === 'image' || (file?.content_type ?? '').startsWith('image/')) as file, fileIdx} Date: Tue, 6 Jan 2026 15:45:11 +0100 Subject: [PATCH 151/254] fix: explicit casting client errors with some datatypes in websearch settings (#20422) --- .../admin/Settings/WebSearch.svelte | 49 ++++++++++++++++--- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/src/lib/components/admin/Settings/WebSearch.svelte b/src/lib/components/admin/Settings/WebSearch.svelte index 68a343e5f6..b70af70bda 100644 --- a/src/lib/components/admin/Settings/WebSearch.svelte +++ b/src/lib/components/admin/Settings/WebSearch.svelte @@ -43,29 +43,42 @@ const submitHandler = async () => { // Convert domain filter string to array before sending - if (webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST) { + if (typeof webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST === 'string' && webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST) { webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST = webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST.split(',') .map((domain) => domain.trim()) .filter((domain) => domain.length > 0); - } else { + } else if (!Array.isArray(webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST)) { webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST = []; } // Convert Youtube loader language string to array before sending - if (webConfig.YOUTUBE_LOADER_LANGUAGE) { + if (typeof webConfig.YOUTUBE_LOADER_LANGUAGE === 'string' && webConfig.YOUTUBE_LOADER_LANGUAGE) { webConfig.YOUTUBE_LOADER_LANGUAGE = webConfig.YOUTUBE_LOADER_LANGUAGE.split(',') .map((lang) => lang.trim()) .filter((lang) => lang.length > 0); - } else { + } else if (!Array.isArray(webConfig.YOUTUBE_LOADER_LANGUAGE)) { webConfig.YOUTUBE_LOADER_LANGUAGE = []; } + // Convert numeric timeout values to strings (backend expects strings) + if (typeof webConfig.FIRECRAWL_TIMEOUT === 'number') { + webConfig.FIRECRAWL_TIMEOUT = webConfig.FIRECRAWL_TIMEOUT.toString(); + } + if (typeof webConfig.PLAYWRIGHT_TIMEOUT === 'number') { + webConfig.PLAYWRIGHT_TIMEOUT = webConfig.PLAYWRIGHT_TIMEOUT.toString(); + } + const res = await updateRAGConfig(localStorage.token, { web: webConfig }); - webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST = webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST.join(','); - webConfig.YOUTUBE_LOADER_LANGUAGE = webConfig.YOUTUBE_LOADER_LANGUAGE.join(','); + // Convert arrays back to strings for display + if (Array.isArray(webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST)) { + webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST = webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST.join(','); + } + if (Array.isArray(webConfig.YOUTUBE_LOADER_LANGUAGE)) { + webConfig.YOUTUBE_LOADER_LANGUAGE = webConfig.YOUTUBE_LOADER_LANGUAGE.join(','); + } }; onMount(async () => { @@ -75,11 +88,31 @@ webConfig = res.web; // Convert array back to comma-separated string for display - if (webConfig?.WEB_SEARCH_DOMAIN_FILTER_LIST) { + if (Array.isArray(webConfig?.WEB_SEARCH_DOMAIN_FILTER_LIST)) { webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST = webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST.join(','); + } else if (!webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST) { + webConfig.WEB_SEARCH_DOMAIN_FILTER_LIST = ''; } - webConfig.YOUTUBE_LOADER_LANGUAGE = webConfig.YOUTUBE_LOADER_LANGUAGE.join(','); + if (Array.isArray(webConfig?.YOUTUBE_LOADER_LANGUAGE)) { + webConfig.YOUTUBE_LOADER_LANGUAGE = webConfig.YOUTUBE_LOADER_LANGUAGE.join(','); + } else if (!webConfig.YOUTUBE_LOADER_LANGUAGE) { + webConfig.YOUTUBE_LOADER_LANGUAGE = ''; + } + + // Convert timeout strings to numbers for number input fields + if (webConfig.FIRECRAWL_TIMEOUT && typeof webConfig.FIRECRAWL_TIMEOUT === 'string') { + const parsed = parseInt(webConfig.FIRECRAWL_TIMEOUT); + if (!isNaN(parsed)) { + webConfig.FIRECRAWL_TIMEOUT = parsed; + } + } + if (webConfig.PLAYWRIGHT_TIMEOUT && typeof webConfig.PLAYWRIGHT_TIMEOUT === 'string') { + const parsed = parseInt(webConfig.PLAYWRIGHT_TIMEOUT); + if (!isNaN(parsed)) { + webConfig.PLAYWRIGHT_TIMEOUT = parsed; + } + } } }); From 17490381f5e4d68da2cd480c5a48732df57b96d7 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Tue, 6 Jan 2026 19:11:56 +0400 Subject: [PATCH 152/254] refac --- src/lib/components/chat/Chat.svelte | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 1177100234..ff41dfe472 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -913,6 +913,8 @@ .filter((m) => !(m?.info?.meta?.hidden ?? false)) .map((m) => m.id); + const defaultModels = $config?.default_models ? $config?.default_models.split(',') : []; + if ($page.url.searchParams.get('models') || $page.url.searchParams.get('model')) { const urlModels = ( $page.url.searchParams.get('models') || @@ -921,8 +923,8 @@ )?.split(','); if (urlModels.length === 1) { - const m = $models.find((m) => m.id === urlModels[0]); - if (!m) { + if (!$models.find((m) => m.id === urlModels[0])) { + // Model not found; open model selector and prefill const modelSelectorButton = document.getElementById('model-selector-0-button'); if (modelSelectorButton) { modelSelectorButton.click(); @@ -936,37 +938,51 @@ } } } else { + // Model found; set it as selected selectedModels = urlModels; } } else { + // Multiple models; set as selected selectedModels = urlModels; } + // Unavailable models filtering selectedModels = selectedModels.filter((modelId) => $models.map((m) => m.id).includes(modelId) ); } else { if ($selectedFolder?.data?.model_ids) { + // Set from folder model IDs selectedModels = $selectedFolder?.data?.model_ids; } else { if (sessionStorage.selectedModels) { + // Set from session storage (temporary selection) selectedModels = JSON.parse(sessionStorage.selectedModels); sessionStorage.removeItem('selectedModels'); } else { if ($settings?.models) { + // Set from user settings selectedModels = $settings?.models; - } else if ($config?.default_models) { - console.log($config?.default_models.split(',') ?? ''); - selectedModels = $config?.default_models.split(','); + } else if (defaultModels && defaultModels.length > 0) { + // Set from default models + selectedModels = defaultModels; } } } + // Unavailable & hidden models filtering selectedModels = selectedModels.filter((modelId) => availableModels.includes(modelId)); } + // Ensure at least one model is selected if (selectedModels.length === 0 || (selectedModels.length === 1 && selectedModels[0] === '')) { if (availableModels.length > 0) { + if (defaultModels && defaultModels.length > 0) { + // Set from default models + selectedModels = defaultModels.filter((modelId) => availableModels.includes(modelId)); + } + + // Set to first available model selectedModels = [availableModels?.at(0) ?? '']; } else { selectedModels = ['']; From cc046695e658e5a870ba0919892cb12eb80cad21 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 6 Jan 2026 17:23:46 +0100 Subject: [PATCH 153/254] feat: add interface user permission (#20424) * feat: add interface user permission Adds admin configurable user / group permissions for the interface settings section * rename --- backend/open_webui/config.py | 8 ++++++ backend/open_webui/routers/users.py | 8 ++++++ .../admin/Users/Groups/EditGroupModal.svelte | 3 ++ .../admin/Users/Groups/Permissions.svelte | 28 ++++++++++++++++++- src/lib/components/chat/SettingsModal.svelte | 4 +++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index b56ad0552f..680ecbb861 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1471,6 +1471,11 @@ USER_PERMISSIONS_FEATURES_API_KEYS = ( ) +USER_PERMISSIONS_SETTINGS_INTERFACE = ( + os.environ.get("USER_PERMISSIONS_SETTINGS_INTERFACE", "True").lower() == "true" +) + + DEFAULT_USER_PERMISSIONS = { "workspace": { "models": USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS, @@ -1529,6 +1534,9 @@ DEFAULT_USER_PERMISSIONS = { "image_generation": USER_PERMISSIONS_FEATURES_IMAGE_GENERATION, "code_interpreter": USER_PERMISSIONS_FEATURES_CODE_INTERPRETER, }, + "settings": { + "interface": USER_PERMISSIONS_SETTINGS_INTERFACE, + }, } USER_PERMISSIONS = PersistentConfig( diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 4257995f62..f1758f26ac 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -227,11 +227,16 @@ class FeaturesPermissions(BaseModel): code_interpreter: bool = True +class SettingsPermissions(BaseModel): + interface: bool = True + + class UserPermissions(BaseModel): workspace: WorkspacePermissions sharing: SharingPermissions chat: ChatPermissions features: FeaturesPermissions + settings: SettingsPermissions @router.get("/default/permissions", response_model=UserPermissions) @@ -249,6 +254,9 @@ async def get_default_user_permissions(request: Request, user=Depends(get_admin_ "features": FeaturesPermissions( **request.app.state.config.USER_PERMISSIONS.get("features", {}) ), + "settings": SettingsPermissions( + **request.app.state.config.USER_PERMISSIONS.get("settings", {}) + ), } diff --git a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte index c0896a17b9..daf056d598 100644 --- a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte +++ b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte @@ -91,6 +91,9 @@ web_search: true, image_generation: true, code_interpreter: true + }, + settings: { + interface: true } }; diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index 58c3547d33..db73ca3bee 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -61,6 +61,9 @@ web_search: true, image_generation: true, code_interpreter: true + }, + settings: { + interface: true } }; @@ -79,7 +82,8 @@ workspace: { ...defaults.workspace, ...obj.workspace }, sharing: { ...defaults.sharing, ...obj.sharing }, chat: { ...defaults.chat, ...obj.chat }, - features: { ...defaults.features, ...obj.features } + features: { ...defaults.features, ...obj.features }, + settings: { ...defaults.settings, ...obj.settings } }; } @@ -839,4 +843,26 @@ {/if}
+ +
+ +
+
{$i18n.t('Settings Permissions')}
+ +
+
+
+ {$i18n.t('Interface Settings Access')} +
+ +
+ {#if defaultPermissions?.settings?.interface && !permissions.settings.interface} +
+
+ {$i18n.t('This is a default user permission and will remain enabled.')} +
+
+ {/if} +
+
diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index 6e7825ba3f..9c601ca916 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -487,6 +487,10 @@ ); } + if (tab.id === 'interface') { + return $user?.role === 'admin' || ($user?.permissions?.settings?.interface ?? true); + } + return true; }); }; From 72698a0465f58176fb163fccef0e289991e94e59 Mon Sep 17 00:00:00 2001 From: BLACKTHOMAS <46499476+BLACKTHOMAS@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:20:06 +0100 Subject: [PATCH 154/254] i18n: Comprehensive improvements to Polish (pl-PL) translation (#20425) * Updated pl-PL lang * Updated pl-PL * polish translation reverted * updated polish translation * updated polish translation * Updated translation --------- Co-authored-by: Tim Baek Co-authored-by: joaoback <156559121+joaoback@users.noreply.github.com> --- src/lib/i18n/locales/pl-PL/translation.json | 2614 +++++++++---------- 1 file changed, 1307 insertions(+), 1307 deletions(-) diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index e65797afac..21a909c893 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -1,66 +1,66 @@ { - "-1 for no limit, or a positive integer for a specific limit": "-1 oznacza brak limitu, lub dodatnia liczba całkowita dla konkretnego limitu", + "-1 for no limit, or a positive integer for a specific limit": "-1 oznacza brak limitu lub dodatnia liczba całkowita dla konkretnego limitu", "'s', 'm', 'h', 'd', 'w' or '-1' for no expiration.": "'s', 'm', 'h', 'd', 'w' lub '-1' dla braku wygaśnięcia.", - "(e.g. `sh webui.sh --api --api-auth username_password`)": "(np. `sh webui.sh --api --api-auth username_password`)>", + "(e.g. `sh webui.sh --api --api-auth username_password`)": "(np. `sh webui.sh --api --api-auth username_password`)", "(e.g. `sh webui.sh --api`)": "(np. `sh webui.sh --api`)", "(latest)": "(najnowszy)", - "(leave blank for to use commercial endpoint)": "", - "[Last] dddd [at] h:mm A": "", - "[Today at] h:mm A": "[Dziś o] h:mm A", - "[Yesterday at] h:mm A": "[Wczoraj o] h:mm A", + "(leave blank for to use commercial endpoint)": "(pozostaw puste, aby użyć komercyjnego punktu końcowego)", + "[Last] dddd [at] h:mm A": "[Ostatnio] dddd [o] H:mm", + "[Today at] h:mm A": "[Dziś o] H:mm", + "[Yesterday at] h:mm A": "[Wczoraj o] H:mm", "{{ models }}": "{{ models }}", "{{COUNT}} Available Tools": "{{COUNT}} dostępnych narzędzi", "{{COUNT}} characters": "{{COUNT}} znaków", - "{{COUNT}} extracted lines": "", - "{{COUNT}} files": "", + "{{COUNT}} extracted lines": "{{COUNT}} wyodrębnionych linii", + "{{COUNT}} files": "{{COUNT}} plików", "{{COUNT}} hidden lines": "{{COUNT}} ukrytych linii", "{{COUNT}} Replies": "{{COUNT}} odpowiedzi", - "{{COUNT}} Rows": "", - "{{COUNT}} Sources": "", + "{{COUNT}} Rows": "{{COUNT}} wierszy", + "{{COUNT}} Sources": "{{COUNT}} źródeł", "{{COUNT}} words": "{{COUNT}} słów", - "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "", - "{{model}} download has been canceled": "", - "{{NAMES}} reacted with {{REACTION}}": "", + "{{LOCALIZED_DATE}} at {{LOCALIZED_TIME}}": "{{LOCALIZED_DATE}} o {{LOCALIZED_TIME}}", + "{{model}} download has been canceled": "Pobieranie modelu {{model}} zostało anulowane", + "{{NAMES}} reacted with {{REACTION}}": "{{NAMES}} zareagował(a) {{REACTION}}", "{{user}}'s Chats": "Czaty użytkownika {{user}}", - "{{webUIName}} Backend Required": "Backend dla {{webUIName}} jest wymagany", - "*Prompt node ID(s) are required for image generation": "Wymagane są identyfikatory węzłów wyzwalających do generowania obrazów.", - "1 Source": "", - "A collaboration channel where people join as members": "", - "A discussion channel where access is controlled by groups and permissions": "", + "{{webUIName}} Backend Required": "Wymagany backend {{webUIName}}", + "*Prompt node ID(s) are required for image generation": "*Wymagane są identyfikatory węzłów Prompt do generowania obrazów", + "1 Source": "1 źródło", + "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}}).", - "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": "Model zadań jest wykorzystywany podczas realizacji zadań, takich jak generowanie tytułów rozmów i zapytań wyszukiwania internetowego.", + "A private conversation between you and selected users": "Prywatna rozmowa między Tobą a wybranymi użytkownikami", + "A task model is used when performing tasks such as generating titles for chats and web search queries": "Model zadaniowy jest używany do czynności takich jak generowanie tytułów czatów i zapytań do wyszukiwarki.", "a user": "użytkownik", - "About": "O nas", - "Accept Autocomplete Generation\nJump to Prompt Variable": "", + "About": "O aplikacji", + "Accept Autocomplete Generation\nJump to Prompt Variable": "Zaakceptuj autouzupełnianie\nPrzejdź do zmiennej promptu", "Access": "Dostęp", "Access Control": "Kontrola dostępu", "Accessible to all users": "Dostępny dla wszystkich użytkowników", "Account": "Konto", "Account Activation Pending": "Aktywacja konta w toku", - "Accurate information": "Precyzyjna informacja", + "Accurate information": "Precyzyjne informacje", "Action": "Akcja", - "Action not found": "", - "Action Required for Chat Log Storage": "Wymagane działanie, aby zapisać dziennik czatu", + "Action not found": "Nie znaleziono akcji", + "Action Required for Chat Log Storage": "Wymagane działanie, aby zapisać historię czatu", "Actions": "Akcje", - "Activate": "Włącz", - "Activate this command by typing \"/{{COMMAND}}\" to chat input.": "Aktywuj tę komendę, wpisując \"/{{COMMAND}}\" do pola wprowadzania czatu.", + "Activate": "Aktywuj", + "Activate this command by typing \"/{{COMMAND}}\" to chat input.": "Aktywuj tę komendę, wpisując \"/{{COMMAND}}\" w polu czatu.", "Active": "Aktywny", "Active Users": "Aktywni użytkownicy", "Add": "Dodaj", "Add a model ID": "Dodaj identyfikator modelu", "Add a short description about what this model does": "Dodaj krótki opis działania tego modelu", "Add a tag": "Dodaj tag", - "Add Arena Model": "Dodaj Model Arena", + "Add Arena Model": "Dodaj model Arena", "Add Connection": "Dodaj połączenie", "Add Content": "Dodaj treść", - "Add content here": "Dodaj tutaj treść", - "Add Custom Parameter": "", - "Add Custom Prompt": "", - "Add Details": "", + "Add content here": "Dodaj treść tutaj", + "Add Custom Parameter": "Dodaj parametr niestandardowy", + "Add Custom Prompt": "Dodaj niestandardowy prompt", + "Add Details": "Dodaj szczegóły", "Add Files": "Dodaj pliki", - "Add Member": "", - "Add Members": "", + "Add Member": "Dodaj członka", + "Add Members": "Dodaj członków", "Add Memory": "Dodaj pamięć", "Add Model": "Dodaj model", "Add Reaction": "Dodaj reakcję", @@ -69,1774 +69,1774 @@ "Add text content": "Dodaj zawartość tekstową", "Add User": "Dodaj użytkownika", "Add User Group": "Dodaj grupę użytkowników", - "Add webpage": "", - "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": "", - "Additional Parameters": "", - "Adds filenames, titles, sections, and snippets into the BM25 text to improve lexical recall.": "", - "Adjusting these settings will apply changes universally to all users.": "Dostosowanie tych ustawień spowoduje wprowadzenie zmian dla wszystkich użytkowników.", + "Add webpage": "Dodaj stronę www", + "Additional Config": "Dodatkowa konfiguracja", + "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": "Dodatkowe opcje konfiguracji dla markera. Powinien to być ciąg JSON z parami klucz-wartość, np. '{\"key\": \"value\"}'. Obsługiwane klucze: 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 Parameters": "Dodatkowe parametry", + "Adds filenames, titles, sections, and snippets into the BM25 text to improve lexical recall.": "Dodaje nazwy plików, tytuły, sekcje i fragmenty do tekstu BM25, aby poprawić wyszukiwanie leksykalne.", + "Adjusting these settings will apply changes universally to all users.": "Zmiana tych ustawień wpłynie na wszystkich użytkowników.", "admin": "administrator", "Admin": "Administrator", "Admin Panel": "Panel administracyjny", "Admin Settings": "Ustawienia administratora", - "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratorzy mają dostęp do wszystkich narzędzi przez cały czas; użytkownicy muszą mieć przydzielone narzędzia dla każdego modelu w przestrzeni roboczej.", - "Advanced Parameters": "Zaawansowane ustawienia", - "Advanced parameters for MinerU parsing (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)": "", - "Advanced Params": "Zaawansowane ustawienia", - "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": "", + "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratorzy mają zawsze dostęp do wszystkich narzędzi; użytkownicy muszą mieć przypisane narzędzia do modelu w obszarze roboczym.", + "Advanced Parameters": "Zaawansowane parametry", + "Advanced parameters for MinerU parsing (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges)": "Zaawansowane parametry parsowania MinerU (enable_ocr, enable_formula, enable_table, language, model_version, page_ranges).", + "Advanced Params": "Zaawansowane parametry", + "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.": "Po aktualizacji lub zmianie modelu embeddingów musisz przeindeksować Bazę wiedzy. Użyj przycisku \"Reindeksuj\" poniżej.", + "AI": "AI", "All": "Wszystkie", - "All chats have been unarchived.": "", - "All models deleted successfully": "Wszystkie modele zostały usunięte pomyślnie.", - "Allow Call": "Zezwól na tryb głosowy", - "Allow Chat Controls": "Zezwól na dostęp do ustawień czatu", - "Allow Chat Delete": "Zezwól na usunięcie czatu", + "All chats have been unarchived.": "Wszystkie czaty zostały odarchiwizowane.", + "All models deleted successfully": "Wszystkie modele zostały pomyślnie usunięte.", + "Allow Call": "Zezwól na wywoływanie", + "Allow Chat Controls": "Zezwól na kontrolę czatu", + "Allow Chat Delete": "Zezwól na usuwanie czatu", "Allow Chat Deletion": "Zezwól na usuwanie czatu", "Allow Chat Edit": "Zezwól na edycję czatu", - "Allow Chat Export": "Zezwól na eksportowanie", - "Allow Chat Params": "", - "Allow Chat Share": "Zezwól na udostępnianie", - "Allow Chat System Prompt": "Zezwól na zmianę promptu systemowego dla czatu", - "Allow Chat Valves": "", - "Allow Continue Response": "", - "Allow Delete Messages": "", - "Allow File Upload": "Pozwól na przesyłanie plików", - "Allow Group Sharing": "", - "Allow Multiple Models in Chat": "Zezwól na wiele modeli w ramach jednego czatu", - "Allow non-local voices": "Pozwól na głosy spoza lokalnej społeczności", - "Allow Rate Response": "", - "Allow Regenerate Response": "", - "Allow Speech to Text": "Zezwól na transkrypcję", - "Allow Temporary Chat": "Zezwól na tymczasową rozmowę", - "Allow Text to Speech": "Zezwól na syntezator głosu", + "Allow Chat Export": "Zezwól na eksport czatu", + "Allow Chat Params": "Zezwól na parametry czatu", + "Allow Chat Share": "Zezwól na udostępnianie czatu", + "Allow Chat System Prompt": "Zezwól na prompt systemowy czatu", + "Allow Chat Valves": "Zezwól na Valves w czacie", + "Allow Continue Response": "Zezwól na kontynuację odpowiedzi", + "Allow Delete Messages": "Zezwól na usuwanie wiadomości", + "Allow File Upload": "Zezwól na przesyłanie plików", + "Allow Group Sharing": "Zezwól na udostępnianie grupowe", + "Allow Multiple Models in Chat": "Zezwól na wiele modeli w czacie", + "Allow non-local voices": "Zezwól na głosy nielokalne", + "Allow Rate Response": "Zezwól na ocenianie odpowiedzi", + "Allow Regenerate Response": "Zezwól na regenerację odpowiedzi", + "Allow Speech to Text": "Zezwól na Speech-to-Text", + "Allow Temporary Chat": "Zezwól na czat tymczasowy", + "Allow Text to Speech": "Zezwól na Text-to-Speech", "Allow User Location": "Zezwól na lokalizację użytkownika", - "Allow Voice Interruption in Call": "Zezwól na przerwanie połączenia głosowego", + "Allow Voice Interruption in Call": "Zezwól na przerywanie w trakcie wywoływania", "Allowed Endpoints": "Dozwolone punkty końcowe", "Allowed File Extensions": "Dozwolone rozszerzenia plików", - "Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.": "", - "Already have an account?": "Czy masz już konto?", - "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.": "", + "Allowed file extensions for upload. Separate multiple extensions with commas. Leave empty for all file types.": "Dozwolone rozszerzenia plików. Oddziel przecinkami. Pozostaw puste dla wszystkich typów.", + "Already have an account?": "Masz już konto?", + "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.": "Alternatywa dla top_p, zapewniająca balans między jakością a różnorodnością. Parametr p to minimalne prawdopodobieństwo tokena względem najbardziej prawdopodobnego tokena. Np. przy p=0.05 i max prawdopodobieństwie 0.9, wartości poniżej 0.045 są odrzucane.", "Always": "Zawsze", "Always Collapse Code Blocks": "Zawsze zwijaj bloki kodu", - "Always Expand Details": "Zawsze rozwiń szczegóły", - "Always Play Notification Sound": "", + "Always Expand Details": "Zawsze rozwijaj szczegóły", + "Always Play Notification Sound": "Zawsze odtwarzaj dźwięk powiadomienia", "Amazing": "Niesamowite", "an assistant": "asystent", - "An error occurred while fetching the explanation": "", - "Analytics": "", - "Analyzed": "Przeanalizowane", + "An error occurred while fetching the explanation": "Wystąpił błąd podczas pobierania wyjaśnienia", + "Analytics": "Analityka", + "Analyzed": "Przeanalizowano", "Analyzing...": "Analizowanie...", "and": "oraz", "and {{COUNT}} more": "i {{COUNT}} więcej", - "and create a new shared link.": "i utwórz nowy link współdzielony.", - "Android": "", - "API Base URL": "Adres bazowy interfejsu API", - "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", + "and create a new shared link.": "i utwórz nowy link udostępniania.", + "Android": "Android", + "API Base URL": "Bazowy adres URL API", + "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "Bazowy adres URL API dla usługi Datalab Marker. Domyślnie: https://www.datalab.to/api/v1/marker", "API Key": "Klucz API", - "API Key created.": "Klucz API został utworzony.", - "API Key Endpoint Restrictions": "Ograniczenia punktu końcowego klucza API", + "API Key created.": "Utworzono klucz API.", + "API Key Endpoint Restrictions": "Ograniczenia punktów końcowych klucza API", "API keys": "Klucze API", - "API Keys": "", - "API Mode": "", - "API Timeout": "", + "API Keys": "Klucze API", + "API Mode": "Tryb API", + "API Timeout": "Limit czasu API", "API Version": "Wersja API", - "API Version is required": "", - "Application DN": "Konto techniczne - Format DN", - "Application DN Password": "Hasło do konta technicznego", + "API Version is required": "Wersja API jest wymagana", + "Application DN": "DN Aplikacji (Konto techniczne)", + "Application DN Password": "Hasło DN Aplikacji", "applies to all users with the \"user\" role": "dotyczy wszystkich użytkowników z rolą \"user\"", "April": "Kwiecień", "Archive": "Archiwum", - "Archive All Chats": "Archiwizuj wszystkie rozmowy", - "Archived Chats": "Zarchiwizowane rozmowy", - "archived-chat-export": "archiwizowany eksport czatu", - "Are you sure you want to clear all memories? This action cannot be undone.": "Czy na pewno chcesz wyczyścić wszystkie wspomnienia? Tej akcji nie można cofnąć.", - "Are you sure you want to delete \"{{NAME}}\"?": "", + "Archive All Chats": "Zarchiwizuj wszystkie czaty", + "Archived Chats": "Zarchiwizowane czaty", + "archived-chat-export": "eksport-zarchiwizowanych-czatow", + "Are you sure you want to clear all memories? This action cannot be undone.": "Czy na pewno chcesz wyczyścić wszystkie wspomnienia? Tej operacji nie można cofnąć.", + "Are you sure you want to delete \"{{NAME}}\"?": "Czy na pewno chcesz usunąć \"{{NAME}}\"?", "Are you sure you want to delete this channel?": "Czy na pewno chcesz usunąć ten kanał?", "Are you sure you want to delete this message?": "Czy na pewno chcesz usunąć tę wiadomość?", - "Are you sure you want to unarchive all archived chats?": "Czy na pewno chcesz przywrócić wszystkie zapisane rozmowy?", - "Are you sure?": "Czy jesteś pewien?", - "Arena Models": "Modele Areny", + "Are you sure you want to unarchive all archived chats?": "Czy na pewno chcesz odarchiwizować wszystkie czaty?", + "Are you sure?": "Czy na pewno?", + "Arena Models": "Modele Arena", "Artifacts": "Artefakty", - "Asc": "", + "Asc": "Rosnąco", "Ask": "Zapytaj", "Ask a question": "Zadaj pytanie", "Assistant": "Asystent", - "Async Embedding Processing": "", - "Attach File From Knowledge": "", - "Attach Knowledge": "", - "Attach Notes": "", - "Attach Webpage": "", + "Async Embedding Processing": "Asynchroniczne przetwarzanie embeddingów", + "Attach File From Knowledge": "Dołącz plik z Bazy wiedzy", + "Attach Knowledge": "Dołącz Bazę wiedzy", + "Attach Notes": "Dołącz notatki", + "Attach Webpage": "Dołącz stronę www", "Attention to detail": "Dbałość o szczegóły", - "Attribute for Mail": "Atrybut dla poczty", - "Attribute for Username": "Atrybut dla nazwy użytkownika", + "Attribute for Mail": "Atrybut dla Email", + "Attribute for Username": "Atrybut dla Nazwy użytkownika", "Audio": "Dźwięk", "August": "Sierpień", - "Auth": "", - "Authenticate": "Zaloguj się", + "Auth": "Autoryzacja", + "Authenticate": "Uwierzytelnij", "Authentication": "Uwierzytelnianie", - "Auto": "", - "Auto-Copy Response to Clipboard": "Automatyczne kopiowanie odpowiedzi do schowka", - "Auto-playback response": "Automatyczna odpowiedź na powtórzenie", + "Auto": "Auto", + "Auto-Copy Response to Clipboard": "Automatycznie kopiuj odpowiedź do schowka", + "Auto-playback response": "Automatyczne odtwarzanie odpowiedzi", "Autocomplete Generation": "Generowanie autouzupełniania", - "Autocomplete Generation Input Max Length": "Maksymalna długość wejścia dla generowania autouzupełniania", + "Autocomplete Generation Input Max Length": "Maks. długość wejścia autouzupełniania", "Automatic1111": "Automatic1111", - "AUTOMATIC1111 Api Auth String": "Automatic1111 - ciąg uwierzytelniania API", - "AUTOMATIC1111 Base URL": "Automatic1111 - Domyślny adres URL", - "AUTOMATIC1111 Base URL is required.": "Automatic1111 - Adres podstawowy jest wymagany.", + "AUTOMATIC1111 Api Auth String": "Ciąg autoryzacji API AUTOMATIC1111", + "AUTOMATIC1111 Base URL": "Bazowy adres URL AUTOMATIC1111", + "AUTOMATIC1111 Base URL is required.": "Bazowy adres URL AUTOMATIC1111 jest wymagany.", "Available list": "Dostępna lista", "Available Tools": "Dostępne narzędzia", "available users": "dostępni użytkownicy", - "available!": "dostępny!", + "available!": "dostępne!", "Away": "Nieobecny", "Awful": "Okropne", "Azure AI Speech": "Azure AI Speech", "Azure OpenAI": "Azure OpenAI", "Azure Region": "Region Azure", "Back": "Wstecz", - "Bad Response": "Nieprawidłowa odpowiedź", - "Banners": "Bannery", - "Base Model (From)": "Model bazowy (od)", - "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": "", + "Bad Response": "Zła odpowiedź", + "Banners": "Banery", + "Base Model (From)": "Model bazowy (Z)", + "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 listy modeli bazowych przyspiesza dostęp, pobierając je tylko przy starcie lub zapisie ustawień – szybciej, ale może nie pokazać ostatnich zmian w modelach.", + "Bearer": "Bearer", "before": "przed", - "Being lazy": "Jest leniwy.", + "Being lazy": "Bezczynny", "Beta": "Beta", - "Bing Search V7 Endpoint": "Wyszukiwarka Bing V7 Endpoint", - "Bing Search V7 Subscription Key": "Klucz subskrypcji Wyszukiwarki Bing V7", - "Bio": "", - "Birth Date": "", - "BM25 Weight": "", + "Bing Search V7 Endpoint": "Punkt końcowy Bing Search V7", + "Bing Search V7 Subscription Key": "Klucz subskrypcji Bing Search V7", + "Bio": "Bio", + "Birth Date": "Data urodzenia", + "BM25 Weight": "Waga BM25", "Bocha Search API Key": "Klucz API Bocha Search", "Bold": "Pogrubienie", - "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", - "Brave Search API Key": "Klucz API wyszukiwania Brave", + "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Wzmacnianie lub karanie tokenów. Wartości bias (obciążenia) są ograniczone do zakresu -100 do 100. (Domyślnie: brak)", + "Brave Search API Key": "Klucz API Brave Search", "Bullet List": "Lista punktowana", - "Button ID": "", - "Button Label": "", - "Button Prompt": "", + "Button ID": "ID Przycisku", + "Button Label": "Etykieta przycisku", + "Button Prompt": "Prompt przycisku", "By {{name}}": "Przez {{name}}", - "Bypass Embedding and Retrieval": "", - "Bypass Web Loader": "", - "Cache Base Model List": "", + "Bypass Embedding and Retrieval": "Pomiń Embedding i Retrieval", + "Bypass Web Loader": "Pomiń Web Loader", + "Cache Base Model List": "Cachuj listę modeli bazowych", "Calendar": "Kalendarz", - "Call": "Rozmowa", - "Call feature is not supported when using Web STT engine": "Funkcja rozmowy nie jest obsługiwana podczas korzystania z silnika Web STT", + "Call": "Wywołanie", + "Call feature is not supported when using Web STT engine": "Funkcja wywołania nie jest obsługiwana przy użyciu silnika Web STT", "Camera": "Kamera", "Cancel": "Anuluj", - "Cannot create an empty note.": "", + "Cannot create an empty note.": "Nie można utworzyć pustej notatki.", "Capabilities": "Możliwości", "Capture": "Przechwyć", - "Capture Audio": "", + "Capture Audio": "Przechwyć dźwięk", "Certificate Path": "Ścieżka certyfikatu", "Change Password": "Zmień hasło", - "Channel": "", - "Channel deleted successfully": "", + "Channel": "Kanał", + "Channel deleted successfully": "Kanał usunięty pomyślnie", "Channel Name": "Nazwa kanału", - "Channel name cannot be empty.": "", - "Channel name must be less than 128 characters": "", - "Channel Type": "", - "Channel updated successfully": "", + "Channel name cannot be empty.": "Nazwa kanału nie może być pusta.", + "Channel name must be less than 128 characters": "Nazwa kanału musi mieć mniej niż 128 znaków", + "Channel Type": "Typ kanału", + "Channel updated successfully": "Kanał zaktualizowany pomyślnie", "Channels": "Kanały", "Character": "Znak", - "Character limit for autocomplete generation input": "Limit znaków dla wejścia generowanego automatycznie", - "Chart new frontiers": "Odkrywaj nowe horyzonty", + "Character limit for autocomplete generation input": "Limit znaków dla wejścia autouzupełniania", + "Chart new frontiers": "Poznawaj nowe możliwości", "Chat": "Czat", "Chat Background Image": "Obraz tła czatu", - "Chat Bubble UI": "Okno dialogowe czatu", + "Chat Bubble UI": "UI dymków czatu", "Chat Controls": "Ustawienia czatu", - "Chat Conversation": "", - "Chat direction": "Kierunek rozmowy czatu", - "Chat ID": "", - "Chat moved successfully": "", + "Chat Conversation": "Rozmowa", + "Chat direction": "Kierunek czatu", + "Chat ID": "ID czatu", + "Chat moved successfully": "Czat przeniesiony pomyślnie", "Chat Overview": "Przegląd czatu", - "Chat Permissions": "Uprawnienia do czatu", + "Chat Permissions": "Uprawnienia czatu", "Chat Tags Auto-Generation": "Automatyczne generowanie tagów czatu", "Chats": "Czaty", "Check Again": "Sprawdź ponownie", "Check for updates": "Sprawdź dostępność aktualizacji", - "Checking for updates...": "Sprawdzanie dostępności aktualizacji...", - "Choose a model before saving...": "Wybierz model przed zapisaniem.", - "Chunk Overlap": "Nakładanie się bloków", - "Chunk Size": "Rozmiar bloku", + "Checking for updates...": "Sprawdzanie aktualizacji...", + "Choose a model before saving...": "Wybierz model przed zapisaniem...", + "Chunk Overlap": "Chunk Overlap", + "Chunk Size": "Chunk Size", "Ciphers": "Szyfry", "Citation": "Cytat", "Citations": "Cytaty", "Clear memory": "Wyczyść pamięć", "Clear Memory": "Wyczyść pamięć", - "Clear status": "", + "Clear status": "Wyczyść status", "click here": "kliknij tutaj", - "Click here for filter guides.": "Kliknij tutaj, aby uzyskać podpowiedź do filtrów.", + "Click here for filter guides.": "Kliknij tutaj, aby zobaczyć przewodnik po filtrach.", "Click here for help.": "Kliknij tutaj, aby uzyskać pomoc.", - "Click here to": "Kliknij tutaj, aby przejść do", - "Click here to download user import template file.": "Kliknij tutaj, aby pobrać szablon pliku importu użytkownika.", + "Click here to": "Kliknij tutaj, aby", + "Click here to download user import template file.": "Kliknij tutaj, aby pobrać szablon importu użytkowników.", "Click here to learn more about faster-whisper and see the available models.": "Kliknij tutaj, aby dowiedzieć się więcej o faster-whisper i zobaczyć dostępne modele.", "Click here to see available models.": "Kliknij tutaj, aby zobaczyć dostępne modele.", "Click here to select": "Kliknij tutaj, aby wybrać", "Click here to select a csv file.": "Kliknij tutaj, aby wybrać plik CSV.", - "Click here to select a py file.": "Kliknij tutaj, aby wybrać plik py.", + "Click here to select a py file.": "Kliknij tutaj, aby wybrać plik PY.", "Click here to upload a workflow.json file.": "Kliknij tutaj, aby przesłać plik workflow.json.", "click here.": "kliknij tutaj.", - "Click on the user role button to change a user's role.": "Kliknij przycisk roli użytkownika, aby zmienić jego uprawnienia.", - "Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Nie można było skopiować do schowka. Sprawdź ustawienia przeglądarki, aby przyznać wymagany dostęp.", - "Clone": "Duplikuj", + "Click on the user role button to change a user's role.": "Kliknij przycisk roli użytkownika, aby ją zmienić.", + "Clipboard write permission denied. Please check your browser settings to grant the necessary access.": "Odmowa dostępu do schowka. Sprawdź ustawienia przeglądarki.", + "Clone": "Sklonuj", "Clone Chat": "Sklonuj czat", - "Clone of {{TITLE}}": "Klon {{TITLE}}", + "Clone of {{TITLE}}": "Kopia {{TITLE}}", "Close": "Zamknij", - "Close Banner": "", - "Close Configure Connection Modal": "", - "Close modal": "", - "Close Modal": "", - "Close settings modal": "", - "Close Sidebar": "", - "cloud": "", - "CMU ARCTIC speaker embedding name": "", + "Close Banner": "Zamknij baner", + "Close Configure Connection Modal": "Zamknij okno konfiguracji połączenia", + "Close modal": "Zamknij okno", + "Close Modal": "Zamknij okno", + "Close settings modal": "Zamknij okno ustawień", + "Close Sidebar": "Zamknij pasek boczny", + "cloud": "chmura", + "CMU ARCTIC speaker embedding name": "Nazwa embeddingu mówcy CMU ARCTIC", "Code Block": "Blok kodu", - "Code Editor": "", - "Code execution": "Wykonanie kodu", - "Code Execution": "Wykonanie kodu", - "Code Execution Engine": "Silnik wykonawczy kodu", + "Code Editor": "Edytor kodu", + "Code execution": "Wykonywanie kodu", + "Code Execution": "Wykonywanie kodu", + "Code Execution Engine": "Silnik wykonywania kodu", "Code Execution Timeout": "Limit czasu wykonywania kodu", - "Code formatted successfully": "Kod został sformatowany pomyślnie.", + "Code formatted successfully": "Sformatowano kod pomyślnie", "Code Interpreter": "Interpreter kodu", - "Code Interpreter Engine": "Silnik interpretatora kodu", + "Code Interpreter Engine": "Silnik interpretera kodu", "Code Interpreter Prompt Template": "Szablon promptu interpretera kodu", - "Collaboration channel where people join as members": "", - "Collapse": "", + "Collaboration channel where people join as members": "Kanał współpracy dostępny dla członków", + "Collapse": "Zwiń", "Collection": "Kolekcja", - "Collections": "", + "Collections": "Kolekcje", "Color": "Kolor", "ComfyUI": "ComfyUI", "ComfyUI API Key": "Klucz API ComfyUI", - "ComfyUI Base URL": "Adres URL bazowy ComfyUI", - "ComfyUI Base URL is required.": "Adres URL bazowy ComfyUI jest wymagany.", - "ComfyUI Workflow": "Komfortowy przepływ pracy ComfyUI", - "ComfyUI Workflow Nodes": "Komfortowe węzły przepływu pracy ComfyUI", - "Comma separated Node Ids (e.g. 1 or 1,2)": "", - "Command": "Polecenie", - "Comment": "", - "Completions": "Uzupełnienia", - "Compress Images in Channels": "", - "Concurrent Requests": "Równoległe żądania", - "Config imported successfully": "", - "Configure": "Skonfigurować", + "ComfyUI Base URL": "Bazowy adres URL ComfyUI", + "ComfyUI Base URL is required.": "Bazowy adres URL ComfyUI jest wymagany.", + "ComfyUI Workflow": "Workflow ComfyUI", + "ComfyUI Workflow Nodes": "Węzły Workflow ComfyUI", + "Comma separated Node Ids (e.g. 1 or 1,2)": "ID węzłów oddzielone przecinkami (np. 1 lub 1,2)", + "Command": "Komenda", + "Comment": "Komentarz", + "Completions": "Completions (Uzupełnianie)", + "Compress Images in Channels": "Kompresuj obrazy w kanałach", + "Concurrent Requests": "Jednoczesne żądania", + "Config imported successfully": "Konfiguracja zaimportowana pomyślnie", + "Configure": "Konfiguruj", "Confirm": "Potwierdź", "Confirm Password": "Potwierdź hasło", - "Confirm your action": "Potwierdź swoją akcję", + "Confirm your action": "Potwierdź działanie", "Confirm your new password": "Potwierdź nowe hasło", - "Confirm Your Password": "", - "Connect to your own OpenAI compatible API endpoints.": "Połącz się ze swoimi własnymi punktami końcowymi API kompatybilnego z OpenAI.", - "Connect to your own OpenAPI compatible external tool servers.": "", + "Confirm Your Password": "Potwierdź swoje hasło", + "Connect to your own OpenAI compatible API endpoints.": "Połącz z własnymi punktami końcowymi API zgodnymi z OpenAI.", + "Connect to your own OpenAPI compatible external tool servers.": "Połącz z własnymi serwerami narzędzi zgodnymi z OpenAPI.", "Connection failed": "Połączenie nieudane", "Connection successful": "Połączenie udane", "Connection Type": "Typ połączenia", "Connections": "Połączenia", "Connections saved successfully": "Połączenia zapisane pomyślnie", - "Connections settings updated": "Ustawienia połączeń zaktualizowane", - "Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort.": "", - "Contact Admin for WebUI Access": "Skontaktuj się z administratorem, aby uzyskać dostęp do WebUI.", + "Connections settings updated": "Zaktualizowano ustawienia połączeń", + "Constrains effort on reasoning for reasoning models. Only applicable to reasoning models from specific providers that support reasoning effort.": "Ogranicza Reasoning Effort dla modeli myślących. Dotyczy wyłączie modeli myślących wspierających zmienną Reasoning Effort.", + "Contact Admin for WebUI Access": "Skontaktuj się z administratorem, aby uzyskać dostęp.", "Content": "Treść", "Content Extraction Engine": "Silnik ekstrakcji treści", "Continue Response": "Kontynuuj odpowiedź", - "Continue with {{provider}}": "Kontynuuj z {{provider}}", - "Continue with Email": "Kontynuuj z e-mailem", - "Continue with LDAP": "Kontynuuj z LDAP", - "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.": "Kontroluj sposób dzielenia tekstu wiadomości dla żądań TTS. 'Punctuation' dzieli na zdania, 'paragraphs' dzieli na akapity, a 'none' pozostawia wiadomość jako pojedynczy ciąg znaków.", - "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.": "", - "Controls": "Ustawienia", - "Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text.": "", - "Conversation saved successfully": "", - "Copied": "Skopiowane", + "Continue with {{provider}}": "Kontynuuj przez {{provider}}", + "Continue with Email": "Kontynuuj przez Email", + "Continue with LDAP": "Kontynuuj przez LDAP", + "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.": "Kontroluje podział tekstu dla TTS. 'Interpunkcja' dzieli na zdania, 'Akapity' na akapity, 'Brak' zostawia jeden ciąg.", + "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.": "Kontroluje powtarzanie sekwencji tokenów. Wyższa wartość (np. 1.5) silniej karze powtórzenia. Wartość 1 wyłącza funkcję.", + "Controls": "Sterowanie", + "Controls the balance between coherence and diversity of the output. A lower value will result in more focused and coherent text.": "Kontroluje balans między spójnością a różnorodnością. Niższa wartość daje bardziej skupiony tekst.", + "Conversation saved successfully": "Rozmowa zapisana pomyślnie", + "Copied": "Skopiowano", "Copied link to clipboard": "Skopiowano link do schowka", - "Copied shared chat URL to clipboard!": "Skopiowano udostępniony URL czatu do schowka!", - "Copied to clipboard": "Skopiowane do schowka", - "Copy": "Skopiuj", - "Copy Formatted Text": "Skopiuj sformatowany tekst", - "Copy Last Code Block": "", - "Copy Last Response": "", - "Copy link": "Skopiuj link", - "Copy Link": "Skopiuj link", - "Copy to clipboard": "Wklej do schowka", - "Copying to clipboard was successful!": "Kopiowanie do schowka zakończyło się sukcesem!", - "CORS must be properly configured by the provider to allow requests from Open WebUI.": "CORS musi być prawidłowo skonfigurowany przez dostawcę, aby umożliwić żądania z Open WebUI.", + "Copied shared chat URL to clipboard!": "Skopiowano udostępniony URL czatu!", + "Copied to clipboard": "Skopiowano do schowka", + "Copy": "Kopiuj", + "Copy Formatted Text": "Kopiuj sformatowany tekst", + "Copy Last Code Block": "Kopiuj ostatni blok kodu", + "Copy Last Response": "Kopiuj ostatnią odpowiedź", + "Copy link": "Kopiuj link", + "Copy Link": "Kopiuj link", + "Copy to clipboard": "Kopiuj do schowka", + "Copying to clipboard was successful!": "Pomyślnie skopiowano do schowka!", + "CORS must be properly configured by the provider to allow requests from Open WebUI.": "Dostawca musi poprawnie skonfigurować CORS, aby zezwolić na żądania z Open WebUI.", "Create": "Utwórz", "Create a knowledge base": "Utwórz bazę wiedzy", "Create a model": "Utwórz model", - "Create a new note": "", + "Create a new note": "Utwórz nową notatkę", "Create Account": "Utwórz konto", "Create Admin Account": "Utwórz konto administratora", "Create Channel": "Utwórz kanał", "Create Folder": "Utwórz folder", "Create Group": "Utwórz grupę", - "Create Image": "", + "Create Image": "Utwórz obraz", "Create Knowledge": "Utwórz wiedzę", - "Create Model": "", + "Create Model": "Utwórz model", "Create new key": "Utwórz nowy klucz", - "Create new secret key": "Utwórz nowy secret key", - "Create note": "", + "Create new secret key": "Utwórz nowy tajny klucz", + "Create note": "Utwórz notatkę", "Create Note": "Utwórz notatkę", - "Create your first note by clicking on the plus button below.": "Utwórz swoją pierwszą notatkę klikając w plus poniżej.", - "Created at": "Utworzono o", - "Created At": "Utworzono o", - "Created by": "Stworzone przez", - "Created by you": "", + "Create your first note by clicking on the plus button below.": "Utwórz pierwszą notatkę klikając plus poniżej.", + "Created at": "Utworzono", + "Created At": "Data utworzenia", + "Created by": "Utworzone przez", + "Created by you": "Utworzone przez Ciebie", "CSV Import": "Import CSV", "Ctrl+Enter to Send": "Ctrl+Enter aby wysłać", - "Current Model": "Aktualny model", - "Current Password": "Aktualne hasło", - "Custom": "Niestandardowy", - "Custom description enabled": "", - "Custom Parameter Name": "", - "Custom Parameter Value": "", - "Danger Zone": "", + "Current Model": "Obecny model", + "Current Password": "Obecne hasło", + "Custom": "Własny", + "Custom description enabled": "Włączono własny opis", + "Custom Parameter Name": "Nazwa parametru niestandardowego", + "Custom Parameter Value": "Wartość parametru niestandardowego", + "Danger Zone": "Strefa krytyczna", "Dark": "Ciemny", - "Data Controls": "", + "Data Controls": "Zarządzanie danymi", "Database": "Baza danych", - "Datalab Marker API": "", - "DD/MM/YYYY": "", + "Datalab Marker API": "API Datalab Marker", + "DD/MM/YYYY": "DD/MM/YYYY", "December": "Grudzień", - "Decrease UI Scale": "", - "Deepgram": "", + "Decrease UI Scale": "Zmniejsz skalę UI", + "Deepgram": "Deepgram", "Default": "Domyślny", "Default (Open AI)": "Domyślny (Open AI)", "Default (SentenceTransformers)": "Domyślny (SentenceTransformers)", - "Default action buttons will be used.": "", - "Default description enabled": "", - "Default Features": "", - "Default Filters": "", - "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.": "Tryb domyślny współpracuje z szerszym zakresem modeli, wywołując narzędzia raz przed wykonaniem. Tryb natywny wykorzystuje wbudowane możliwości wywoływania narzędzi przez model, ale wymaga, aby model wewnętrznie obsługiwał tę funkcję.", + "Default action buttons will be used.": "Zostaną użyte domyślne przyciski akcji.", + "Default description enabled": "Włączono opis domyślny", + "Default Features": "Domyślne funkcje", + "Default Filters": "Domyślne filtry", + "Default Group": "Domyślna grupa", + "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.": "Tryb domyślny działa z większą liczbą modeli. Tryb natywny używa wbudowanych funkcji modelu (function calling), ale wymaga wsparcia ze strony modelu.", "Default Model": "Model domyślny", - "Default model updated": "Domyślny model został zaktualizowany", + "Default model updated": "Zaktualizowano model domyślny", "Default Models": "Domyślne modele", "Default permissions": "Domyślne uprawnienia", - "Default permissions updated successfully": "Domyślne uprawnienia zaktualizowane pomyślnie", - "Default Pinned Models": "", - "Default Prompt Suggestions": "Domyślne propozycje promptów", - "Default to 389 or 636 if TLS is enabled": "Domyślnie użyj 389 lub 636, jeśli TLS jest włączony", - "Default to ALL": "Domyślne dla wszystkich", - "Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.": "", + "Default permissions updated successfully": "Zaktualizowano domyślne uprawnienia", + "Default Pinned Models": "Domyślne przypięte modele", + "Default Prompt Suggestions": "Domyślne sugestie promptów", + "Default to 389 or 636 if TLS is enabled": "Domyślnie 389 lub 636 przy włączonym TLS", + "Default to ALL": "Domyślnie WSZYSTKIE", + "Default to segmented retrieval for focused and relevant content extraction, this is recommended for most cases.": "Domyślnie używa segmented retrieval dla lepszej precyzji. Zalecane w większości przypadków.", "Default User Role": "Domyślna rola użytkownika", "Delete": "Usuń", "Delete a model": "Usuń model", - "Delete All Chats": "Usuń wszystkie rozmowy", - "Delete all contents inside this folder": "", - "Delete All Models": "Usuń Wszystkie Modele", - "Delete Chat": "Usuń rozmowę", + "Delete All Chats": "Usuń wszystkie czaty", + "Delete all contents inside this folder": "Usuń całą zawartość tego folderu", + "Delete All Models": "Usuń wszystkie modele", + "Delete Chat": "Usuń czat", "Delete chat?": "Usunąć czat?", "Delete folder?": "Usunąć folder?", - "Delete function?": "Czy na pewno chcesz usunąć funkcję?", + "Delete function?": "Usunąć funkcję?", "Delete Message": "Usuń wiadomość", "Delete message?": "Usunąć wiadomość?", - "Delete Model": "", + "Delete Model": "Usuń model", "Delete note?": "Usunąć notatkę?", - "Delete prompt?": "Czy chcesz usunąć prompt?", - "delete this link": "usuń to połączenie", + "Delete prompt?": "Usunąć prompt?", + "delete this link": "usuń ten link", "Delete tool?": "Usunąć narzędzie?", "Delete User": "Usuń użytkownika", - "Deleted {{deleteModelTag}}": "Usunieto {{deleteModelTag}}", - "Deleted {{name}}": "Usunięto użytkownika {{name}}", + "Deleted {{deleteModelTag}}": "Usunięto {{deleteModelTag}}", + "Deleted {{name}}": "Usunięto {{name}}", "Deleted User": "Usunięty użytkownik", - "Deployment names are required for Azure OpenAI": "", - "Desc": "", - "Describe your knowledge base and objectives": "Opisz swoją bazę wiedzy i cele", + "Deployment names are required for Azure OpenAI": "Nazwy wdrożeń są wymagane dla Azure OpenAI", + "Desc": "Opis", + "Describe your knowledge base and objectives": "Opisz bazę wiedzy i cele", "Description": "Opis", - "Detect Artifacts Automatically": "", - "Dictate": "", - "Didn't fully follow instructions": "Nie wykonał w pełni instrukcji", - "Direct": "", + "Detect Artifacts Automatically": "Wykrywaj artefakty automatycznie", + "Dictate": "Dyktuj", + "Didn't fully follow instructions": "Nie w pełni wykonał instrukcje", + "Direct": "Bezpośredni", "Direct Connections": "Połączenia bezpośrednie", - "Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "Połączenia bezpośrednie umożliwiają użytkownikom łączenie się z własnymi końcówkami API kompatybilnymi z OpenAI.", - "Direct Message": "", - "Direct Tool Servers": "", - "Directory selection was cancelled": "", - "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.": "", - "Disabled": "Wyłączony", - "Discover a function": "Odkrywaj funkcję", - "Discover a model": "Odkrywaj model", - "Discover a prompt": "Odkrywaj prompty", - "Discover a tool": "Odkrywaj narzędzia", - "Discover how to use Open WebUI and seek support from the community.": "Odkryj, jak korzystać z Open WebUI i szukaj wsparcia w społeczności.", + "Direct Connections allow users to connect to their own OpenAI compatible API endpoints.": "Połączenia bezpośrednie pozwalają użytkownikom łączyć się z własnymi API kompatybilnymi z OpenAI.", + "Direct Message": "Wiadomość prywatna", + "Direct Tool Servers": "Bezpośrednie serwery narzędzi", + "Directory selection was cancelled": "Anulowano wybór katalogu", + "Disable Code Interpreter": "Wyłącz interpreter kodu", + "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 Fałsz.", + "Disabled": "Wyłączone", + "Discover a function": "Odkryj funkcję", + "Discover a model": "Odkryj model", + "Discover a prompt": "Odkryj prompt", + "Discover a tool": "Odkryj narzędzie", + "Discover how to use Open WebUI and seek support from the community.": "Odkryj jak używać Open WebUI i szukaj wsparcia społeczności.", "Discover wonders": "Odkrywaj cuda", - "Discover, download, and explore custom functions": "Odkryj, pobierz i eksploruj niestandardowe funkcje", - "Discover, download, and explore custom prompts": "Odkryj, pobierz i eksploruj niestandardowe prompty", - "Discover, download, and explore custom tools": "Odkryj, pobierz i eksploruj niestandardowe narzędzia", - "Discover, download, and explore model presets": "Odkryj, pobierz i badaj ustawienia modeli", - "Discussion channel where access is based on groups and permissions": "", - "Display": "Wyświetl", - "Display chat title in tab": "", - "Display Emoji in Call": "Wyświetl emoji w połączeniu", - "Display Multi-model Responses in Tabs": "", - "Display the username instead of You in the Chat": "Wyświetl nazwę użytkownika zamiast 'You' w czacie.", - "Displays citations in the response": "Wyświetla cytowania w odpowiedzi", - "Displays status updates (e.g., web search progress) in the response": "", + "Discover, download, and explore custom functions": "Odkrywaj, pobieraj i eksploruj własne funkcje", + "Discover, download, and explore custom prompts": "Odkrywaj, pobieraj i eksploruj własne prompty", + "Discover, download, and explore custom tools": "Odkrywaj, pobieraj i eksploruj własne narzędzia", + "Discover, download, and explore model presets": "Odkrywaj, pobieraj i eksploruj ustawienia modeli", + "Discussion channel where access is based on groups and permissions": "Kanał dyskusyjny z dostępem opartym na grupach", + "Display": "Wyświetlanie", + "Display chat title in tab": "Pokaż tytuł czatu w karcie", + "Display Emoji in Call": "Pokaż emoji w wywołaniu", + "Display Multi-model Responses in Tabs": "Pokaż odpowiedzi multimodalne w kartach", + "Display the username instead of You in the Chat": "Pokaż nazwę użytkownika zamiast 'Ty' w czacie", + "Displays citations in the response": "Wyświetla cytaty w odpowiedzi", + "Displays status updates (e.g., web search progress) in the response": "Wyświetla statusy (np. postęp wyszukiwania) w odpowiedzi", "Dive into knowledge": "Zanurz się w wiedzy", - "Do not install functions from sources you do not fully trust.": "Nie instaluj funkcji ze źródeł, którym nie ufasz w pełni.", - "Do not install tools from sources you do not fully trust.": "Nie instaluj narzędzi ze źródeł, którym nie ufasz w pełni.", - "Docling": "", - "Docling Parameters": "", - "Docling Server URL required.": "", + "Do not install functions from sources you do not fully trust.": "Nie instaluj funkcji z niezaufanych źródeł.", + "Do not install tools from sources you do not fully trust.": "Nie instaluj narzędzi z niezaufanych źródeł.", + "Docling": "Docling", + "Docling Parameters": "Parametry Docling", + "Docling Server URL required.": "Wymagany URL serwera Docling.", "Document": "Dokument", - "Document Intelligence": "", - "Document Intelligence endpoint required.": "", - "Document Intelligence Model": "", + "Document Intelligence": "Document Intelligence", + "Document Intelligence endpoint required.": "Wymagany endpoint Document Intelligence.", + "Document Intelligence Model": "Model Document Intelligence", "Documentation": "Dokumentacja", "Documents": "Dokumenty", - "does not make any external connections, and your data stays securely on your locally hosted server.": "nie nawiązuje żadnych zewnętrznych połączeń, a Twoje dane pozostają bezpiecznie na Twoim lokalnie hostowanym serwerze.", - "Domain Filter List": "Lista filtrów domeny", - "don't fetch random pipelines from sources you don't trust.": "Nie pobieraj losowych pipelines ze źródeł, którym nie ufasz.", + "does not make any external connections, and your data stays securely on your locally hosted server.": "nie nawiązuje połączeń zewnętrznych, a Twoje dane zostają lokalnie.", + "Domain Filter List": "Lista filtrowania domen", + "don't fetch random pipelines from sources you don't trust.": "nie pobieraj pipeline'ów z niezaufanych źródeł.", "Don't have an account?": "Nie masz konta?", - "don't install random functions from sources you don't trust.": "Nie instaluj losowych funkcji z niezaufanych źródeł.", - "don't install random tools from sources you don't trust.": "Nie instaluj przypadkowych narzędzi z niezaufanych źródeł.", - "Don't like the style": "Nie przypadł mi do gustu styl", - "Done": "Wykonano", - "Download": "Pobieranie", + "don't install random functions from sources you don't trust.": "nie instaluj funkcji z niezaufanych źródeł.", + "don't install random tools from sources you don't trust.": "nie instaluj narzędzi z niezaufanych źródeł.", + "Don't like the style": "Nie podoba mi się styl", + "Done": "Gotowe", + "Download": "Pobierz", "Download & Delete": "Pobierz i usuń", "Download as SVG": "Pobierz jako SVG", "Download canceled": "Pobieranie anulowane", "Download Database": "Pobierz bazę danych", "Draw": "Rysuj", - "Drop any files here to upload": "", - "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "np. '30s', '10m'. Poprawne jednostki czasu to: 's' (sekunda), 'm' (minuta), 'h' (godzina).", - "e.g. \"json\" or a JSON schema": "", - "e.g. 60": "", - "e.g. A filter to remove profanity from text": "np. Filtr do usuwania wulgaryzmów z tekstu", - "e.g. about the Roman Empire": "", - "e.g. en": "", - "e.g. My Filter": "np. Mój filtr", - "e.g. My Tools": "np. Moje narzędzia", + "Drop any files here to upload": "Upuść pliki tutaj, aby przesłać", + "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "np. '30s','10m'. Jednostki: 's' (sek), 'm' (min), 'h' (godz).", + "e.g. \"json\" or a JSON schema": "np. \"json\" lub schemat JSON", + "e.g. 60": "np. 60", + "e.g. A filter to remove profanity from text": "np. Filtr usuwający wulgaryzmy", + "e.g. about the Roman Empire": "np. o Imperium Rzymskim", + "e.g. en": "np. pl", + "e.g. My Filter": "np. Mój Filtr", + "e.g. My Tools": "np. Moje Narzędzia", "e.g. my_filter": "np. moj_filtr", - "e.g. my_tools": "np. moje_narzędzia", - "e.g. pdf, docx, txt": "", - "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": "np. Narzędzia do wykonywania różnych operacji", - "e.g., 3, 4, 5 (leave blank for default)": "np. 3, 4, 5 (zostaw puste dla domyślnego)", - "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. my_tools": "np. moje_narzedzia", + "e.g. pdf, docx, txt": "np. pdf, docx, txt", + "e.g. Tell me a fun fact": "np. Powiedz mi ciekawostkę", + "e.g. Tell me a fun fact about the Roman Empire": "np. Powiedz mi ciekawostkę o Imperium Rzymskim", + "e.g. Tools for performing various operations": "np. Narzędzia do różnych operacji", + "e.g., 3, 4, 5 (leave blank for default)": "np. 3, 4, 5 (zostaw puste dla domyślnych)", + "e.g., audio/wav,audio/mpeg,video/* (leave blank for defaults)": "np. audio/wav,audio/mpeg,video/* (zostaw puste dla domyślnych)", + "e.g., en-US,ja-JP (leave blank for auto-detect)": "np. pl-PL,en-US (zostaw puste dla auto-wykrywania)", + "e.g., westus (leave blank for eastus)": "np. westus (zostaw puste dla eastus)", "Edit": "Edytuj", - "Edit Arena Model": "Edytuj model arenę", + "Edit Arena Model": "Edytuj model Arena", "Edit Channel": "Edytuj kanał", "Edit Connection": "Edytuj połączenie", "Edit Default Permissions": "Edytuj domyślne uprawnienia", "Edit Folder": "Edytuj folder", - "Edit Image": "", - "Edit Last Message": "", + "Edit Image": "Edytuj obraz", + "Edit Last Message": "Edytuj ostatnią wiadomość", "Edit Memory": "Edytuj pamięć", "Edit User": "Edytuj profil użytkownika", - "Edit User Group": "Edytuj grupa użytkowników", - "Edit workflow.json content": "", - "edited": "", - "Edited": "", - "Editing": "", - "Eject": "Usuń model z pamięci", + "Edit User Group": "Edytuj grupę użytkowników", + "Edit workflow.json content": "Edytuj treść workflow.json", + "edited": "edytowano", + "Edited": "Edytowano", + "Editing": "Edytowanie", + "Eject": "Wysuń (Odładuj)", "ElevenLabs": "ElevenLabs", "Email": "Email", - "Embark on adventures": "Wyruszaj na przygody", - "Embedding": "", - "Embedding Batch Size": "Rozmiar partii wstępnego przetwarzania", - "Embedding Model": "Model osadzania", - "Embedding Model Engine": "Silnik modelu osadzania", - "Enable API Keys": "", - "Enable autocomplete generation for chat messages": "Włącz generowanie autouzupełniania dla wiadomości czatu", + "Embark on adventures": "Wyrusz na przygodę", + "Embedding": "Embedding", + "Embedding Batch Size": "Embedding Batch Size", + "Embedding Model": "Model embeddingów", + "Embedding Model Engine": "Silnik modelu embeddingów", + "Enable API Keys": "Włącz klucze API", + "Enable autocomplete generation for chat messages": "Włącz autouzupełnianie w czacie", "Enable Code Execution": "Włącz wykonywanie kodu", "Enable Code Interpreter": "Włącz interpreter kodu", - "Enable Community Sharing": "Włączanie udostępniania społecznościowego", - "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.": "Włącz blokowanie pamięci (mlock), aby zapobiec swappingowi danych modelu z RAM. Ta opcja blokuje zbiór stron roboczych modelu w RAM, co gwarantuje, że nie będą one wymieniane na dysk. Może to pomóc w utrzymaniu wydajności poprzez unikanie błędów strony i zapewnienie szybkiego dostępu do danych.", - "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.": "Włącz mapowanie pamięci (mmap), aby załadować dane modelu. Ta opcja pozwala systemowi traktować pliki dysku jako rozszerzenie RAM, co może poprawić wydajność modelu przez umożliwienie szybszego dostępu do danych. Należy jednak pamiętać, że ta funkcja może nie działać poprawnie ze wszystkimi systemami i zużywać znaczną ilość przestrzeni dyskowej.", + "Enable Community Sharing": "Włącz udostępnianie społecznościowe", + "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.": "Włącz mlock (blokowanie pamięci), aby trzymać model w RAM. Zapobiega to używaniu dysku (swap) i zwiększa wydajność.", + "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.": "Włącz mmap (mapowanie pamięci). Pozwala używać dysku jako rozszerzenia RAM. Może przyspieszyć ładowanie, ale zużywa dużo miejsca na dysku.", "Enable Message Rating": "Włącz ocenianie wiadomości", - "Enable Mirostat sampling for controlling perplexity.": "", - "Enable New Sign Ups": "Włącz nowe rejestracje", - "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 Mirostat sampling for controlling perplexity.": "Włącz próbkowanie Mirostat do kontroli perplexity.", + "Enable New Sign Ups": "Zezwól na nowe rejestracje", + "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.": "Włącz, wyłącz lub dostosuj tagi reasoning (rozumowania). \"Włączone\" używa domyślnych, \"Wyłączone\" usuwa je, \"Własne\" pozwala zdefiniować tagi start/koniec.", "Enabled": "Włączone", - "End Tag": "", - "Endpoint URL": "", - "Enforce Temporary Chat": "", - "Enhance": "", - "Enrich Hybrid Search Text": "", - "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Upewnij się, że twój plik CSV zawiera dokładnie 4 kolumny w następującej kolejności: Nazwa, Email, Hasło, Rola.", - "Enter {{role}} message here": "Wprowadź komunikat dla {{role}} tutaj", - "Enter a detail about yourself for your LLMs to recall": "Podaj informacje o sobie, aby LLMs mogły je przypomnieć.", - "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 api auth string (e.g. username:password)": "Wprowadź ciąg uwierzytelniania API (np. nazwa użytkownika:hasło)", - "Enter Application DN": "Wprowadź nazwę konta technicznego - Format DN", - "Enter Application DN Password": "Wprowadź hasło do konta technicznego", - "Enter Bing Search V7 Endpoint": "Wprowadź endpoint wyszukiwania Bing V7", + "End Tag": "Tag końcowy", + "Endpoint URL": "URL punktu końcowego", + "Enforce Temporary Chat": "Wymuś czat tymczasowy", + "Enhance": "Ulepsz", + "Enrich Hybrid Search Text": "Wzbogać tekst wyszukiwania hybrydowego", + "Ensure your CSV file includes 4 columns in this order: Name, Email, Password, Role.": "Upewnij się, że plik CSV ma 4 kolumny: Nazwa, Email, Hasło, Rola.", + "Enter {{role}} message here": "Wpisz wiadomość roli {{role}} tutaj", + "Enter a detail about yourself for your LLMs to recall": "Wpisz szczegóły o sobie, aby LLM je zapamiętał", + "Enter a title for the pending user info overlay. Leave empty for default.": "Wpisz tytuł ekranu oczekującego użytkownika. Zostaw puste dla domyślnego.", + "Enter a watermark for the response. Leave empty for none.": "Wpisz znak wodny odpowiedzi. Zostaw puste dla braku.", + "Enter additional headers in JSON format": "Wprowadź dodatkowe nagłówki (JSON)", + "Enter additional headers in JSON format (e.g. {\"X-Custom-Header\": \"value\"}": "Wprowadź nagłówki w JSON (np. {\"X-Custom-Header\": \"value\"})", + "Enter additional parameters in JSON format": "Wprowadź dodatkowe parametry (JSON)", + "Enter api auth string (e.g. username:password)": "Wprowadź ciąg auth API (np. user:pass)", + "Enter Application DN": "Wprowadź DN aplikacji", + "Enter Application DN Password": "Wprowadź hasło DN aplikacji", + "Enter Bing Search V7 Endpoint": "Wprowadź endpoint Bing Search V7", "Enter Bing Search V7 Subscription Key": "Wprowadź klucz subskrypcji Bing Search V7", "Enter Bocha Search API Key": "Wprowadź klucz API Bocha Search", "Enter Brave Search API Key": "Wprowadź klucz API Brave Search", - "Enter certificate path": "Wprowadź ścieżkę do certyfikatu", - "Enter Chunk Overlap": "Wprowadź nakładanie się bloków", - "Enter Chunk Size": "Wprowadź wielkość bloku", - "Enter comma-separated \"token:bias_value\" pairs (example: 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 certificate path": "Wprowadź ścieżkę certyfikatu", + "Enter Chunk Overlap": "Wprowadź Chunk Overlap", + "Enter Chunk Size": "Wprowadź Chunk Size", + "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Wprowadź pary \"token:bias\" po przecinku (np. 5432:100, 413:-100)", + "Enter content for the pending user info overlay. Leave empty for default.": "Wprowadź treść ekranu oczekiwania. Zostaw puste dla domyślnej.", + "Enter coordinates (e.g. 51.505, -0.09)": "Wprowadź współrzędne (np. 51.505, -0.09)", + "Enter Datalab Marker API Base URL": "Wprowadź Base URL Datalab Marker API", + "Enter Datalab Marker API Key": "Wprowadź klucz API Datalab Marker", "Enter description": "Wprowadź opis", - "Enter Docling API Key": "", - "Enter Docling Server URL": "", - "Enter Document Intelligence Endpoint": "", - "Enter Document Intelligence Key": "", - "Enter Document Intelligence Model": "", - "Enter domains separated by commas (e.g., example.com,site.org,!excludedsite.com)": "", + "Enter Docling API Key": "Wprowadź klucz API Docling", + "Enter Docling Server URL": "Wprowadź URL serwera Docling", + "Enter Document Intelligence Endpoint": "Wprowadź endpoint Document Intelligence", + "Enter Document Intelligence Key": "Wprowadź klucz Document Intelligence", + "Enter Document Intelligence Model": "Wprowadź model Document Intelligence", + "Enter domains separated by commas (e.g., example.com,site.org,!excludedsite.com)": "Wprowadź domeny po przecinku (np. example.com,!exclude.com)", "Enter Exa API Key": "Wprowadź klucz API Exa", - "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 External Document Loader API Key": "Wprowadź klucz API External Document Loader", + "Enter External Document Loader URL": "Wprowadź URL External Document Loader", + "Enter External Web Loader API Key": "Wprowadź klucz API External Web Loader", + "Enter External Web Loader URL": "Wprowadź URL External Web Loader", + "Enter External Web Search API Key": "Wprowadź klucz API External Web Search", + "Enter External Web Search URL": "Wprowadź URL External Web Search", + "Enter Firecrawl API Base URL": "Wprowadź Base URL Firecrawl API", + "Enter Firecrawl API Key": "Wprowadź klucz API Firecrawl", "Enter folder name": "Wprowadź nazwę folderu", - "Enter function name filter list (e.g. func1, !func2)": "", - "Enter Github Raw URL": "Wprowadź surowy adres URL usługi GitHub", + "Enter function name filter list (e.g. func1, !func2)": "Wprowadź listę filtrów funkcji (np. func1, !func2)", + "Enter Github Raw URL": "Wprowadź Github Raw URL", "Enter Google PSE API Key": "Wprowadź klucz API Google PSE", - "Enter Google PSE Engine Id": "Wprowadź identyfikator urządzenia Google PSE", - "Enter hex color (e.g. #FF0000)": "", - "Enter ID": "", - "Enter Image Size (e.g. 512x512)": "Podaj rozmiar obrazu (np. 512x512)", - "Enter Jina API Key": "Wprowadź klucz API Jiny", - "Enter JSON config (e.g., {\"disable_links\": true})": "", + "Enter Google PSE Engine Id": "Wprowadź ID silnika Google PSE", + "Enter hex color (e.g. #FF0000)": "Wprowadź kolor hex (np. #FF0000)", + "Enter ID": "Wprowadź ID", + "Enter Image Size (e.g. 512x512)": "Wprowadź rozmiar obrazu (np. 512x512)", + "Enter Jina API Key": "Wprowadź klucz API Jina", + "Enter JSON config (e.g., {\"disable_links\": true})": "Wprowadź konfigurację JSON (np. {\"disable_links\": true})", "Enter Jupyter Password": "Wprowadź hasło Jupyter", "Enter Jupyter Token": "Wprowadź token Jupyter", - "Enter Jupyter URL": "Podaj adres URL Jupytera", - "Enter Kagi Search API Key": "Wprowadź klucz wyszukiwania Kagi", + "Enter Jupyter URL": "Wprowadź URL Jupyter", + "Enter Kagi Search API Key": "Wprowadź klucz API Kagi Search", "Enter Key Behavior": "Zachowanie klawisza Enter", "Enter language codes": "Wprowadź kody języków", - "Enter Mistral API Base URL": "", - "Enter Mistral API Key": "", + "Enter Mistral API Base URL": "Wprowadź Base URL Mistral API", + "Enter Mistral API Key": "Wprowadź klucz API Mistral", "Enter Model ID": "Wprowadź ID modelu", - "Enter model tag (e.g. {{modelTag}})": "Wprowadź znacznik modelu (np. {{modelTag}})", + "Enter model tag (e.g. {{modelTag}})": "Wprowadź tag modelu (np. {{modelTag}})", "Enter Mojeek Search API Key": "Wprowadź klucz API Mojeek Search", - "Enter name": "", - "Enter New Password": "", - "Enter Number of Steps (e.g. 50)": "Podaj liczbę kroków (np. 50)", - "Enter Ollama Cloud API Key": "", - "Enter Perplexity API Key": "Klucz API Perplexity", - "Enter Perplexity Search API URL": "", - "Enter Playwright Timeout": "", - "Enter Playwright WebSocket URL": "", - "Enter proxy URL (e.g. https://user:password@host:port)": "Podaj adres URL proxy (np. https://user:password@host:port)", - "Enter reasoning effort": "Podaj powód wysiłku", - "Enter Score": "Wprowadź wynik", + "Enter name": "Wprowadź nazwę", + "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 Perplexity API Key": "Wprowadź klucz API Perplexity", + "Enter Perplexity Search API URL": "Wprowadź URL API Perplexity Search", + "Enter Playwright Timeout": "Wprowadź timeout Playwright", + "Enter Playwright WebSocket URL": "Wprowadź URL WebSocket Playwright", + "Enter proxy URL (e.g. https://user:password@host:port)": "Wprowadź URL proxy (np. https://user:pass@host:port)", + "Enter reasoning effort": "Wprowadź Reasoning Effort", + "Enter Score": "Wprowadź wynik (Score)", "Enter SearchApi API Key": "Wprowadź klucz API SearchApi", - "Enter SearchApi Engine": "Wprowadź zapytanie do silnika wyszukiwania SearchApi", - "Enter Searxng Query URL": "Wprowadź adres URL zapytania wyszukiwania Searxng", - "Enter Searxng search language": "", + "Enter SearchApi Engine": "Wprowadź silnik SearchApi", + "Enter Searxng Query URL": "Wprowadź URL zapytania Searxng", + "Enter Searxng search language": "Wprowadź język wyszukiwania Searxng", "Enter Seed": "Wprowadź Seed", "Enter SerpApi API Key": "Wprowadź klucz API SerpApi", "Enter SerpApi Engine": "Wprowadź silnik SerpApi", "Enter Serper API Key": "Wprowadź klucz API Serper", "Enter Serply API Key": "Wprowadź klucz API Serply", "Enter Serpstack API Key": "Wprowadź klucz API Serpstack", - "Enter server host": "Wprowadź nazwę hosta serwera", + "Enter server host": "Wprowadź host serwera", "Enter server label": "Wprowadź etykietę serwera", - "Enter server port": "Wprowadź numer portu serwera", - "Enter Sougou Search API sID": "", - "Enter Sougou Search API SK": "", + "Enter server port": "Wprowadź port serwera", + "Enter Sougou Search API sID": "Wprowadź sID Sougou Search API", + "Enter Sougou Search API SK": "Wprowadź SK Sougou Search API", "Enter stop sequence": "Wprowadź sekwencję stop", "Enter system prompt": "Wprowadź prompt systemowy", - "Enter system prompt here": "", + "Enter system prompt here": "Wprowadź prompt systemowy tutaj", "Enter Tavily API Key": "Wprowadź klucz API Tavily", - "Enter Tavily Extract Depth": "", - "Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Wprowadź publiczny adres URL Twojego WebUI. Ten adres URL zostanie użyty do generowania linków w powiadomieniach.", - "Enter the URL of the function to import": "", - "Enter the URL to import": "", - "Enter Tika Server URL": "Wprowadź adres URL serwera Tika", - "Enter timeout in seconds": "", - "Enter to Send": "Enter aby wysłać", - "Enter Top K": "Wprowadź {Top K}", - "Enter Top K Reranker": "", - "Enter URL (e.g. http://127.0.0.1:7860/)": "Podaj adres URL (np. http://127.0.0.1:7860/)", - "Enter URL (e.g. http://localhost:11434)": "Wprowadź adres URL (np. 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 your code here...": "Wpisz tutaj swój kod...", - "Enter your current password": "Wprowadź swoje aktualne hasło", - "Enter Your Email": "Podaj swój adres e-mail", - "Enter Your Full Name": "Podaj swoje pełne imię i nazwisko", - "Enter your gender": "", - "Enter your message": "Wprowadź swój komunikat", - "Enter your name": "", - "Enter Your Name": "", + "Enter Tavily Extract Depth": "Wprowadź Tavily Extract Depth", + "Enter the public URL of your WebUI. This URL will be used to generate links in the notifications.": "Wprowadź publiczny URL Twojego WebUI. Używany w powiadomieniach.", + "Enter the URL of the function to import": "Wprowadź URL funkcji do zaimportowania", + "Enter the URL to import": "Wprowadź URL do zaimportowania", + "Enter Tika Server URL": "Wprowadź URL serwera Tika", + "Enter timeout in seconds": "Wprowadź limit czasu w sekundach", + "Enter to Send": "Enter wysyła", + "Enter Top K": "Wprowadź Top K", + "Enter Top K Reranker": "Wprowadź Top K Reranker", + "Enter URL (e.g. http://127.0.0.1:7860/)": "Wprowadź URL (np. http://127.0.0.1:7860/)", + "Enter URL (e.g. http://localhost:11434)": "Wprowadź URL (np. http://localhost:11434)", + "Enter value": "Wprowadź wartość", + "Enter value (true/false)": "Wprowadź wartość (true/false)", + "Enter Yacy Password": "Wprowadź hasło Yacy", + "Enter Yacy URL (e.g. http://yacy.example.com:8090)": "Wprowadź URL Yacy (np. http://yacy.example.com:8090)", + "Enter Yacy Username": "Wprowadź nazwę użytkownika Yacy", + "Enter your code here...": "Wprowadź swój kod tutaj...", + "Enter your current password": "Wprowadź obecne hasło", + "Enter Your Email": "Wprowadź swój email", + "Enter Your Full Name": "Wprowadź pełne imię i nazwisko", + "Enter your gender": "Wprowadź płeć", + "Enter your message": "Wpisz wiadomość", + "Enter your name": "Wprowadź imię", + "Enter Your Name": "Wprowadź imię", "Enter your new password": "Wprowadź nowe hasło", - "Enter Your Password": "Wprowadź swoje hasło", - "Enter Your Role": "Podaj swoją rolę", - "Enter Your Username": "Podaj swoją nazwę użytkownika", - "Enter your webhook URL": "Podaj adres URL swojego webhooka", - "Entra ID": "", + "Enter Your Password": "Wprowadź hasło", + "Enter Your Role": "Wprowadź rolę", + "Enter Your Username": "Wprowadź nazwę użytkownika", + "Enter your webhook URL": "Wprowadź URL webhooka", + "Entra ID": "Entra ID", "Error": "Błąd", "ERROR": "BŁĄD", - "Error accessing directory": "", - "Error accessing Google Drive: {{error}}": "Błąd podczas dostępu do Google Drive: {{error}}", - "Error accessing media devices.": "", - "Error starting recording.": "", - "Error unloading model: {{error}}": "", - "Error uploading file: {{error}}": "Błąd podczas przesyłania pliku: {{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.": "", - "Evaluations": "Oceny", - "Everyone": "Każdy", + "Error accessing directory": "Błąd dostępu do katalogu", + "Error accessing Google Drive: {{error}}": "Błąd dostępu do Google Drive: {{error}}", + "Error accessing media devices.": "Błąd dostępu do urządzeń medialnych.", + "Error starting recording.": "Błąd podczas rozpoczynania nagrywania.", + "Error unloading model: {{error}}": "Błąd odładowywania modelu: {{error}}", + "Error uploading file: {{error}}": "Błąd przesyłania pliku: {{error}}", + "Error: A model with the ID '{{modelId}}' already exists. Please select a different ID to proceed.": "Błąd: Model o ID '{{modelId}}' już istnieje. Wybierz inne ID.", + "Error: Model ID cannot be empty. Please enter a valid ID to proceed.": "Błąd: ID modelu nie może być puste. Wprowadź poprawne ID.", + "Evaluations": "Ewaluacje", + "Everyone": "Wszyscy", "Exa API Key": "Klucz API Exa", "Example: (&(objectClass=inetOrgPerson)(uid=%s))": "Przykład: (&(objectClass=inetOrgPerson)(uid=%s))", "Example: ALL": "Przykład: ALL", "Example: mail": "Przykład: mail", "Example: ou=users,dc=foo,dc=example": "Przykład: ou=users,dc=foo,dc=example", "Example: sAMAccountName or uid or userPrincipalName": "Przykład: sAMAccountName lub uid lub userPrincipalName", - "Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "Przekroczono liczbę stanowisk w licencji. Skontaktuj się z pomocą techniczną, aby zwiększyć liczbę stanowisk.", - "Exclude": "Wykluczyć", + "Exceeded the number of seats in your license. Please contact support to increase the number of seats.": "Przekroczono liczbę stanowisk w licencji. Skontaktuj się ze wsparciem.", + "Exclude": "Wyklucz", "Execute code for analysis": "Wykonaj kod do analizy", - "Executing **{{NAME}}**...": "", - "Expand": "", + "Executing **{{NAME}}**...": "Wykonywanie **{{NAME}}**...", + "Expand": "Rozwiń", "Experimental": "Eksperymentalne", "Explain": "Wyjaśnij", - "Explore the cosmos": "Odkrywaj kosmos", - "Export": "Eksport", - "Export All Archived Chats": "Wyeksportuj wszystkie archiwalne rozmowy", - "Export All Chats (All Users)": "Eksportuj wszystkie rozmowy (wszyscy użytkownicy)", - "Export chat (.json)": "Eksport czatu (.json)", - "Export Chats": "Eksportuj rozmowy", - "Export Config to JSON File": "Eksportuj konfigurację do pliku JSON", - "Export Models": "", - "Export Presets": "Wyeksportuj ustawienia domyślne", - "Export Prompts": "", - "Export to CSV": "Eksport do CSV", - "Export Tools": "", - "Export Users": "", - "External": "", - "External Document Loader URL required.": "", - "External Task Model": "", - "External Tools": "", - "External Web Loader API Key": "", - "External Web Loader URL": "", - "External Web Search API Key": "", - "External Web Search URL": "", - "Fade Effect for Streaming Text": "", + "Explore the cosmos": "Eksploruj kosmos", + "Export": "Eksportuj", + "Export All Archived Chats": "Eksportuj wszystkie zarchiwizowane czaty", + "Export All Chats (All Users)": "Eksportuj wszystkie czaty (Wszyscy użytkownicy)", + "Export chat (.json)": "Eksportuj czat (.json)", + "Export Chats": "Eksportuj czaty", + "Export Config to JSON File": "Eksportuj konfigurację do JSON", + "Export Models": "Eksportuj modele", + "Export Presets": "Eksportuj ustawienia (Presets)", + "Export Prompts": "Eksportuj prompty", + "Export to CSV": "Eksportuj do CSV", + "Export Tools": "Eksportuj narzędzia", + "Export Users": "Eksportuj użytkowników", + "External": "Zewnętrzny", + "External Document Loader URL required.": "Wymagany URL External Document Loader.", + "External Task Model": "Zewnętrzny Model Zadaniowy", + "External Tools": "Narzędzia Zewnętrzne", + "External Web Loader API Key": "Klucz API External Web Loader", + "External Web Loader URL": "URL External Web Loader", + "External Web Search API Key": "Klucz API External Web Search", + "External Web Search URL": "URL External Web Search", + "Fade Effect for Streaming Text": "Efekt zanikania dla strumieniowanego tekstu", "Failed to add file.": "Nie udało się dodać pliku.", - "Failed to add members": "", - "Failed to clear status": "", - "Failed to connect to {{URL}} OpenAPI tool server": "", + "Failed to add members": "Nie udało się dodać członków", + "Failed to clear status": "Nie udało się wyczyścić statusu", + "Failed to connect to {{URL}} OpenAPI tool server": "Nie udało się połączyć z serwerem narzędzi OpenAPI {{URL}}", "Failed to copy link": "Nie udało się skopiować linku", - "Failed to create API Key.": "Nie udało się wygenerować klucza API.", + "Failed to create API Key.": "Nie udało się utworzyć klucza API.", "Failed to delete note": "Nie udało się usunąć notatki", - "Failed to extract content from the file: {{error}}": "", - "Failed to extract content from the file.": "", + "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.", "Failed to fetch models": "Nie udało się pobrać modeli", "Failed to generate title": "Nie udało się wygenerować tytułu", - "Failed to import models": "", - "Failed to load chat preview": "", + "Failed to import models": "Nie udało się zaimportować modeli", + "Failed to load chat preview": "Nie udało się załadować podglądu czatu", "Failed to load file content.": "Nie udało się załadować zawartości pliku.", - "Failed to move chat": "", - "Failed to process URL: {{url}}": "", - "Failed to read clipboard contents": "Nie udało się odczytać zawartości schowka", - "Failed to remove member": "", - "Failed to render diagram": "", - "Failed to render visualization": "", - "Failed to save connections": "Nie udałio się zapisać połączeń", + "Failed to move chat": "Nie udało się przenieść czatu", + "Failed to process URL: {{url}}": "Nie udało się przetworzyć URL: {{url}}", + "Failed to read clipboard contents": "Nie udało się odczytać schowka", + "Failed to remove member": "Nie udało się usunąć członka", + "Failed to render diagram": "Nie udało się wyrenderować diagramu", + "Failed to render visualization": "Nie udało się wyrenderować wizualizacji", + "Failed to save connections": "Nie udało się zapisać połączeń", "Failed to save conversation": "Nie udało się zapisać rozmowy", - "Failed to save models configuration": "Nie udało się zapisać konfiguracji modelu", + "Failed to save models configuration": "Nie udało się zapisać konfiguracji modeli", "Failed to update settings": "Nie udało się zaktualizować ustawień", - "Failed to update status": "", + "Failed to update status": "Nie udało się zaktualizować statusu", "Failed to upload file.": "Nie udało się przesłać pliku.", "Features": "Funkcje", - "Features Permissions": "Uprawnienia do funkcji", + "Features Permissions": "Uprawnienia funkcji", "February": "Luty", - "Feedback deleted successfully": "", - "Feedback Details": "", - "Feedback History": "Historia ocen", - "Feedbacks": "Oceny", - "Feel free to add specific details": "Nie krępuj się dodawać szczegółów", - "Female": "", + "Feedback deleted successfully": "Opinia usunięta pomyślnie", + "Feedback Details": "Szczegóły opinii", + "Feedback History": "Historia opinii", + "Feedbacks": "Opinie", + "Feel free to add specific details": "Możesz dodać szczegóły", + "Female": "Kobieta", "File": "Plik", "File added successfully.": "Plik dodany pomyślnie.", - "File content updated successfully.": "Plik został zaktualizowany pomyślnie.", + "File content updated successfully.": "Treść pliku zaktualizowana pomyślnie.", "File Mode": "Tryb pliku", - "File not found.": "Plik nie został znaleziony.", - "File removed successfully.": "Plik został usunięty pomyślnie.", - "File size should not exceed {{maxSize}} MB.": "Rozmiar pliku nie powinien przekraczać {{maxSize}} MB.", - "File Upload": "", - "File uploaded successfully": "Plik został pomyślnie przesłany", - "File uploaded!": "", + "File not found.": "Plik nie znaleziony.", + "File removed successfully.": "Plik usunięty pomyślnie.", + "File size should not exceed {{maxSize}} MB.": "Rozmiar pliku nie może przekraczać {{maxSize}} MB.", + "File Upload": "Przesyłanie plików", + "File uploaded successfully": "Plik przesłany pomyślnie", + "File uploaded!": "Plik przesłany!", "Files": "Pliki", "Filter": "Filtr", "Filter is now globally disabled": "Filtr jest teraz globalnie wyłączony", "Filter is now globally enabled": "Filtr jest teraz globalnie włączony", "Filters": "Filtry", - "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Wykryto próbę oszustwa z odciskiem palca: Nie można używać inicjałów jako awatara. Powrót do domyślnego obrazu profilowego.", - "Firecrawl API Base URL": "", - "Firecrawl API Key": "", - "Floating Quick Actions": "", - "Focus Chat Input": "", - "Folder": "", - "Folder Background Image": "", - "Folder deleted successfully": "Folder został usunięty pomyślnie", + "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Wykryto spoofing (Fingerprint): Nie można użyć inicjałów jako awatara. Używam domyślnego obrazka.", + "Firecrawl API Base URL": "Base URL Firecrawl API", + "Firecrawl API Key": "Klucz API Firecrawl", + "Floating Quick Actions": "Pływające szybkie akcje", + "Focus Chat Input": "Skupienie na polu czatu", + "Folder": "Folder", + "Folder Background Image": "Tło folderu", + "Folder deleted successfully": "Folder usunięty pomyślnie", "Folder Name": "Nazwa folderu", "Folder name cannot be empty.": "Nazwa folderu nie może być pusta.", - "Folder name updated successfully": "Nazwa folderu została zaktualizowana pomyślnie", - "Folder updated successfully": "", - "Folders": "", - "Follow up": "", - "Follow Up Generation": "", - "Follow Up Generation Prompt": "", - "Follow-Up Auto-Generation": "", - "Followed instructions perfectly": "Wykonał instrukcje idealnie", + "Folder name updated successfully": "Nazwa folderu zaktualizowana pomyślnie", + "Folder updated successfully": "Folder zaktualizowany pomyślnie", + "Folders": "Foldery", + "Follow up": "Kontynuacja", + "Follow Up Generation": "Generowanie pytań kontynuacyjnych", + "Follow Up Generation Prompt": "Prompt generowania kontynuacji", + "Follow-Up Auto-Generation": "Automatyczne generowanie kontynuacji", + "Followed instructions perfectly": "Instrukcje wykonane idealnie", "Force OCR": "Wymuś 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": "Wytyczaj nowe ścieżki", + "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.": "Wymuś OCR na wszystkich stronach PDF. Może pogorszyć wyniki, jeśli PDF ma już dobry tekst. Domyślnie Fałsz.", + "Forge new paths": "Wyznaczaj nowe ścieżki", "Form": "Formularz", - "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.": "", - "Format your variables using brackets like this:": "Sformatuj swoje zmienne, używając nawiasów w następujący sposób:", - "Formatting may be inconsistent from source.": "", - "Forwards system user OAuth access token to authenticate": "", - "Forwards system user session credentials to authenticate": "", + "Format Lines": "Formatuj linie", + "Format the lines in the output. Defaults to False. If set to True, the lines will be formatted to detect inline math and styles.": "Formatuj linie wyjścia (np. wykrywanie matematyki inline). Domyślnie Fałsz.", + "Format your variables using brackets like this:": "Formatuj zmienne używając klamer:", + "Formatting may be inconsistent from source.": "Formatowanie może różnić się od źródła.", + "Forwards system user OAuth access token to authenticate": "Przekazuje token dostępu OAuth użytkownika systemowego", + "Forwards system user session credentials to authenticate": "Przekazuje poświadczenia sesji użytkownika systemowego", "Full Context Mode": "Tryb pełnego kontekstu", "Function": "Funkcja", "Function Calling": "Wywoływanie funkcji", "Function created successfully": "Funkcja utworzona pomyślnie", - "Function deleted successfully": "Funkcja została usunięta pomyślnie", + "Function deleted successfully": "Funkcja usunięta pomyślnie", "Function Description": "Opis funkcji", - "Function ID": "Funkcja ID", - "Function imported successfully": "", + "Function ID": "ID Funkcji", + "Function imported successfully": "Funkcja zaimportowana pomyślnie", "Function is now globally disabled": "Funkcja jest teraz globalnie wyłączona", "Function is now globally enabled": "Funkcja jest teraz globalnie włączona", - "Function Name": "Nazwa Funkcji", - "Function Name Filter List": "", - "Function updated successfully": "Funkcja została zaktualizowana pomyślnie", + "Function Name": "Nazwa funkcji", + "Function Name Filter List": "Lista filtrów nazw funkcji", + "Function updated successfully": "Funkcja zaktualizowana pomyślnie", "Functions": "Funkcje", - "Functions allow arbitrary code execution.": "Funkcje umożliwiają wykonanie dowolnego kodu.", - "Functions imported successfully": "Funkcje zostały pomyślnie zaimportowane", + "Functions allow arbitrary code execution.": "Funkcje pozwalają na wykonywanie dowolnego kodu.", + "Functions imported successfully": "Funkcje zaimportowane pomyślnie", "Gemini": "Gemini", - "Gemini API Key": "", - "Gemini API Key is required.": "Wymagany jest klucz API Gemini.", - "Gemini Base URL": "", - "Gemini Endpoint Method": "", - "Gender": "", + "Gemini API Key": "Klucz API Gemini", + "Gemini API Key is required.": "Klucz API Gemini jest wymagany.", + "Gemini Base URL": "Base URL Gemini", + "Gemini Endpoint Method": "Metoda endpointu Gemini", + "Gender": "Płeć", "General": "Ogólne", - "Generate": "Wygeneruj", + "Generate": "Generuj", "Generate an image": "Wygeneruj obraz", - "Generate Image": "Wygeneruj obraz", - "Generate Message Pair": "", - "Generated Image": "", - "Generating search query": "Tworzenie zapytania wyszukiwania", + "Generate Image": "Generuj obraz", + "Generate Message Pair": "Generuj parę wiadomości", + "Generated Image": "Wygenerowany obraz", + "Generating search query": "Generowanie zapytania wyszukiwania", "Generating...": "Generowanie...", - "Get information on {{name}} in the UI": "", + "Get information on {{name}} in the UI": "Uzyskaj informacje o {{name}} w interfejsie", "Get started": "Rozpocznij", - "Get started with {{WEBUI_NAME}}": "Rozpocznij pracę z {{WEBUI_NAME}}", - "Global": "Globalny", + "Get started with {{WEBUI_NAME}}": "Rozpocznij z {{WEBUI_NAME}}", + "Global": "Globalne", "Good Response": "Dobra odpowiedź", - "Google Drive": "Dysk Google", + "Google Drive": "Google Drive", "Google PSE API Key": "Klucz API Google PSE", - "Google PSE Engine Id": "Identyfikator silnika Google PSE", - "Gravatar": "", - "Grid": "", + "Google PSE Engine Id": "ID silnika Google PSE", + "Gravatar": "Gravatar", + "Grid": "Siatka", "Group": "Grupa", - "Group Channel": "", + "Group Channel": "Kanał grupowy", "Group created successfully": "Grupa utworzona pomyślnie", - "Group deleted successfully": "Grupa została usunięta pomyślnie", + "Group deleted successfully": "Grupa usunięta pomyślnie", "Group Description": "Opis grupy", "Group Name": "Nazwa grupy", "Group updated successfully": "Grupa zaktualizowana pomyślnie", - "groups": "", + "groups": "grupy", "Groups": "Grupy", - "H1": "", - "H2": "", - "H3": "", - "Haptic Feedback": "Haptyczne sprzężenie zwrotne", - "Headers": "", - "Headers must be a valid JSON object": "", - "Height": "", + "H1": "H1", + "H2": "H2", + "H3": "H3", + "Haptic Feedback": "Wibracje (Haptic)", + "Headers": "Nagłówki", + "Headers must be a valid JSON object": "Nagłówki muszą być poprawnym obiektem JSON", + "Height": "Wysokość", "Hello, {{name}}": "Witaj, {{name}}", "Help": "Pomoc", - "Help us create the best community leaderboard by sharing your feedback history!": "Pomóż nam stworzyć najlepszą tablicę liderów społeczności, dzieląc się swoją historią opinii!", - "Hex Color": "Kolor heksadecymalny", - "Hex Color - Leave empty for default color": "Kolor heksadecymalny - pozostaw puste dla domyślnego koloru", + "Help us create the best community leaderboard by sharing your feedback history!": "Pomóż nam tworzyć ranking społeczności, udostępniając historię swoich opinii!", + "Hex Color": "Kolor Hex", + "Hex Color - Leave empty for default color": "Kolor Hex - zostaw puste dla domyślnego", "Hide": "Ukryj", - "Hide from Sidebar": "Ukryj z paska bocznego", + "Hide from Sidebar": "Ukryj w pasku bocznym", "Hide Model": "Ukryj model", - "High": "", - "High Contrast Mode": "", - "Home": "Dom", - "Host": "Serwer", - "How can I help you today?": "Jak mogę Ci dzisiaj pomóc?", - "How would you rate this response?": "Jak oceniłbyś tę odpowiedź?", - "HTML": "", - "http://localhost:8000": "", - "https://mineru.net/api/v4": "", + "High": "Wysoki", + "High Contrast Mode": "Tryb wysokiego kontrastu", + "Home": "Strona główna", + "Host": "Host", + "How can I help you today?": "W czym mogę pomóc?", + "How would you rate this response?": "Jak oceniasz tę odpowiedź?", + "HTML": "HTML", + "http://localhost:8000": "http://localhost:8000", + "https://mineru.net/api/v4": "https://mineru.net/api/v4", "Hybrid Search": "Wyszukiwanie hybrydowe", - "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.": "Potwierdzam, że przeczytałem i rozumiem konsekwencje mojego działania. Jestem świadomy ryzyka związanego z wykonywaniem kodu o nieznanym pochodzeniu i zweryfikowałem wiarygodność źródła.", + "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.": "Potwierdzam, że rozumiem konsekwencje. Jestem świadomy ryzyka wykonywania dowolnego kodu i zweryfikowałem zaufanie do źródła.", "ID": "ID", - "ID cannot contain \":\" or \"|\" characters": "", - "iframe Sandbox Allow Forms": "", - "iframe Sandbox Allow Same Origin": "", - "Ignite curiosity": "Rozbudź ciekawość", + "ID cannot contain \":\" or \"|\" characters": "ID nie może zawierać \":\" ani \"|\"", + "iframe Sandbox Allow Forms": "iframe Sandbox Allow Forms", + "iframe Sandbox Allow Same Origin": "iframe Sandbox Allow Same Origin", + "Ignite curiosity": "Rozpal ciekawość", "Image": "Obraz", "Image Compression": "Kompresja obrazu", - "Image Compression Height": "", - "Image Compression Width": "", - "Image Edit": "", - "Image Edit Engine": "", - "Image Generation": "Generowanie obrazów", - "Image Generation Engine": "Silnik generowania obrazów", - "Image Max Compression Size": "Maksymalny rozmiar kompresji obrazu", - "Image Max Compression Size height": "", - "Image Max Compression Size width": "", - "Image Prompt Generation": "Generowanie promptu obrazu", - "Image Prompt Generation Prompt": "Prompt do generowania obrazów", - "Image Size": "", + "Image Compression Height": "Wysokość kompresji obrazu", + "Image Compression Width": "Szerokość kompresji obrazu", + "Image Edit": "Edycja obrazu", + "Image Edit Engine": "Silnik edycji obrazu", + "Image Generation": "Generowanie obrazu", + "Image Generation Engine": "Silnik generowania obrazu", + "Image Max Compression Size": "Maksymalny rozmiar kompresji", + "Image Max Compression Size height": "Maks. wysokość kompresji", + "Image Max Compression Size width": "Maks. szerokość kompresji", + "Image Prompt Generation": "Generowanie promptu dla obrazu", + "Image Prompt Generation Prompt": "Prompt generujący prompt dla obrazu", + "Image Size": "Rozmiar obrazu", "Images": "Obrazy", - "Import": "", + "Import": "Importuj", "Import Chats": "Importuj czaty", - "Import Config from JSON File": "Importuj konfigurację z pliku JSON", + "Import Config from JSON File": "Importuj konfigurację z JSON", "Import From Link": "Importuj z linku", - "Import Models": "", - "Import Presets": "Importuj ustawienia", - "Import Prompts": "", - "Import successful": "", - "Import Tools": "", + "Import Models": "Importuj modele", + "Import Presets": "Importuj ustawienia (Presets)", + "Import Prompts": "Importuj prompty", + "Import successful": "Import udany", + "Import Tools": "Importuj narzędzia", "Important Update": "Ważna aktualizacja", - "Include": "Włączyć", - "Include `--api-auth` flag when running stable-diffusion-webui": "Użyj flagi `--api-auth` podczas uruchamiania stable-diffusion-webui", - "Include `--api` flag when running stable-diffusion-webui": "Użyj flagi `--api` podczas uruchamiania stable-diffusion-webui.", + "Include": "Dołącz", + "Include `--api-auth` flag when running stable-diffusion-webui": "Dodaj flagę `--api-auth` uruchamiając stable-diffusion-webui", + "Include `--api` flag when running stable-diffusion-webui": "Dodaj flagę `--api` uruchamiając stable-diffusion-webui", "Includes SharePoint": "Zawiera SharePoint", - "Increase UI Scale": "", - "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": "Informacje", - "Initials": "", - "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 Variables": "", - "Insert": "", - "Insert Follow-Up Prompt to Input": "", - "Insert Prompt as Rich Text": "", - "Insert Suggestion Prompt to Input": "", - "Install from Github URL": "Instalacja z adresu URL serwisu Github", - "Instant Auto-Send After Voice Transcription": "Automatyczne natychmiastowe wysyłanie po transkrypcji głosowej", - "Integration": "", - "Integrations": "", + "Increase UI Scale": "Zwiększ skalę 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.": "Wpływa na szybkość reakcji algorytmu na feedback. Niższy 'learning rate' to wolniejsze zmiany, wyższy to szybsza reakcja.", + "Info": "Info", + "Initials": "Inicjały", + "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Wstrzyknij całą treść jako kontekst (zalecane dla złożonych zapytań).", + "Input": "Wejście", + "Input Key (e.g. text, unet_name, steps)": "Klucz wejściowy (np. text, unet_name, steps)", + "Input Variables": "Zmienne wejściowe", + "Insert": "Wstaw", + "Insert Follow-Up Prompt to Input": "Wstaw prompt kontynuacji do wejścia", + "Insert Prompt as Rich Text": "Wstaw prompt jako Rich Text", + "Insert Suggestion Prompt to Input": "Wstaw sugerowany prompt do wejścia", + "Install from Github URL": "Zainstaluj z URL Githuba", + "Instant Auto-Send After Voice Transcription": "Natychmiastowe wysyłanie po transkrypcji głosu", + "Integration": "Integracja", + "Integrations": "Integracje", "Interface": "Interfejs", "Invalid file content": "Nieprawidłowa zawartość pliku", "Invalid file format.": "Nieprawidłowy format pliku.", "Invalid JSON file": "Nieprawidłowy plik 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 in Additional Config": "", - "Invalid JSON format in MinerU Parameters": "", + "Invalid JSON format for ComfyUI Edit Workflow.": "Błędny format JSON dla ComfyUI Edit Workflow.", + "Invalid JSON format for ComfyUI Workflow.": "Błędny format JSON dla ComfyUI Workflow.", + "Invalid JSON format for Parameters": "Błędny format JSON dla parametrów", + "Invalid JSON format in {{NAME}}": "Błędny format JSON w {{NAME}}", + "Invalid JSON format in Additional Config": "Błędny format JSON w Dodatkowej konfiguracji", + "Invalid JSON format in MinerU Parameters": "Błędny format JSON w parametrach MinerU", "Invalid Tag": "Nieprawidłowy tag", - "is typing...": "Pisanie...", - "Italic": "Pochylenie", + "is typing...": "pisze...", + "Italic": "Kursywa", "January": "Styczeń", - "Jina API Key": "Klucz API Jiny", - "join our Discord for help.": "Dołącz do naszego Discorda, aby uzyskać pomoc.", + "Jina API Key": "Klucz API Jina", + "join our Discord for help.": "dołącz do Discorda po pomoc.", "JSON": "JSON", "JSON Preview": "Podgląd JSON", - "JSON Spec": "", + "JSON Spec": "Specyfikacja JSON", "July": "Lipiec", "June": "Czerwiec", - "Jupyter Auth": "Jupyter Auth", - "Jupyter URL": "Adres URL Jupytera", - "JWT Expiration": "Termin ważności JWT", + "Jupyter Auth": "Autoryzacja Jupyter", + "Jupyter URL": "URL Jupyter", + "JWT Expiration": "Wygaśnięcie JWT", "JWT Token": "Token JWT", "Kagi Search API Key": "Klucz API Kagi Search", - "Keep Follow-Up Prompts in Chat": "", - "Keep in Sidebar": "", + "Keep Follow-Up Prompts in Chat": "Zachowaj prompty kontynuacji w czacie", + "Keep in Sidebar": "Zachowaj w pasku bocznym", "Key": "Klucz", - "Key is required": "", + "Key is required": "Klucz jest wymagany", "Keyboard shortcuts": "Skróty klawiszowe", - "Keyboard Shortcuts": "", - "Knowledge": "Wiedza", - "Knowledge Access": "Dostęp do wiedzy", - "Knowledge Base": "", - "Knowledge created successfully.": "Pomyślnie utworzona wiedza.", - "Knowledge deleted successfully.": "Wiedza została usunięta pomyślnie.", - "Knowledge Description": "", - "Knowledge Name": "", - "Knowledge Public Sharing": "", - "Knowledge reset successfully.": "Pomyślnie zresetowano wiedzę.", - "Knowledge Sharing": "", + "Keyboard Shortcuts": "Skróty klawiszowe", + "Knowledge": "Baza wiedzy", + "Knowledge Access": "Dostęp do bazy wiedzy", + "Knowledge Base": "Baza wiedzy", + "Knowledge created successfully.": "Wiedza utworzona pomyślnie.", + "Knowledge deleted successfully.": "Wiedza usunięta pomyślnie.", + "Knowledge Description": "Opis Wiedzy", + "Knowledge Name": "Nazwa Wiedzy", + "Knowledge Public Sharing": "Publiczne udostępnianie Wiedzy", + "Knowledge reset successfully.": "Wiedza zresetowana pomyślnie.", + "Knowledge Sharing": "Udostępnianie Wiedzy", "Knowledge updated successfully": "Wiedza zaktualizowana pomyślnie", "Kokoro.js (Browser)": "Kokoro.js (Przeglądarka)", - "Kokoro.js Dtype": "Kokoro.js Dtype", - "Label": "Nazwa serwera", - "Landing Page Mode": "Tryb strony głównej", + "Kokoro.js Dtype": "Typ danych Kokoro.js", + "Label": "Etykieta", + "Landing Page Mode": "Tryb Landing Page", "Language": "Język", - "Language Locales": "", + "Language Locales": "Lokalizacje językowe", "Last Active": "Ostatnio aktywny", "Last Modified": "Ostatnia modyfikacja", "Last reply": "Ostatnia odpowiedź", "LDAP": "LDAP", - "LDAP server updated": "Serwer LDAP został zaktualizowany", + "LDAP server updated": "Serwer LDAP zaktualizowany", "Leaderboard": "Tablica wyników", - "Learn More": "", - "Learn more about OpenAPI tool servers.": "", - "Learn more about Voxtral transcription.": "", - "Leave empty for no compression": "", - "Leave empty for unlimited": "Pozostaw puste dla nieograniczonego", - "Leave empty to include all models from \"{{url}}\" endpoint": "", - "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", - "Leave empty to include all models from \"{{url}}/models\" endpoint": "", - "Leave empty to include all models or select specific models": "Pozostaw puste, aby uwzględnić wszystkie modele lub wybierz konkretne modele", - "Leave empty to use the default model (voxtral-mini-latest).": "", - "Leave empty to use the default prompt, or enter a custom prompt": "Pozostaw puste, aby użyć domyślnego promptu, lub wprowadź niestandardowy prompt", - "Leave model field empty to use the default model.": "Pozostaw pole modelu puste, aby użyć domyślnego modelu.", - "Legacy": "", - "lexical": "", + "Learn More": "Dowiedz się więcej", + "Learn more about OpenAPI tool servers.": "Dowiedz się więcej o serwerach narzędzi OpenAPI.", + "Learn more about Voxtral transcription.": "Dowiedz się więcej o transkrypcji Voxtral.", + "Leave empty for no compression": "Zostaw puste dla braku kompresji", + "Leave empty for unlimited": "Zostaw puste dla braku limitu", + "Leave empty to include all models from \"{{url}}\" endpoint": "Zostaw puste, aby dołączyć wszystkie modele z endpointu \"{{url}}\"", + "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Zostaw puste, aby dołączyć wszystkie modele z \"{{url}}/api/tags\"", + "Leave empty to include all models from \"{{url}}/models\" endpoint": "Zostaw puste, aby dołączyć wszystkie modele z \"{{url}}/models\"", + "Leave empty to include all models or select specific models": "Zostaw puste, aby uwzględnić wszystkie, lub wybierz konkretne", + "Leave empty to use the default model (voxtral-mini-latest).": "Zostaw puste, aby użyć domyślnego modelu (voxtral-mini-latest).", + "Leave empty to use the default prompt, or enter a custom prompt": "Zostaw puste dla domyślnego, lub wpisz własny", + "Leave model field empty to use the default model.": "Zostaw puste, aby użyć modelu domyślnego.", + "Legacy": "Przestarzałe (Legacy)", + "lexical": "leksykalny", "License": "Licencja", - "Lift List": "", + "Lift List": "Lift List", "Light": "Jasny", - "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "", - "List": "", - "Listening...": "Słuchanie...", + "Limit concurrent search queries. 0 = unlimited (default). Set to 1 for sequential execution (recommended for APIs with strict rate limits like Brave free tier).": "Limit jednoczesnych zapytań. 0 = brak (domyślnie). Ustaw 1 dla sekwencyjnego wykonywania (zalecane dla darmowych API np. Brave).", + "List": "Lista", + "Listening...": "Słucham...", "Llama.cpp": "Llama.cpp", - "LLMs can make mistakes. Verify important information.": "LLMy mogą popełniać błędy. Upewnij się, że ważne informacje są poprawne.", - "Loader": "", - "Loading Kokoro.js...": "Wczytywanie Kokoro.js...", - "Loading...": "Wczytywanie...", - "local": "", + "LLMs can make mistakes. Verify important information.": "Modele LLM mogą popełniać błędy. Weryfikuj ważne informacje.", + "Loader": "Loader", + "Loading Kokoro.js...": "Ładowanie Kokoro.js...", + "Loading...": "Ładowanie...", + "local": "lokalny", "Local": "Lokalny", - "Local Task Model": "", - "Location access not allowed": "", - "Lost": "Przegrał", - "Low": "", - "LTR": "LTR", - "Made by Open WebUI Community": "Opracowane przez społeczność Open WebUI", - "Make password visible in the user interface": "", - "Make sure to enclose them with": "Upewnij się, że są one zawarte w", - "Make sure to export a workflow.json file as API format from ComfyUI.": "Upewnij się, że wyeksportowałeś plik workflow.json w formacie API z ComfyUI.", - "Male": "", + "Local Task Model": "Lokalny Model Zadaniowy", + "Location access not allowed": "Brak dostępu do lokalizacji", + "Lost": "Przegrano", + "Low": "Niski", + "LTR": "LTR (Od lewej)", + "Made by Open WebUI Community": "Stworzone przez społeczność Open WebUI", + "Make password visible in the user interface": "Pokaż hasło w interfejsie", + "Make sure to enclose them with": "Upewnij się, że otaczasz je", + "Make sure to export a workflow.json file as API format from ComfyUI.": "Upewnij się, że eksportujesz workflow.json w formacie API z ComfyUI.", + "Male": "Mężczyzna", "Manage": "Zarządzaj", - "Manage Direct Connections": "Zarządzaj bezpośrednimi połączeniami", + "Manage Direct Connections": "Zarządzaj połączeniami bezpośrednimi", "Manage Models": "Zarządzaj modelami", - "Manage Ollama": "Zarządzaj Ollamą", - "Manage Ollama API Connections": "Zarządzaj połączeniami z API Ollama", - "Manage OpenAI API Connections": "Zarządzaj połączeniami z API OpenAI", - "Manage Pipelines": "Zarządzanie przepływem", - "Manage Tool Servers": "", - "Manage your account information.": "", + "Manage Ollama": "Zarządzaj Ollama", + "Manage Ollama API Connections": "Zarządzaj połączeniami API Ollama", + "Manage OpenAI API Connections": "Zarządzaj połączeniami API OpenAI", + "Manage Pipelines": "Zarządzaj Pipeline'ami", + "Manage Tool Servers": "Zarządzaj serwerami narzędzi", + "Manage your account information.": "Zarządzaj informacjami o koncie.", "March": "Marzec", - "Markdown": "", - "Markdown (Header)": "", - "Max Speakers": "", - "Max Upload Count": "Maksymalna liczba przesyłanych plików", - "Max Upload Size": "Maksymalny rozmiar przesyłanego pliku", - "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksymalnie 3 modele można pobierać jednocześnie. Proszę spróbować ponownie później.", + "Markdown": "Markdown", + "Markdown (Header)": "Markdown (Nagłówek)", + "Max Speakers": "Maks. mówców", + "Max Upload Count": "Maks. liczba plików", + "Max Upload Size": "Maks. rozmiar pliku", + "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksymalnie 3 modele mogą być pobierane jednocześnie. Spróbuj później.", "May": "Maj", - "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 added successfully": "", - "Memories accessible by LLMs will be shown here.": "Wspomnienia dostępne za pomocą LLM zostaną wyświetlone tutaj.", + "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.": "Wsparcie MCP jest eksperymentalne i może powodować niekompatybilność. Wsparcie OpenAPI jest utrzymywane przez zespół Open WebUI i jest bardziej niezawodne.", + "Medium": "Średni", + "Member removed successfully": "Członek usunięty pomyślnie", + "Members": "Członkowie", + "Members added successfully": "Członkowie dodani pomyślnie", + "Memories accessible by LLMs will be shown here.": "Wspomnienia dostępne dla LLM pojawią się tutaj.", "Memory": "Pamięć", - "Memory added successfully": "Pamięć dodana pomyślnie", - "Memory cleared successfully": "Pamięć oczyszczona pomyślnie", - "Memory deleted successfully": "Pamięć została usunięta pomyślnie", - "Memory updated successfully": "Pamięć zaktualizowana pomyślnie", - "Merge Responses": "Scalaj odpowiedzi ", + "Memory added successfully": "Wspomnienie dodane pomyślnie", + "Memory cleared successfully": "Pamięć wyczyszczona pomyślnie", + "Memory deleted successfully": "Wspomnienie usunięte pomyślnie", + "Memory updated successfully": "Wspomnienie zaktualizowane pomyślnie", + "Merge Responses": "Połącz odpowiedzi", "Merged Response": "Połączona odpowiedź", - "Message": "", - "Message rating should be enabled to use this feature": "Ocena wiadomości powinna być włączona, aby korzystać z tej funkcji.", - "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Wiadomości wysyłane po utworzeniu linku nie będą udostępniane. Użytkownicy z adresem URL będą mogli wyświetlić udostępnioną rozmowę.", - "Microsoft OneDrive": "", - "Microsoft OneDrive (personal)": "", - "Microsoft OneDrive (work/school)": "", - "MinerU": "", - "MinerU API Key required for Cloud API mode.": "", - "Mistral OCR": "", - "Mistral OCR API Key required.": "", - "MistralAI": "", + "Message": "Wiadomość", + "Message rating should be enabled to use this feature": "Ocenianie wiadomości musi być włączone, aby użyć tej funkcji", + "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Wiadomości wysłane po utworzeniu linku nie będą udostępniane. Użytkownicy z linkiem zobaczą udostępniony czat.", + "Microsoft OneDrive": "Microsoft OneDrive", + "Microsoft OneDrive (personal)": "Microsoft OneDrive (osobisty)", + "Microsoft OneDrive (work/school)": "Microsoft OneDrive (praca/szkoła)", + "MinerU": "MinerU", + "MinerU API Key required for Cloud API mode.": "Klucz API MinerU wymagany dla trybu Cloud API.", + "Mistral OCR": "Mistral OCR", + "Mistral OCR API Key required.": "Wymagany klucz API Mistral OCR.", + "MistralAI": "MistralAI", "Model": "Model", "Model '{{modelName}}' has been successfully downloaded.": "Model '{{modelName}}' został pomyślnie pobrany.", - "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' jest już w kolejce do pobrania.", - "Model {{modelId}} not found": "Model o identyfikatorze {{modelId}} nie został znaleziony.", - "Model {{modelName}} is not vision capable": "Model {{modelName}} nie jest zdolny do widzenia", + "Model '{{modelTag}}' is already in queue for downloading.": "Model '{{modelTag}}' jest już w kolejce pobierania.", + "Model {{modelId}} not found": "Nie znaleziono modelu {{modelId}}", + "Model {{modelName}} is not vision capable": "Model {{modelName}} nie obsługuje widzenia (Vision)", "Model {{name}} is now {{status}}": "Model {{name}} jest teraz {{status}}", "Model {{name}} is now hidden": "Model {{name}} jest teraz ukryty", "Model {{name}} is now visible": "Model {{name}} jest teraz widoczny", - "Model accepts file inputs": "Model przyjmuje pliki", - "Model accepts image inputs": "Model przyjmuje obrazy", - "Model can execute code and perform calculations": "Model może wykonywać kod i przeprowadzać obliczenia", - "Model can generate images based on text prompts": "Model może generować obrazy bazując na tekstowych promptach", - "Model can search the web for information": "Model może wyszukiwać informacje w sieci Web", + "Model accepts file inputs": "Model akceptuje pliki", + "Model accepts image inputs": "Model akceptuje obrazy", + "Model can execute code and perform calculations": "Model może wykonywać kod i obliczenia", + "Model can generate images based on text prompts": "Model może generować obrazy z tekstu", + "Model can search the web for information": "Model może szukać informacji w sieci", "Model created successfully!": "Model utworzony pomyślnie!", - "Model filesystem path detected. Model shortname is required for update, cannot continue.": "Wykryto ścieżkę systemu plików modelu. Podanie krótkiej nazwy modelu jest wymagane do aktualizacji, nie można kontynuować.", - "Model Filtering": "Filtracja modeli", - "Model ID": "Identyfikator modelu", - "Model ID is required.": "", - "Model IDs": "Identyfikatory modeli", + "Model filesystem path detected. Model shortname is required for update, cannot continue.": "Wykryto ścieżkę systemową. Krótka nazwa modelu wymagana do aktualizacji.", + "Model Filtering": "Filtrowanie modeli", + "Model ID": "ID Modelu", + "Model ID is required.": "ID Modelu jest wymagane.", + "Model IDs": "ID Modeli", "Model Name": "Nazwa modelu", - "Model name already exists, please choose a different one": "", - "Model Name is required.": "", - "Model not selected": "Model nie został wybrany", + "Model name already exists, please choose a different one": "Nazwa modelu już istnieje, wybierz inną", + "Model Name is required.": "Nazwa modelu jest wymagana.", + "Model not selected": "Nie wybrano modelu", "Model Params": "Parametry modelu", "Model Permissions": "Uprawnienia modelu", - "Model unloaded successfully": "", - "Model updated successfully": "Model został zaktualizowany pomyślnie", - "Model(s) do not support file upload": "", - "Modelfile Content": "Treść pliku modelu", + "Model unloaded successfully": "Model odładowany pomyślnie", + "Model updated successfully": "Model zaktualizowany pomyślnie", + "Model(s) do not support file upload": "Model(e) nie obsługują przesyłania plików", + "Modelfile Content": "Treść Modelfile", "Models": "Modele", "Models Access": "Dostęp do modeli", - "Models configuration saved successfully": "Konfiguracja modeli została zapisana pomyślnie", - "Models imported successfully": "", - "Models Public Sharing": "", - "Models Sharing": "", + "Models configuration saved successfully": "Konfiguracja modeli zapisana pomyślnie", + "Models imported successfully": "Modele zaimportowane pomyślnie", + "Models Public Sharing": "Publiczne udostępnianie modeli", + "Models Sharing": "Udostępnianie modeli", "Mojeek Search API Key": "Klucz API Mojeek Search", "More": "Więcej", - "More Concise": "", - "More Options": "", - "Move": "", + "More Concise": "Bardziej zwięzły", + "More Options": "Więcej opcji", + "Move": "Przenieś", "Name": "Nazwa", - "Name and ID are required, please fill them out": "", - "Name your knowledge base": "Nazwij swoją bazę wiedzy", - "Native": "Rodzimy", - "New": "", - "New Button": "", + "Name and ID are required, please fill them out": "Nazwa i ID są wymagane", + "Name your knowledge base": "Nazwij bazę wiedzy", + "Native": "Natywny", + "New": "Nowy", + "New Button": "Nowy przycisk", "New Chat": "Nowy czat", "New Folder": "Nowy folder", "New Function": "Nowa funkcja", - "New Knowledge": "", - "New Model": "", - "New Note": "", + "New Knowledge": "Nowa Wiedza", + "New Model": "Nowy model", + "New Note": "Nowa notatka", "New Password": "Nowe hasło", - "New Prompt": "", - "New Temporary Chat": "", + "New Prompt": "Nowy prompt", + "New Temporary Chat": "Nowy czat tymczasowy", "New Tool": "Nowe narzędzie", - "new-channel": "nowy-kanał", + "new-channel": "nowy-kanal", "Next message": "Następna wiadomość", - "No authentication": "", + "No authentication": "Brak autoryzacji", "No chats found": "Nie znaleziono czatów", - "No chats found for this user.": "Nie znaleziono czatów tego użytkownika.", + "No chats found for this user.": "Nie znaleziono czatów dla tego użytkownika.", "No chats found.": "Nie znaleziono czatów.", - "No content": "Brak zawartości", - "No content found": "Nie znaleziono żadnej zawartości.", - "No content to speak": "Brak treści do omówienia", - "No conversation to save": "", - "No distance available": "Brak dostępnej odległości", - "No expiration can pose security risks.": "", - "No feedbacks found": "Nie znaleziono żadnych opinii", - "No file selected": "Nie wybrano żadnego pliku", - "No files in this knowledge base.": "", - "No functions found": "", - "No groups with access, add a group to grant access": "Brak grup z dostępem, dodaj grupę, aby przyznać dostęp", - "No HTML, CSS, or JavaScript content found.": "Nie znaleziono żadnej zawartości HTML, CSS ani JavaScript.", - "No inference engine with management support found": "Nie znaleziono silnika wnioskującego z obsługą zarządzania", - "No knowledge bases found.": "", - "No knowledge found": "Brak znalezionej wiedzy", + "No content": "Brak treści", + "No content found": "Nie znaleziono treści", + "No content to speak": "Brak treści do wymówienia", + "No conversation to save": "Brak rozmowy do zapisania", + "No distance available": "Brak dostępnego dystansu", + "No expiration can pose security risks.": "Brak wygaśnięcia może stanowić ryzyko bezpieczeństwa.", + "No feedbacks found": "Nie znaleziono opinii", + "No file selected": "Nie wybrano pliku", + "No files in this knowledge base.": "Brak plików w tej bazie wiedzy.", + "No functions found": "Nie znaleziono funkcji", + "No groups with access, add a group to grant access": "Brak grup z dostępem, dodaj grupę", + "No HTML, CSS, or JavaScript content found.": "Nie znaleziono treści HTML, CSS ani JS.", + "No inference engine with management support found": "Nie znaleziono silnika wnioskowania ze wsparciem zarządzania", + "No knowledge bases found.": "Nie znaleziono baz wiedzy.", + "No knowledge found": "Nie znaleziono wiedzy", "No memories to clear": "Brak wspomnień do wyczyszczenia", - "No model IDs": "Brak identyfikatorów modeli", + "No model IDs": "Brak ID modeli", "No models found": "Nie znaleziono modeli", - "No models selected": "Brak wybranych modeli", + "No models selected": "Nie wybrano modeli", "No Notes": "Brak notatek", - "No notes found": "", - "No pinned messages": "", - "No prompts found": "", + "No notes found": "Nie znaleziono notatek", + "No pinned messages": "Brak przypiętych wiadomości", + "No prompts found": "Nie znaleziono promptów", "No results": "Brak wyników", "No results found": "Brak wyników", - "No search query generated": "Nie wygenerowano żadnego zapytania wyszukiwania", - "No source available": "Źródło nie jest dostępne.", - "No sources found": "", + "No search query generated": "Nie wygenerowano zapytania wyszukiwania", + "No source available": "Brak dostępnego źródła", + "No sources found": "Nie znaleziono źródeł", "No suggestion prompts": "Brak sugerowanych promptów", - "No tools found": "", + "No tools found": "Nie znaleziono narzędzi", "No users were found.": "Nie znaleziono użytkowników.", - "No valves": "", + "No valves": "Brak Valves", "No valves to update": "Brak zaworów do aktualizacji", - "Node Ids": "", + "Node Ids": "ID Węzłów", "None": "Brak", - "Not factually correct": "Niezgodne z rzeczywistością", - "Not helpful": "Nieprzydatne", - "Not Registered": "", - "Note": "", - "Note deleted successfully": "Notatka została usunięta", - "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Uwaga: Jeśli określisz minimalną punktację, wyszukiwanie zwróci tylko dokumenty o wyniku równym lub wyższym niż minimalna punktacja.", + "Not factually correct": "Merytorycznie niepoprawne", + "Not helpful": "Niepomocne", + "Not Registered": "Niezarejestrowany", + "Note": "Notatka", + "Note deleted successfully": "Notatka usunięta pomyślnie", + "Note: If you set a minimum score, the search will only return documents with a score greater than or equal to the minimum score.": "Uwaga: Jeśli ustawisz minimalny wynik, wyszukiwanie zwróci tylko dokumenty powyżej tego progu.", "Notes": "Notatki", - "Notes Public Sharing": "", - "Notes Sharing": "", + "Notes Public Sharing": "Publiczne udostępnianie notatek", + "Notes Sharing": "Udostępnianie notatek", "Notification Sound": "Dźwięk powiadomienia", - "Notification Webhook": "Powiadomienie Webhook", + "Notification Webhook": "Webhook powiadomień", "Notifications": "Powiadomienia", "November": "Listopad", - "OAuth": "", - "OAuth 2.1": "", - "OAuth ID": "Identyfikator OAuth", + "OAuth": "OAuth", + "OAuth 2.1": "OAuth 2.1", + "OAuth ID": "ID OAuth", "October": "Październik", - "Off": "Wyłączone", - "Okay, Let's Go!": "Okej, do dzieła!", - "OLED Dark": "Ciemny OLED", + "Off": "Wył.", + "Okay, Let's Go!": "OK, Jedziemy!", + "OLED Dark": "Ciemny (OLED)", "Ollama": "Ollama", - "Ollama API": "Interfejs API Ollama", - "Ollama API settings updated": "Ustawienia API Ollama zostały zaktualizowane", - "Ollama Cloud API Key": "", + "Ollama API": "API Ollama", + "Ollama API settings updated": "Zaktualizowano ustawienia API Ollama", + "Ollama Cloud API Key": "Klucz API Ollama Cloud", "Ollama Version": "Wersja Ollama", - "On": "Włączone", - "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 alphanumeric characters and hyphens are allowed": "Dozwolone są tylko znaki alfanumeryczne i myślniki", - "Only alphanumeric characters and hyphens are allowed in the command string.": "W komendzie dozwolone są wyłącznie znaki alfanumeryczne i myślniki.", - "Only can be triggered when the chat input is in focus.": "", - "Only collections can be edited, create a new knowledge base to edit/add documents.": "Tylko kolekcje można edytować, utwórz nową bazę wiedzy, aby edytować/dodawać dokumenty.", - "Only invited users can access": "", - "Only markdown files are allowed": "", - "Only select users and groups with permission can access": "Tylko wybrani użytkownicy i grupy z uprawnieniami mogą uzyskać dostęp.", - "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Wygląda na to, że podany URL jest nieprawidłowy. Proszę sprawdzić go ponownie i spróbować jeszcze raz.", - "Oops! There are files still uploading. Please wait for the upload to complete.": "Oops! Nadal trwa przesyłanie plików. Proszę poczekać, aż przesyłanie zostanie ukończone.", - "Oops! There was an error in the previous response.": "Oops! Wystąpił błąd w poprzedniej odpowiedzi.", - "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Oops! Używasz nieobsługiwanej metody (tylko interfejs użytkownika). Proszę serwować WebUI z poziomu backendu.", + "On": "Wł.", + "OneDrive": "OneDrive", + "Only active when \"Paste Large Text as File\" setting is toggled on.": "Aktywne tylko gdy opcja \"Wklej duży tekst jako plik\" jest włączona.", + "Only active when the chat input is in focus and an LLM is generating a response.": "Aktywne tylko gdy pole czatu jest aktywne a LLM generuje odpowiedź.", + "Only active when the chat input is in focus.": "Aktywne tylko gdy pole czatu jest wybrane.", + "Only alphanumeric characters and hyphens are allowed": "Dozwolone tylko znaki alfanumeryczne i myślniki", + "Only alphanumeric characters and hyphens are allowed in the command string.": "Dozwolone tylko znaki alfanumeryczne i myślniki w ciągu komendy.", + "Only can be triggered when the chat input is in focus.": "Można wywołać tylko gdy pole czatu jest wybrane.", + "Only collections can be edited, create a new knowledge base to edit/add documents.": "Można edytować tylko kolekcje. Utwórz nową bazę wiedzy by dodawać lub edytować dokumenty.", + "Only invited users can access": "Tylko zaproszeni użytkownic mają dostęp", + "Only markdown files are allowed": "Tylko pliki markdown są dozwolone", + "Only select users and groups with permission can access": "Tylko wybrani użytkownicy z uprawnieniami mają dostęp", + "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! URL wygląda na nieprawidłowy. Sprawdź i spróbuj ponownie.", + "Oops! There are files still uploading. Please wait for the upload to complete.": "Ups! Pliki wciąż się przesyłają. Poczekaj na zakończenie.", + "Oops! There was an error in the previous response.": "Ups! Wystąpił błąd w poprzedniej odpowiedzi.", + "Oops! You're using an unsupported method (frontend only). Please serve the WebUI from the backend.": "Ups! Używasz nieobsługiwanej metody (tylko frontend). Uruchom WebUI z backendu.", "Open file": "Otwórz plik", - "Open in full screen": "Otwórz na pełny ekran", - "Open link": "", - "Open modal to configure connection": "", - "Open Modal To Manage Floating Quick Actions": "", - "Open Modal To Manage Image Compression": "", - "Open Settings": "", - "Open Sidebar": "", - "Open User Profile Menu": "", - "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI może używać narzędzi dostarczanych przez serwery OpenAPI.", - "Open WebUI uses faster-whisper internally.": "Open WebUI korzysta wewnętrznie z szybszego faster-whisper.", - "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Otwarta WebUI wykorzystuje SpeechT5 i wbudowane zbiory danych mówcy CMU Arctic.", - "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Wersja Open WebUI (v{{OPEN_WEBUI_VERSION}}) jest niższa niż wymagana wersja (v{{REQUIRED_VERSION}})", + "Open in full screen": "Pełny ekran", + "Open link": "Otwórz link", + "Open modal to configure connection": "Otwórz okno konfiguracji połączenia", + "Open Modal To Manage Floating Quick Actions": "Otwórz okno zarządzania szybkimi akcjami", + "Open Modal To Manage Image Compression": "Otwórz okno zarządzania kompresją obrazu", + "Open Settings": "Otwórz Ustawienia", + "Open Sidebar": "Otwórz pasek boczny", + "Open User Profile Menu": "Otwórz menu profilu", + "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI może używać narzędzi z dowolnego serwera OpenAPI.", + "Open WebUI uses faster-whisper internally.": "Open WebUI używa wewnętrznie faster-whisper.", + "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI używa SpeechT5 i embeddingów CMU Arctic.", + "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Wersja Open WebUI (v{{OPEN_WEBUI_VERSION}}) jest niższa niż wymagana (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", - "OpenAI API": "Interfejs API OpenAI", - "OpenAI API Base URL": "", - "OpenAI API Key": "", - "OpenAI API Key is required.": "Klucz API OpenAI jest niezbędny.", - "OpenAI API settings updated": "Ustawienia API OpenAI zostały zaktualizowane", - "OpenAI API Version": "", - "OpenAI URL/Key required.": "Wymagany jest URL/klucz OpenAI.", - "OpenAPI": "", - "OpenAPI Spec": "", - "openapi.json URL or Path": "", - "Optional": "", + "OpenAI API": "API OpenAI", + "OpenAI API Base URL": "Base URL API OpenAI", + "OpenAI API Key": "Klucz API OpenAI", + "OpenAI API Key is required.": "Klucz API OpenAI jest wymagany.", + "OpenAI API settings updated": "Zaktualizowano ustawienia API OpenAI", + "OpenAI API Version": "Wersja API OpenAI", + "OpenAI URL/Key required.": "Wymagany URL/Klucz OpenAI.", + "OpenAPI": "OpenAPI", + "OpenAPI Spec": "Specyfikacja OpenAPI", + "openapi.json URL or Path": "URL lub ścieżka openapi.json", + "Optional": "Opcjonalne", "or": "lub", "Ordered List": "Lista numerowana", - "Organize your users": "Zorganizuj swoich użytkowników", - "Other": "Pozostałe", - "OUTPUT": "WYNIKI", + "Organize your users": "Organizuj użytkowników", + "Other": "Inne", + "OUTPUT": "WYNIK", "Output format": "Format wyjściowy", - "Output Format": "", + "Output Format": "Format wyjściowy", "Overview": "Przegląd", "page": "strona", - "Paginate": "", + "Paginate": "Stronicowanie", "Parameters": "Parametry", "Password": "Hasło", - "Passwords do not match.": "", + "Passwords do not match.": "Hasła nie pasują do siebie.", "Paste Large Text as File": "Wklej duży tekst jako plik", "PDF document (.pdf)": "Dokument PDF (.pdf)", - "PDF Extract Images (OCR)": "PDF Ekstrahuj obrazy (OCR)", - "pending": "oczekiwanie", - "Pending": "", - "Pending User Overlay Content": "", - "Pending User Overlay Title": "", - "Permission denied when accessing media devices": "Odmowa dostępu podczas uzyskiwania dostępu do urządzeń multimedialnych", - "Permission denied when accessing microphone": "Odmowa dostępu podczas uzyskiwania dostępu do mikrofonu", + "PDF Extract Images (OCR)": "Wyodrębnij obrazy z PDF (OCR)", + "pending": "oczekuje", + "Pending": "Oczekujące", + "Pending User Overlay Content": "Treść ekranu oczekującego użytkownika", + "Pending User Overlay Title": "Tytuł ekranu oczekującego użytkownika", + "Permission denied when accessing media devices": "Odmowa dostępu do urządzeń multimedialnych", + "Permission denied when accessing microphone": "Odmowa dostępu do mikrofonu", "Permission denied when accessing microphone: {{error}}": "Odmowa dostępu do mikrofonu: {{error}}", "Permissions": "Uprawnienia", "Perplexity API Key": "Klucz API Perplexity", - "Perplexity Model": "", - "Perplexity Search API URL": "", - "Perplexity Search Context Usage": "", + "Perplexity Model": "Model Perplexity", + "Perplexity Search API URL": "URL API Perplexity Search", + "Perplexity Search Context Usage": "Użycie kontekstu Perplexity Search", "Personalization": "Personalizacja", "Pin": "Przypnij", - "Pinned": "Przypięty", - "Pinned Messages": "", - "Pioneer insights": "Pionierskie spostrzeżenia", - "Pipe": "", - "Pipeline deleted successfully": "Przepływ usunięty pomyślnie", - "Pipeline downloaded successfully": "Przepływ pobrany pomyślnie", - "Pipelines": "Przepływy", - "Pipelines are a plugin system with arbitrary code execution —": "Pipelines to system wtyczek umożliwiający dowolne wykonywanie kodu —", - "Pipelines Not Detected": "Przepływ nie wykryty", - "Pipelines Valves": "Przepływy i Zawory", + "Pinned": "Przypięte", + "Pinned Messages": "Przypięte wiadomości", + "Pioneer insights": "Odkrywaj nowe wglądy", + "Pipe": "Pipe", + "Pipeline deleted successfully": "Pipeline usunięty pomyślnie", + "Pipeline downloaded successfully": "Pipeline pobrany pomyślnie", + "Pipelines": "Pipelines", + "Pipelines are a plugin system with arbitrary code execution —": "Pipelines to system wtyczek z wykonywaniem dowolnego kodu —", + "Pipelines Not Detected": "Nie wykryto Pipeline'ów", + "Pipelines Valves": "Pipelines Valves", "Plain text (.md)": "Zwykły tekst (.md)", "Plain text (.txt)": "Zwykły tekst (.txt)", - "Playground": "Plac zabaw", - "Playwright Timeout (ms)": "", - "Playwright WebSocket URL": "", - "Please carefully review the following warnings:": "Proszę uważnie przejrzeć poniższe ostrzeżenia:", - "Please do not close the settings page while loading the model.": "Proszę nie zamykać strony ustawień podczas ładowania modelu.", - "Please enter a message or attach a file.": "", - "Please enter a prompt": "Proszę podać prompt", - "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 fill in all fields.": "Proszę wypełnić wszystkie pola.", - "Please register the OAuth client": "", - "Please save the connection to persist the OAuth client information and do not change the ID": "", - "Please select a model first.": "Proszę najpierw wybrać model.", - "Please select a model.": "Proszę wybrać model.", - "Please select a reason": "Proszę wybrać powód", - "Please select a valid JSON file": "", - "Please select at least one user for Direct Message channel.": "", - "Please wait until all files are uploaded.": "", + "Playground": "Playground", + "Playwright Timeout (ms)": "Timeout Playwright (ms)", + "Playwright WebSocket URL": "URL WebSocket Playwright", + "Please carefully review the following warnings:": "Uważnie przeczytaj poniższe ostrzeżenia:", + "Please do not close the settings page while loading the model.": "Nie zamykaj ustawień podczas ładowania modelu.", + "Please enter a message or attach a file.": "Wpisz wiadomość lub załącz plik.", + "Please enter a prompt": "Wprowadź prompt", + "Please enter a valid ID": "Wprowadź poprawne ID", + "Please enter a valid JSON spec": "Wprowadź poprawną specyfikację JSON", + "Please enter a valid path": "Wprowadź poprawną ścieżkę", + "Please enter a valid URL": "Wprowadź poprawny URL", + "Please enter a valid URL.": "Wprowadź poprawny URL.", + "Please fill in all fields.": "Wypełnij wszystkie pola.", + "Please register the OAuth client": "Zarejestruj klienta OAuth", + "Please save the connection to persist the OAuth client information and do not change the ID": "Zapisz połączenie aby zachować dane klienta OAuth i nie zmieniaj ID", + "Please select a model first.": "Najpierw wybierz model.", + "Please select a model.": "Wybierz model.", + "Please select a reason": "Wybierz powód", + "Please select a valid JSON file": "Wybierz poprawny plik JSON", + "Please select at least one user for Direct Message channel.": "Wybierz co najmniej jednego użytkownika do czatu prywatnego.", + "Please wait until all files are uploaded.": "Poczekaj na przesłanie wszystkich plików.", "Port": "Port", "Positive attitude": "Pozytywne nastawienie", - "Prefer not to say": "", - "Prefix ID": "Identyfikator prefiksu", - "Prefix ID is used to avoid conflicts with other connections by adding a prefix to the model IDs - leave empty to disable": "ID prefiksu jest używane do unikania konfliktów z innymi połączeniami poprzez dodanie prefiksu do ID modelu - pozostaw puste, aby wyłączyć", - "Prevent File Creation": "", + "Prefer not to say": "Wolę nie mówić", + "Prefix ID": "Prefix ID", + "Prefix ID is used to avoid conflicts with other connections by adding a prefix to the model IDs - leave empty to disable": "Prefix ID służy do unikania konfliktów (dodawany do ID modelu). Zostaw puste aby wyłączyć", + "Prevent File Creation": "Zapobiegaj tworzeniu plików", "Preview": "Podgląd", "Previous 30 days": "Ostatnie 30 dni", "Previous 7 days": "Ostatnie 7 dni", "Previous message": "Poprzednia wiadomość", - "Private": "Prywatne", - "Private conversation between selected users": "", + "Private": "Prywatny", + "Private conversation between selected users": "Prywatna rozmowa między wybranymi użytkownikami", "Profile": "Profil", - "Prompt": "Wprowadź prompt: ", + "Prompt": "Prompt", "Prompt Autocompletion": "Autouzupełnianie promptu", "Prompt Content": "Treść promptu", - "Prompt created successfully": "Prompt został utworzony pomyślnie", - "Prompt updated successfully": "Prompt został zaktualizowany pomyślnie.", + "Prompt created successfully": "Prompt utworzony pomyślnie", + "Prompt updated successfully": "Prompt zaktualizowany pomyślnie", "Prompts": "Prompty", "Prompts Access": "Dostęp do promptów", "Prompts Public Sharing": "Publiczne udostępnianie promptów", - "Prompts Sharing": "", - "Provider Type": "", - "Public": "Publiczne", + "Prompts Sharing": "Udostępnianie promptów", + "Provider Type": "Typ dostawcy", + "Public": "Publiczny", "Pull \"{{searchValue}}\" from Ollama.com": "Pobierz \"{{searchValue}}\" z Ollama.com", "Pull a model from Ollama.com": "Pobierz model z Ollama.com", - "Pull Model": "", - "Query Generation Prompt": "Prompt do generowania zapytań", - "Querying": "", - "Quick Actions": "", + "Pull Model": "Pobierz Model", + "Query Generation Prompt": "Prompt generowania zapytania", + "Querying": "Odpytywanie", + "Quick Actions": "Szybkie akcje", "RAG Template": "Szablon RAG", "Rating": "Ocena", - "Re-rank models by topic similarity": "Ponowny ranking modeli według podobieństwa tematycznego", + "Re-rank models by topic similarity": "Re-rank models by topic similarity", "Read": "Czytaj", "Read Aloud": "Czytaj na głos", - "Read more →": "", - "Read Only": "", - "Read-Only Access": "", + "Read more →": "Czytaj więcej →", + "Read Only": "Tylko do odczytu", + "Read-Only Access": "Dostęp tylko do odczytu", "Reason": "Powód", - "Reasoning Effort": "Wysiłek rozumowania", - "Reasoning Tags": "", + "Reasoning Effort": "Reasoning Effort", + "Reasoning Tags": "Reasoning Tags", "Record": "Nagraj", - "Record voice": "Nagraj swój głos", - "Redirecting you to Open WebUI Community": "Przekierowujemy Cię do społeczności Open WebUI", - "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.": "", - "Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Odnoś się do mnie jako \"Użytkownik\" (np. \"Użytkownik uczy się hiszpańskiego\")", - "Reference Chats": "", + "Record voice": "Nagraj głos", + "Redirecting you to Open WebUI Community": "Przekierowanie do społeczności Open WebUI", + "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.": "Redukuje prawdopodobieństwo generowania nonsensu. Wyższa wartość (np. 100) = większa różnorodność, niższa (np. 10) = bardziej zachowawczo.", + "Refer to yourself as \"User\" (e.g., \"User is learning Spanish\")": "Mów o sobie \"Użytkownik\" (np. \"Użytkownik uczy się...\")", + "Reference Chats": "Czaty referencyjne", "Refused when it shouldn't have": "Odmówił, gdy nie powinien", "Regenerate": "Wygeneruj ponownie", - "Regenerate Menu": "", - "Regenerate Response": "", - "Register Again": "", - "Register Client": "", - "Registered": "", - "Registration failed": "", - "Registration successful": "", - "Reindex": "", - "Reindex Knowledge Base Vectors": "", - "Release Notes": "Notatki do wydania", + "Regenerate Menu": "Menu regeneracji", + "Regenerate Response": "Wygeneruj odpowiedź ponownie", + "Register Again": "Zarejestruj ponownie", + "Register Client": "Zarejestruj klienta", + "Registered": "Zarejestrowano", + "Registration failed": "Rejestracja nieudana", + "Registration successful": "Rejestracja udana", + "Reindex": "Reindeksuj", + "Reindex Knowledge Base Vectors": "Reindeksuj wektory bazy wiedzy", + "Release Notes": "Informacje o wydaniu", "Releases": "Wydania", "Relevance": "Trafność", - "Relevance Threshold": "", - "Remember Dismissal": "", + "Relevance Threshold": "Próg trafności", + "Remember Dismissal": "Zapamiętaj odrzucenie", "Remove": "Usuń", - "Remove {{MODELID}} from list.": "", - "Remove file": "", - "Remove File": "", - "Remove image": "", + "Remove {{MODELID}} from list.": "Usuń {{MODELID}} z listy.", + "Remove file": "Usuń plik", + "Remove File": "Usuń plik", + "Remove image": "Usuń obraz", "Remove Model": "Usuń model", - "Remove this tag from list": "", + "Remove this tag from list": "Usuń ten tag z listy", "Rename": "Zmień nazwę", - "Reorder Models": "Przeorganizuj modele", - "Reply": "", + "Reorder Models": "Zmień kolejność modeli", + "Reply": "Odpowiedz", "Reply in Thread": "Odpowiedz w wątku", - "Reply to thread...": "", - "Replying to {{NAME}}": "", - "required": "", - "Reranking Engine": "", - "Reranking Model": "Poprawa rankingu modelu", + "Reply to thread...": "Odpowiedz w wątku...", + "Replying to {{NAME}}": "Odpowiedź do {{NAME}}", + "required": "wymagane", + "Reranking Engine": "Silnik Rerankingu", + "Reranking Model": "Reranking Model", "Reset": "Resetuj", "Reset All Models": "Resetuj wszystkie modele", "Reset Image": "Resetuj obraz", - "Reset Upload Directory": "Resetuj katalog pobierania", - "Reset Vector Storage/Knowledge": "Reset magazynu wektorowego/wiedzy", + "Reset Upload Directory": "Resetuj katalog przesyłania", + "Reset Vector Storage/Knowledge": "Resetuj bazę wektorową/wiedzę", "Reset view": "Resetuj widok", - "Response": "", - "Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Powiadomienia o odpowiedziach nie mogą zostać aktywowane, ponieważ uprawnienia strony zostały odrzucone. Proszę odwiedzić ustawienia przeglądarki, aby przyznać wymagany dostęp.", - "Response splitting": "Rozdzielanie odpowiedzi", - "Response Watermark": "", + "Response": "Odpowiedź", + "Response notifications cannot be activated as the website permissions have been denied. Please visit your browser settings to grant the necessary access.": "Nie można włączyć powiadomień. Sprawdź uprawnienia przeglądarki.", + "Response splitting": "Podział odpowiedzi", + "Response Watermark": "Znak wodny odpowiedzi", "Result": "Wynik", - "RESULT": "Wynik", - "Retrieval": "", - "Retrieval Query Generation": "Generowanie zapytań pobierania", - "Retrieved {{count}} sources": "", - "Retrieved {{count}} sources_one": "", - "Retrieved {{count}} sources_few": "", - "Retrieved {{count}} sources_many": "", - "Retrieved {{count}} sources_other": "", - "Retrieved 1 source": "", - "Rich Text Input for Chat": "Pole do wprowadzania tekstu sformatowanego dla czatu", + "RESULT": "WYNIK", + "Retrieval": "Retrieval (Pobieranie)", + "Retrieval Query Generation": "Generowanie zapytań Retrieval", + "Retrieved {{count}} sources": "Pobrano {{count}} źródeł", + "Retrieved {{count}} sources_one": "Pobrano {{count}} źródło", + "Retrieved {{count}} sources_few": "Pobrano {{count}} źródeł", + "Retrieved {{count}} sources_many": "Pobrano {{count}} źródeł", + "Retrieved {{count}} sources_other": "Pobrano {{count}} źródeł", + "Retrieved 1 source": "Pobrano 1 źródło", + "Rich Text Input for Chat": "Bogaty tekst w czacie", "RK": "RK", "Role": "Rola", - "Rosé Pine": "Różana Sosna", - "Rosé Pine Dawn": "Różany Poranek Pine Dawn", - "RTL": "RTL", + "Rosé Pine": "Rosé Pine", + "Rosé Pine Dawn": "Rosé Pine Dawn", + "RTL": "RTL (Od prawej)", "Run": "Uruchom", - "Running": "Uruchomiono", - "Running...": "Uruchomiono...", - "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "", + "Running": "Działa", + "Running...": "Działa...", + "Runs embedding tasks concurrently to speed up processing. Turn off if rate limits become an issue.": "Uruchamia zadania embeddingu współbieżnie. Wyłącz, jeśli masz limity API.", "Save": "Zapisz", - "Save & Create": "Zapisz i stwórz", - "Save & Update": "Zapisz i odśwież", - "Save As Copy": "Zapisz jako kopia", - "Save Chat": "", + "Save & Create": "Zapisz i utwórz", + "Save & Update": "Zapisz i aktualizuj", + "Save As Copy": "Zapisz jako kopię", + "Save Chat": "Zapisz czat", "Save Tag": "Zapisz tag", "Saved": "Zapisano", - "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": "Zapisywanie dzienników czatu bezpośrednio w pamięci przeglądarki nie jest już obsługiwane. Prosimy o pobranie i usunięcie dzienników czatu, klikając przycisk poniżej. Nie przejmuj się, możesz łatwo ponownie zaimportować dzienniki czatu do backendu przez", - "Scroll On Branch Change": "", + "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": "Zapisywanie historii w przeglądarce nie jest już wspierane. Pobierz i usuń logi poniżej. Możesz je potem zaimportować do backendu przez", + "Scroll On Branch Change": "Przewiń przy zmianie gałęzi", "Search": "Szukaj", - "Search a model": "Wyszukaj model", - "Search all emojis": "", - "Search Base": "Użytkownicy - Baza wyszukiwania", - "Search Chats": "Przeszukaj czaty", + "Search a model": "Szukaj modelu", + "Search all emojis": "Szukaj emoji", + "Search Base": "Baza wyszukiwania", + "Search Chats": "Szukaj czatów", "Search Collection": "Przeszukaj kolekcję", "Search Filters": "Filtry wyszukiwania", - "search for archived chats": "", - "search for folders": "", - "search for pinned chats": "", - "search for shared chats": "", - "search for tags": "wyszukiwanie tagów", - "Search Functions": "Funkcje wyszukiwania", - "Search In Models": "", - "Search Knowledge": "Przeszukaj wiedzę", - "Search Models": "Wyszukiwanie modeli", - "Search Notes": "Wyszukiwanie notatek", + "search for archived chats": "szukaj w zarchiwizowanych", + "search for folders": "szukaj folderów", + "search for pinned chats": "szukaj przypiętych", + "search for shared chats": "szukaj udostępnionych", + "search for tags": "szukaj tagów", + "Search Functions": "Szukaj funkcji", + "Search In Models": "Szukaj w modelach", + "Search Knowledge": "Przeszukaj bazę wiedzy", + "Search Models": "Szukaj modeli", + "Search Notes": "Szukaj notatek", "Search options": "Opcje wyszukiwania", "Search Prompts": "Szukaj promptów", "Search Result Count": "Liczba wyników wyszukiwania", "Search the internet": "Przeszukaj internet", "Search Tools": "Szukaj narzędzi", "SearchApi API Key": "Klucz API SearchApi", - "SearchApi Engine": "Search API Engine", + "SearchApi Engine": "Silnik SearchApi", "Searched {{count}} sites": "Przeszukano {{count}} stron", - "Searching": "", - "Searching \"{{searchQuery}}\"": "Wyszukiwanie \"{{searchQuery}}\"", - "Searching Knowledge for \"{{searchQuery}}\"": "Przeszukiwanie wiedzy dla \"{{searchQuery}}\"", - "Searching the web": "Przeszukuję sieć Web...", - "Searxng Query URL": "Adres URL zapytania Searxng", - "Searxng search language (all, en, es, de, fr, etc.)": "", - "See readme.md for instructions": "Sprawdź readme.md dla instrukcji", - "See what's new": "Sprawdź nowości", + "Searching": "Wyszukiwanie", + "Searching \"{{searchQuery}}\"": "Szukanie \"{{searchQuery}}\"", + "Searching Knowledge for \"{{searchQuery}}\"": "Przeszukiwanie Wiedzy dla \"{{searchQuery}}\"", + "Searching the web": "Przeszukiwanie sieci...", + "Searxng Query URL": "URL zapytania Searxng", + "Searxng search language (all, en, es, de, fr, etc.)": "Język wyszukiwania Searxng (all, en, pl, de...)", + "See readme.md for instructions": "Zobacz readme.md po instrukcje", + "See what's new": "Zobacz co nowego", "Seed": "Seed", - "Select": "", - "Select a base model": "Wybór modelu bazowego", - "Select a base model (e.g. llama3, gpt-4o)": "", - "Select a conversation to preview": "", + "Select": "Wybierz", + "Select a base model": "Wybierz model bazowy", + "Select a base model (e.g. llama3, gpt-4o)": "Wybierz model bazowy (np. llama3, gpt-4o)", + "Select a conversation to preview": "Wybierz rozmowę do podglądu", "Select a engine": "Wybierz silnik", "Select a function": "Wybierz funkcję", "Select a group": "Wybierz grupę", - "Select a language": "", - "Select a mode": "", + "Select a language": "Wybierz język", + "Select a mode": "Wybierz tryb", "Select a model": "Wybierz model", - "Select a model (optional)": "", - "Select a pipeline": "Wybierz potok", - "Select a pipeline url": "Wybierz adres URL przepływu", - "Select a reranking model engine": "", - "Select a role": "", - "Select a theme": "", + "Select a model (optional)": "Wybierz model (opcjonalnie)", + "Select a pipeline": "Wybierz pipeline", + "Select a pipeline url": "Wybierz URL pipeline'u", + "Select a reranking model engine": "Wybierz silnik modelu rerankingu", + "Select a role": "Wybierz rolę", + "Select a theme": "Wybierz motyw", "Select a tool": "Wybierz narzędzie", - "Select a voice": "", - "Select an auth method": "Wybierz metodę uwierzytelniania", - "Select an embedding model engine": "", - "Select an engine": "", + "Select a voice": "Wybierz głos", + "Select an auth method": "Wybierz metodę autoryzacji", + "Select an embedding model engine": "Wybierz silnik modelu embeddingów", + "Select an engine": "Wybierz silnik", "Select an Ollama instance": "Wybierz instancję Ollama", - "Select an output format": "", - "Select dtype": "", + "Select an output format": "Wybierz format wyjściowy", + "Select dtype": "Wybierz dtype", "Select Engine": "Wybierz silnik", - "Select how to split message text for TTS requests": "", - "Select Knowledge": "Wybierz wiedzę", - "Select Method": "", + "Select how to split message text for TTS requests": "Wybierz sposób podziału tekstu dla TTS", + "Select Knowledge": "Wybierz bazę wiedzy", + "Select Method": "Wybierz metodę", "Select only one model to call": "Wybierz tylko jeden model do wywołania", - "Select view": "", - "Selected model(s) do not support image inputs": "Wybrane modele nie obsługują danych wejściowych w formie obrazu", - "semantic": "", + "Select view": "Wybierz widok", + "Selected model(s) do not support image inputs": "Wybrane modele nie obsługują obrazów", + "semantic": "semantyczny", "Send": "Wyślij", "Send a Message": "Wyślij wiadomość", "Send message": "Wyślij wiadomość", - "Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.": "Wysyła `stream_options: { include_usage: true }` w żądaniu.\nObsługiwani dostawcy zwrócą informacje o użyciu tokenów w odpowiedzi, gdy to ustawienie jest aktywne.", + "Sends `stream_options: { include_usage: true }` in the request.\nSupported providers will return token usage information in the response when set.": "Wysyła `stream_options: { include_usage: true }`. Obsługiwani dostawcy zwrócą zużycie tokenów.", "September": "Wrzesień", "SerpApi API Key": "Klucz API SerpApi", "SerpApi Engine": "Silnik SerpApi", "Serper API Key": "Klucz API Serper", "Serply API Key": "Klucz API Serply", "Serpstack API Key": "Klucz API Serpstack", - "Server connection verified": "Połączenie z serwerem zostało zweryfikowane", - "Session": "", + "Server connection verified": "Połączenie z serwerem zweryfikowane", + "Session": "Sesja", "Set as default": "Ustaw jako domyślny", - "Set embedding model": "Ustawianie modelu osadzania", - "Set embedding model (e.g. {{model}})": "Skonfiguruj model osadzania (np. {{model}})", - "Set reranking model (e.g. {{model}})": "Skonfiguruj model ponownego rankingu (np. {{model}})", - "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.": "Ustaw liczbę warstw, które zostaną przeniesione na GPU. Zwiększenie tej wartości może znacząco poprawić wydajność dla modeli optymalizowanych pod kątem akceleracji GPU, ale także może zużywać więcej energii i zasobów 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.": "Ustaw liczbę wątków pracowników używanych do obliczeń. Ta opcja kontroluje, ile wątków jest używanych do jednoczesnego przetwarzania przychodzących żądań. Zwiększenie tej wartości może poprawić wydajność pod wysokim obciążeniem, ale może również zużywać więcej zasobów CPU.", + "Set embedding model": "Ustaw model embeddingów", + "Set embedding model (e.g. {{model}})": "Ustaw model embeddingów (np. {{model}})", + "Set reranking model (e.g. {{model}})": "Ustaw model rerankingu (np. {{model}})", + "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.": "Ustaw liczbę warstw przenoszonych na GPU. Zwiększenie wartości poprawia wydajność, ale zużywa więcej pamięci VRAM.", + "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.": "Ustaw liczbę wątków roboczych (worker threads). Kontroluje równoległe przetwarzanie żądań.", "Set Voice": "Ustaw głos", - "Set whisper model": "Ustaw model szeptu", - "Set your status": "", - "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.": "", - "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.": "", - "Sets how far back for the model to look back to prevent repetition.": "", - "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.": "", - "Sets the size of the context window used to generate the next token.": "", - "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.": "Ustawia sekwencje stopu do użycia. Gdy ten wzorzec zostanie napotkany, LLM przestanie generować tekst i zwróci wynik. Można skonfigurować wiele sekwencji stopu, określając kilka oddzielnych parametrów stopu w pliku modelu.", - "Setting": "", + "Set whisper model": "Ustaw model Whisper", + "Set your status": "Ustaw status", + "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.": "Ustawia płaski bias (karę) dla użytych tokenów. Wyższa wartość = silniejsza kara za powtórzenia.", + "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.": "Ustawia skalowalny bias (karę) za powtórzenia. Wyższa wartość = silniejsza kara.", + "Sets how far back for the model to look back to prevent repetition.": "Określa jak daleko model sprawdza wstecz, by unikać powtórzeń.", + "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.": "Ustawia ziarno losowości (Seed). Konkretny numer gwarantuje powtarzalność wyników.", + "Sets the size of the context window used to generate the next token.": "Ustawia rozmiar okna kontekstowego (Context Window).", + "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.": "Ustawia sekwencje stop. Gdy wystąpią, LLM przerywa generowanie.", + "Setting": "Ustawienie", "Settings": "Ustawienia", - "Settings saved successfully!": "Ustawienia zostały zapisane pomyślnie!", + "Settings saved successfully!": "Ustawienia zapisane pomyślnie!", "Share": "Udostępnij", - "Share Chat": "Udostępnij rozmowę", - "Share to Open WebUI Community": "Udostępnij w społeczności OpenWebUI", - "Share your background and interests": "", - "Shared with you": "", + "Share Chat": "Udostępnij czat", + "Share to Open WebUI Community": "Udostępnij społeczności Open WebUI", + "Share your background and interests": "Udostępnij swoje tło i zainteresowania", + "Shared with you": "Udostępnione Tobie", "Sharing Permissions": "Uprawnienia udostępniania", - "Show": "Wyświetl", - "Show \"What's New\" modal on login": "Wyświetl okno dialogowe \"What's New\" podczas logowania", - "Show Admin Details in Account Pending Overlay": "Wyświetl szczegóły administratora w okienu informacyjnym o potrzebie zatwierdzenia przez administratora konta użytkownika", - "Show Files": "", - "Show Formatting Toolbar": "", - "Show image preview": "", - "Show Model": "", - "Show Shortcuts": "", - "Show your support!": "Wyraź swoje poparcie!", - "Showcased creativity": "Prezentacja kreatywności", + "Show": "Pokaż", + "Show \"What's New\" modal on login": "Pokaż okno \"Co nowego\" przy logowaniu", + "Show Admin Details in Account Pending Overlay": "Pokaż dane admina na ekranie oczekiwania", + "Show Files": "Pokaż pliki", + "Show Formatting Toolbar": "Pokaż pasek formatowania", + "Show image preview": "Pokaż podgląd obrazu", + "Show Model": "Pokaż model", + "Show Shortcuts": "Pokaż skróty", + "Show your support!": "Pokaż wsparcie!", + "Showcased creativity": "Kreatywność", "Sign in": "Zaloguj się", "Sign in to {{WEBUI_NAME}}": "Zaloguj się do {{WEBUI_NAME}}", - "Sign in to {{WEBUI_NAME}} with LDAP": "Zaloguj się do {{WEBUI_NAME}} przy użyciu LDAP", - "Sign Out": "Wyloguj się", + "Sign in to {{WEBUI_NAME}} with LDAP": "Zaloguj się do {{WEBUI_NAME}} przez LDAP", + "Sign Out": "Wyloguj", "Sign up": "Zarejestruj się", "Sign up to {{WEBUI_NAME}}": "Zarejestruj się w {{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.": "Znacząco poprawia dokładność używając LLM do tabel, wzorów i układu. Zwiększa opóźnienie. Domyślnie Fałsz.", "Signing in to {{WEBUI_NAME}}": "Logowanie do {{WEBUI_NAME}}", - "Sink List": "", + "Sink List": "Sink List", "sk-1234": "sk-1234", - "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": "", - "Sougou Search API sID": "", - "Sougou Search API SK": "", + "Skip Cache": "Pomiń Cache", + "Skip the cache and re-run the inference. Defaults to False.": "Pomiń pamięć podręczną i uruchom wnioskowanie ponownie. Domyślnie Fałsz.", + "Something went wrong :/": "Coś poszło nie tak :/", + "Sonar": "Sonar", + "Sonar Deep Research": "Sonar Deep Research", + "Sonar Pro": "Sonar Pro", + "Sonar Reasoning": "Sonar Reasoning", + "Sonar Reasoning Pro": "Sonar Reasoning Pro", + "Sort": "Sortuj", + "Sougou Search API sID": "sID Sougou Search API", + "Sougou Search API SK": "SK Sougou Search API", "Source": "Źródło", "Speech Playback Speed": "Prędkość odtwarzania mowy", "Speech recognition error: {{error}}": "Błąd rozpoznawania mowy: {{error}}", - "Speech-to-Text": "", - "Speech-to-Text Engine": "Silnik konwersji mowy na tekst", - "Start a new conversation": "", + "Speech-to-Text": "Speech-to-Text", + "Speech-to-Text Engine": "Silnik Speech-to-Text", + "Start a new conversation": "Rozpocznij nową rozmowę", "Start of the channel": "Początek kanału", - "Start Tag": "", - "Status": "", - "Status cleared successfully": "", - "Status updated successfully": "", - "Status Updates": "", + "Start Tag": "Tag startowy", + "Status": "Status", + "Status cleared successfully": "Status wyczyszczony pomyślnie", + "Status updated successfully": "Status zaktualizowany pomyślnie", + "Status Updates": "Aktualizacje statusu", "STDOUT/STDERR": "STDOUT/STDERR", - "Steps": "", - "Stop": "Zatrzymaj", - "Stop Generating": "", - "Stop Sequence": "Zatrzymaj sekwencję", - "Stream Chat Response": "Strumieniowanie odpowiedzi z czatu", - "Stream Delta Chunk Size": "", - "Streamable HTTP": "", + "Steps": "Kroki (Steps)", + "Stop": "Przerwij", + "Stop Generating": "Przerwij generowanie", + "Stop Sequence": "Sekwencja stop", + "Stream Chat Response": "Strumieniuj odpowiedź czatu", + "Stream Delta Chunk Size": "Chunk Size strumienia (Delta)", + "Streamable HTTP": "Streamable HTTP", "Strikethrough": "Przekreślenie", - "Strip Existing OCR": "", - "Strip existing OCR text from the PDF and re-run OCR. Ignored if Force OCR is enabled. Defaults to False.": "", + "Strip Existing OCR": "Usuń istniejący OCR", + "Strip existing OCR text from the PDF and re-run OCR. Ignored if Force OCR is enabled. Defaults to False.": "Usuń istniejący tekst OCR z PDF i uruchom ponownie. Ignorowane jeśli Wymuś OCR jest włączone. Domyślnie Fałsz.", "STT Model": "Model STT", "STT Settings": "Ustawienia STT", - "Stylized PDF Export": "", - "Subtitle": "", + "Stylized PDF Export": "Stylizowany eksport PDF", + "Subtitle": "Podtytuł", "Success": "Sukces", - "Successfully imported {{userCount}} users.": "", - "Successfully updated.": "Uaktualniono pomyślnie.", - "Suggest a change": "", - "Suggested": "Proponowane", + "Successfully imported {{userCount}} users.": "Pomyślnie zaimportowano {{userCount}} użytkowników.", + "Successfully updated.": "Zaktualizowano pomyślnie.", + "Suggest a change": "Zasugeruj zmianę", + "Suggested": "Sugerowane", "Support": "Wsparcie", "Support this plugin:": "Wesprzyj ten plugin:", - "Supported MIME Types": "", - "Sync directory": "Sync directory", + "Supported MIME Types": "Obsługiwane typy MIME", + "Sync directory": "Katalog synchronizacji", "System": "System", "System Instructions": "Instrukcje systemowe", "System Prompt": "Prompt systemowy", - "Tag": "", + "Tag": "Tag", "Tags": "Tagi", "Tags Generation": "Generowanie tagów", - "Tags Generation Prompt": "Prompt do generowania tagów", - "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.": "", - "Talk to Model": "", - "Tap to interrupt": "Kliknij, aby przerwać", + "Tags Generation Prompt": "Prompt generowania tagów", + "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 redukuje wpływ mało prawdopodobnych tokenów. Wyższa wartość (np. 2.0) = silniejsza redukcja. 1.0 wyłącza.", + "Talk to Model": "Rozmawiaj z modelem", + "Tap to interrupt": "Dotknij by przerwać", "Task List": "Lista zadań", - "Task Model": "", + "Task Model": "Model zadaniowy", "Tasks": "Zadania", "Tavily API Key": "Klucz API Tavily", - "Tavily Extract Depth": "", - "Tell us more:": "Podaj więcej informacji", - "Temperature": "Temperatura", - "Temporary Chat": "Tymczasowa rozmowa", - "Temporary Chat by Default": "", - "Text Splitter": "Rozdzielacz tekstu", - "Text-to-Speech": "Syntezator mowy", - "Text-to-Speech Engine": "Silnik konwersji tekstu na mowę", - "Thanks for your feedback!": "Dziękujemy za twoją opinię!", - "The Application Account DN you bind with for search": "Konto techniczne w formacie DN, z którym się wiążesz w celu przeszukiwania", - "The base to search for users": "Podstawa do wyszukiwania użytkowników", - "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.": "", - "The developers behind this plugin are passionate volunteers from the community. If you find this plugin helpful, please consider contributing to its development.": "Twórcy tego wtyczki to entuzjaści, którzy działają jako wolontariusze ze społeczności. Jeśli uważasz, że ta wtyczka jest pomocna, rozważ wsparcie jej rozwoju.", - "The evaluation leaderboard is based on the Elo rating system and is updated in real-time.": "Tablica wyników oceny opiera się na systemie rankingu Elo i jest aktualizowana w czasie rzeczywistym.", - "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 LDAP attribute that maps to the mail that users use to sign in.": "Atrybut LDAP, który mapuje się na adres e-mail używany przez użytkowników do logowania.", - "The LDAP attribute that maps to the username that users use to sign in.": "Atrybut LDAP, który mapuje się na nazwę użytkownika, którą użytkownicy używają do logowania.", - "The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.": "Tablica wyników jest w wersji beta, więc w miarę udoskonalania algorytmu możemy jeszcze modyfikować sposób obliczania ocen.", - "The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.": "Maksymalny rozmiar pliku w MB. Jeśli rozmiar pliku przekroczy ten limit, plik nie zostanie przesłany.", - "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.": "Maksymalna liczba plików, które można użyć jednocześnie w czacie. Jeśli liczba plików przekroczy ten limit, pliki nie zostaną przesłane.", - "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 score should be a value between 0.0 (0%) and 1.0 (100%).": "Wynik powinien być wartością pomiędzy 0,0 (0%) a 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 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": "", - "The width in pixels to compress images to. Leave empty for no compression.": "", + "Tavily Extract Depth": "Tavily Extract Depth", + "Tell us more:": "Powiedz nam więcej:", + "Temperature": "Temperature", + "Temporary Chat": "Czat tymczasowy", + "Temporary Chat by Default": "Domyślnie czat tymczasowy", + "Text Splitter": "Text Splitter", + "Text-to-Speech": "Text-to-Speech", + "Text-to-Speech Engine": "Silnik Text-to-Speech", + "Thanks for your feedback!": "Dzięki za opinię!", + "The Application Account DN you bind with for search": "DN konta aplikacji do wyszukiwania", + "The base to search for users": "Baza wyszukiwania użytkowników", + "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.": "Rozmiar wsadu (batch size) określa ile żądań jest przetwarzanych naraz. Wyższy = szybciej, ale wymaga więcej pamięci.", + "The developers behind this plugin are passionate volunteers from the community. If you find this plugin helpful, please consider contributing to its development.": "Twórcy tego pluginu to wolontariusze. Rozważ wsparcie jego rozwoju.", + "The evaluation leaderboard is based on the Elo rating system and is updated in real-time.": "Ranking oparty jest na systemie Elo i aktualizowany w czasie rzeczywistym.", + "The format to return a response in. Format can be json or a JSON schema.": "Format odpowiedzi (json lub schemat JSON).", + "The height in pixels to compress images to. Leave empty for no compression.": "Wysokość (px) do kompresji obrazów. Zostaw puste dla braku kompresji.", + "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.": "Język audio wejściowego (ISO-639-1, np. pl). Poprawia dokładność. Zostaw puste dla auto-wykrywania.", + "The LDAP attribute that maps to the mail that users use to sign in.": "Atrybut LDAP mapowany na email logowania.", + "The LDAP attribute that maps to the username that users use to sign in.": "Atrybut LDAP mapowany na nazwę użytkownika.", + "The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.": "Ranking jest w wersji beta, obliczenia mogą ulec zmianie.", + "The maximum file size in MB. If the file size exceeds this limit, the file will not be uploaded.": "Maksymalny rozmiar pliku (MB).", + "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.": "Maksymalna liczba plików w czacie.", + "The output format for the text. Can be 'json', 'markdown', or 'html'. Defaults to 'markdown'.": "Format wyjściowy tekstu (json, markdown, html). Domyślnie 'markdown'.", + "The passwords you entered don't quite match. Please double-check and try again.": "Hasła nie pasują. Sprawdź i spróbuj ponownie.", + "The score should be a value between 0.0 (0%) and 1.0 (100%).": "Wynik powinien być między 0.0 (0%) a 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.": "Rozmiar fragmentu strumienia. Większy = większe kawałki tekstu naraz.", + "The temperature of the model. Increasing the temperature will make the model answer more creatively.": "Temperatura modelu. Wyższa = bardziej kreatywne (losowe) odpowiedzi.", + "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "Waga BM25 w wyszukiwaniu hybrydowym. 0 = semantyczne, 1 = leksykalne. Domyślnie 0.5", + "The width in pixels to compress images to. Leave empty for no compression.": "Szerokość (px) do kompresji obrazów. Zostaw puste dla braku kompresji.", "Theme": "Motyw", "Thinking...": "Myślę...", - "This action cannot be undone. Do you wish to continue?": "Czy na pewno chcesz kontynuować? Ta akcja nie może zostać cofnięta.", - "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", - "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!": "To gwarantuje, że Twoje wartościowe rozmowy są bezpiecznie zapisywane w bazie danych backendowej. Dziękujemy!", - "This feature is experimental and may be modified or discontinued without notice.": "", - "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.": "To jest funkcja eksperymentalna, może nie działać zgodnie z oczekiwaniami i jest podatna na zmiany w dowolnym momencie.", - "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 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.": "", - "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 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.": "Ta opcja usunie wszystkie istniejące pliki w kolekcji i zastąpi je nowo przesłanymi plikami.", - "This response was generated by \"{{model}}\"": "Ta odpowiedź została wygenerowana przez \"{{model}}\".", - "This will delete": "To usunie wszystkie pliki z katalogu.", - "This will delete {{NAME}} and all its contents.": "To usunie {{NAME}} i wszystkie jego zawartości.", - "This will delete all models including custom models": "To usunie wszystkie modele, w tym niestandardowe.", - "This will delete all models including custom models and cannot be undone.": "To usunie wszystkie modele, w tym niestandardowe modele, i nie można tego cofnąć.", - "This will reset the knowledge base and sync all files. Do you wish to continue?": "Czy chcesz wyzerować bazę wiedzy i zsynchronizować wszystkie pliki? Proszę potwierdź swoją decyzję.", - "Thorough explanation": "Szczegółowe wyjaśnienie", - "Thought for {{DURATION}}": "Myślenie przez {{DURATION}}", - "Thought for {{DURATION}} seconds": "Myślenie przez {{DURATION}} sekund", - "Thought for less than a second": "", + "This action cannot be undone. Do you wish to continue?": "Tej akcji nie można cofnąć. Kontynuować?", + "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Ten kanał utworzono {{createdAt}}. To początek kanału {{channelName}}.", + "This chat won't appear in history and your messages will not be saved.": "Ten czat nie pojawi się w historii, a wiadomości nie zostaną zapisane.", + "This ensures that your valuable conversations are securely saved to your backend database. Thank you!": "To zapewnia bezpieczny zapis rozmów w bazie danych. Dziękujemy!", + "This feature is experimental and may be modified or discontinued without notice.": "Ta funkcja jest eksperymentalna i może zostać zmieniona.", + "This is a default user permission and will remain enabled.": "To domyślne uprawnienie i pozostanie włączone.", + "This is an experimental feature, it may not function as expected and is subject to change at any time.": "To funkcja eksperymentalna, może nie działać poprawnie.", + "This model is not publicly available. Please select another model.": "Ten model nie jest publicznie dostępny. Wybierz inny.", + "This option controls how long the model will stay loaded into memory following the request (default: 5m)": "Kontroluje jak długo model zostaje w pamięci po żądaniu (domyślnie: 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.": "Kontroluje ile tokenów jest zachowywanych przy odświeżaniu kontekstu.", + "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.": "Włącza funkcję reasoning w Ollama (myślenie przed odpowiedzią).", + "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 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).", + "This will delete all models including custom models and cannot be undone.": "To usunie wszystkie modele i jest nieodwracalne.", + "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 for {{DURATION}}": "Myślał przez {{DURATION}}", + "Thought for {{DURATION}} seconds": "Myślał przez {{DURATION}} sekund", + "Thought for less than a second": "Myślał krócej niż sekundę", "Thread": "Wątek", "Tika": "Tika", - "Tika Server URL required.": "Wymagany jest adres URL serwera Tika.", + "Tika Server URL required.": "Wymagany URL serwera Tika.", "Tiktoken": "Tiktoken", - "Timeout": "", + "Timeout": "Limit czasu (Timeout)", "Title": "Tytuł", - "Title Auto-Generation": "Automatyczne tworzenie tytułu", - "Title cannot be an empty string.": "Tytuł nie może być pustym stringiem.", - "Title Generation": "Generowanie tytułów", - "Title Generation Prompt": "Prompt do generowania tytułu", + "Title Auto-Generation": "Auto-generowanie tytułu", + "Title cannot be an empty string.": "Tytuł nie może być pusty.", + "Title Generation": "Generowanie tytułu", + "Title Generation Prompt": "Prompt generowania tytułu", "TLS": "TLS", - "To access the available model names for downloading,": "Aby wyświetlić dostępne nazwy modeli do pobrania,", - "To access the GGUF models available for downloading,": "Aby uzyskać dostęp do modeli GGUF dostępnych do pobrania,", - "To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Aby uzyskać dostęp do interfejsu WebUI, skontaktuj się z administratorem. Administratorzy mogą zarządzać statusami użytkowników z Panelu Administracyjnego.", - "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Aby dołączyć bazę wiedzy tutaj, dodaj je najpierw do przestrzeni roboczej \"Wiedza\". ", - "To learn more about available endpoints, visit our documentation.": "Aby dowiedzieć się więcej o dostępnych punktach końcowych, odwiedź naszą dokumentację.", - "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Aby chronić Twoją prywatność, udostępniane są tylko oceny, identyfikatory modeli, tagi i metadane z Twoich opinii – Twoje dzienniki czatu pozostają prywatne i nie są uwzględniane.", - "To select toolkits here, add them to the \"Tools\" workspace first.": "Aby wybrać zestawy narzędzi tutaj, dodaj je najpierw do przestrzeni roboczej \"Narzędzia\". ", - "Toast notifications for new updates": "Powiadomienia o nowych aktualizacjach", + "To access the available model names for downloading,": "Aby zobaczyć nazwy modeli do pobrania,", + "To access the GGUF models available for downloading,": "Aby zobaczyć modele GGUF do pobrania,", + "To access the WebUI, please reach out to the administrator. Admins can manage user statuses from the Admin Panel.": "Aby uzyskać dostęp, skontaktuj się z administratorem.", + "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Aby dołączyć Bazę wiedzy, dodaj ją najpierw w obszarze \"Knowledge\".", + "To learn more about available endpoints, visit our documentation.": "Odwiedź dokumentację, aby poznać dostępne endpointy.", + "To learn more about powerful prompt variables, click here": "Kliknij tutaj, aby poznać zmienne promptów", + "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Chronimy Twoją prywatność: udostępniane są tylko oceny i metadane, treść czatu pozostaje prywatna.", + "To select toolkits here, add them to the \"Tools\" workspace first.": "Aby wybrać narzędzia, dodaj je najpierw w obszarze \"Narzędzia\".", + "Toast notifications for new updates": "Powiadomienia o aktualizacjach", "Today": "Dzisiaj", - "Today at {{LOCALIZED_TIME}}": "", - "Toggle Sidebar": "", - "Toggle whether current connection is active.": "", + "Today at {{LOCALIZED_TIME}}": "Dzisiaj o {{LOCALIZED_TIME}}", + "Toggle Sidebar": "Przełącz pasek boczny", + "Toggle whether current connection is active.": "Przełącz aktywność połączenia.", "Token": "Token", - "Too verbose": "Zbyt rozwlekłe", + "Too verbose": "Zbyt gadatliwy", "Tool created successfully": "Narzędzie utworzone pomyślnie", - "Tool deleted successfully": "Narzędzie zostało usunięte pomyślnie", + "Tool deleted successfully": "Narzędzie usunięte pomyślnie", "Tool Description": "Opis narzędzia", - "Tool ID": "ID narzędzia", - "Tool imported successfully": "Narzędzie zostało pomyślnie zaimportowane", + "Tool ID": "ID Narzędzia", + "Tool imported successfully": "Narzędzie zaimportowane pomyślnie", "Tool Name": "Nazwa narzędzia", - "Tool Servers": "", + "Tool Servers": "Serwery narzędzi", "Tool updated successfully": "Narzędzie zaktualizowane pomyślnie", "Tools": "Narzędzia", - "Tools Access": "Narzędzia Dostępu", - "Tools are a function calling system with arbitrary code execution": "Narzędzia to system wywoływania funkcji z możliwością wykonania dowolnego kodu.", - "Tools Function Calling Prompt": "Narzędzia Funkcja Wywołania Promptu", - "Tools have a function calling system that allows arbitrary code execution.": "Narzędzia mają funkcję wywoływania systemu, która umożliwia wykonanie dowolnego kodu.", - "Tools Public Sharing": "", - "Tools Sharing": "", - "Top": "", - "Top K": "Najlepsze K", - "Top K Reranker": "", - "Transformers": "Transformery", - "Trouble accessing Ollama?": "Czy masz problemy z dostępem do Ollama?", - "Trust Proxy Environment": "", - "Try adjusting your search or filter to find what you are looking for.": "", - "Try Again": "", + "Tools Access": "Dostęp do narzędzi", + "Tools are a function calling system with arbitrary code execution": "Narzędzia to system wywoływania funkcji z wykonywaniem kodu", + "Tools Function Calling Prompt": "Prompt wywoływania funkcji (Tools)", + "Tools have a function calling system that allows arbitrary code execution.": "Narzędzia posiadają system wywoływania funkcji pozwalający na wykonywanie kodu.", + "Tools Public Sharing": "Publiczne udostępnianie narzędzi", + "Tools Sharing": "Udostępnianie narzędzi", + "Top": "Góra", + "Top K": "Top K", + "Top K Reranker": "Top K Reranker", + "Transformers": "Transformers", + "Trouble accessing Ollama?": "Problem z dostępem do Ollama?", + "Trust Proxy Environment": "Ufaj środowisku Proxy", + "Try adjusting your search or filter to find what you are looking for.": "Spróbuj zmienić wyszukiwanie lub filtry.", + "Try Again": "Spróbuj ponownie", "TTS Model": "Model TTS", - "TTS Settings": "Ustawienia syntezatora mowy", + "TTS Settings": "Ustawienia TTS", "TTS Voice": "Głos TTS", "Type": "Typ", - "Type here...": "", - "Type Hugging Face Resolve (Download) URL": "Podaj adres URL do pobrania z Hugging Face", + "Type here...": "Pisz tutaj...", + "Type Hugging Face Resolve (Download) URL": "Wpisz URL Hugging Face Resolve (Pobieranie)", "Uh-oh! There was an issue with the response.": "Ojej! Wystąpił problem z odpowiedzią.", - "UI": "Interfejs użytkownika", - "UI Scale": "", + "UI": "Interfejs (UI)", + "UI Scale": "Skala UI", "Unarchive All": "Odarchiwizuj wszystko", - "Unarchive All Archived Chats": "Odarchiwizuj wszystkie zarchiwizowane rozmowy", + "Unarchive All Archived Chats": "Odarchiwizuj wszystkie czaty", "Unarchive Chat": "Odarchiwizuj czat", "Underline": "Podkreślenie", - "Unknown": "", - "Unknown User": "", - "Unloads {{FROM_NOW}}": "", - "Unlock mysteries": "Rozwiązywanie zagadek", - "Unpin": "Odpiąć", - "Unravel secrets": "Odkryj tajemnice", - "Unsupported file type.": "", - "Untagged": "Nie otagowane", - "Untitled": "", - "Update": "Aktualizacja", + "Unknown": "Nieznany", + "Unknown User": "Nieznany użytkownik", + "Unloads {{FROM_NOW}}": "Odładowuje za {{FROM_NOW}}", + "Unlock mysteries": "Odkrywaj tajemnice", + "Unpin": "Odepnij", + "Unravel secrets": "Rozwiązuj zagadki", + "Unsupported file type.": "Nieobsługiwany typ pliku.", + "Untagged": "Bez tagów", + "Untitled": "Bez tytułu", + "Update": "Aktualizuj", "Update and Copy Link": "Aktualizuj i kopiuj link", - "Update for the latest features and improvements.": "Aktualizacja do najnowszych funkcji i ulepszeń.", - "Update password": "Zmiana hasła", - "Update your status": "", + "Update for the latest features and improvements.": "Zaktualizuj, aby uzyskać nowe funkcje.", + "Update password": "Zaktualizuj hasło", + "Update your status": "Zaktualizuj status", "Updated": "Zaktualizowano", - "Updated at": "Aktualizacja dnia", - "Updated At": "Czas aktualizacji", - "Upgrade to a licensed plan for enhanced capabilities, including custom theming and branding, and dedicated support.": "Przejdź na licencjonowany plan, aby uzyskać rozszerzone możliwości, w tym niestandardowe motywy, personalizację oraz dedykowane wsparcie.", + "Updated at": "Zaktualizowano", + "Updated At": "Data aktualizacji", + "Upgrade to a licensed plan for enhanced capabilities, including custom theming and branding, and dedicated support.": "Ulepsz do planu licencjonowanego, aby uzyskać branding i wsparcie.", "Upload": "Prześlij", "Upload a GGUF model": "Prześlij model GGUF", "Upload Audio": "Prześlij audio", "Upload directory": "Prześlij katalog", "Upload files": "Prześlij pliki", "Upload Files": "Prześlij pliki", - "Upload Model": "", - "Upload Pipeline": "Prześlij przepływ", - "Upload Progress": "Postęp przesyłania plików", - "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", - "Uploading file...": "", - "URL": "Adres URL", - "URL is required": "", + "Upload Model": "Prześlij Model", + "Upload Pipeline": "Prześlij Pipeline", + "Upload Progress": "Postęp przesyłania", + "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Postęp: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploading file...": "Przesyłanie pliku...", + "URL": "URL", + "URL is required": "URL jest wymagany", "URL Mode": "Tryb URL", - "Usage": "", - "Use '#' in the prompt input to load and include your knowledge.": "Użyj '#' w polu wprowadzania zapytania, aby załadować i uwzględnić swoją wiedzę.", - "Use /v1/chat/completions endpoint instead of /v1/audio/transcriptions for potentially better accuracy.": "", - "Use Chat Completions API": "", - "Use groups to group your users and assign permissions.": "Wykorzystaj grupy do grupowania użytkowników i przypisywania uprawnień.", - "Use LLM": "", - "Use no proxy to fetch page contents.": "", - "Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "", + "Usage": "Wykorzystanie", + "Use '#' in the prompt input to load and include your knowledge.": "Użyj '#' w prompcie, aby załadować Bazę wiedzy.", + "Use /v1/chat/completions endpoint instead of /v1/audio/transcriptions for potentially better accuracy.": "Użyj endpointu /v1/chat/completions zamiast /v1/audio/transcriptions dla lepszej dokładności.", + "Use Chat Completions API": "Użyj Chat Completions API", + "Use groups to group your users and assign permissions.": "Użyj grup do zarządzania uprawnieniami.", + "Use LLM": "Użyj LLM", + "Use no proxy to fetch page contents.": "Nie używaj proxy do pobierania stron.", + "Use proxy designated by http_proxy and https_proxy environment variables to fetch page contents.": "Używaj proxy ze zmiennych środowiskowych do pobierania stron.", "user": "użytkownik", "User": "Użytkownik", - "User Groups": "", - "User location successfully retrieved.": "Lokalizacja użytkownika została pomyślnie pobrana.", - "User menu": "", + "User Groups": "Grupy użytkowników", + "User location successfully retrieved.": "Lokalizacja użytkownika pobrana pomyślnie.", + "User menu": "Menu użytkownika", "User Webhooks": "Webhooki użytkownika", "Username": "Nazwa użytkownika", - "users": "", + "users": "użytkownicy", "Users": "Użytkownicy", - "Uses DefaultAzureCredential to authenticate": "", - "Uses OAuth 2.1 Dynamic Client Registration": "", - "Using Entire Document": "", - "Using Focused Retrieval": "", - "Using the default arena model with all models. Click the plus button to add custom models.": "Korzystanie z domyślnego modelu areny ze wszystkimi modelami. Kliknij przycisk plus, aby dodać niestandardowe modele.", - "Valid time units:": "Dozwolone jednostki czasu:", - "Validate certificate": "", - "Valves": "Zawory", - "Valves updated": "Zawory zaktualizowane", - "Valves updated successfully": "Zawory zaktualizowane pomyślnie", + "Uses DefaultAzureCredential to authenticate": "Używa DefaultAzureCredential do autoryzacji", + "Uses OAuth 2.1 Dynamic Client Registration": "Używa OAuth 2.1 Dynamic Client Registration", + "Using Entire Document": "Używanie całego dokumentu", + "Using Focused Retrieval": "Używanie Focused Retrieval", + "Using the default arena model with all models. Click the plus button to add custom models.": "Używanie domyślnego modelu arena. Kliknij plus aby dodać własne.", + "Valid time units:": "Poprawne jednostki czasu:", + "Validate certificate": "Waliduj certyfikat", + "Valves": "Valves", + "Valves updated": "Valves zaktualizowane", + "Valves updated successfully": "Valves zaktualizowane pomyślnie", "variable": "zmienna", "Verify Connection": "Sprawdź połączenie", - "Verify SSL Certificate": "Sprawdź certyfikat SSL", + "Verify SSL Certificate": "Weryfikuj certyfikat SSL", "Version": "Wersja", "Version {{selectedVersion}} of {{totalVersions}}": "Wersja {{selectedVersion}} z {{totalVersions}}", - "View Replies": "Wyświetl odpowiedzi", - "View Result from **{{NAME}}**": "", + "View Replies": "Zobacz odpowiedzi", + "View Result from **{{NAME}}**": "Zobacz wynik od **{{NAME}}**", "Visibility": "Widoczność", - "Visible to all users": "", - "Vision": "", + "Visible to all users": "Widoczne dla wszystkich", + "Vision": "Analiza obrazu", "Voice": "Głos", "Voice Input": "Wprowadzanie głosowe", - "Voice mode": "", - "Voice Mode Custom Prompt": "", - "Voice Mode Prompt": "", - "Warning": "Uwaga", - "Warning:": "Uwaga:", - "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Uwaga: Włączenie tego pozwoli użytkownikom na przesyłanie dowolnego kodu na serwer.", - "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Uwaga: Uruchamianie Jupytera umożliwia wykonywanie dowolnego kodu, co stwarza poważne zagrożenia dla bezpieczeństwa – postępuj z ekstremalną ostrożnością.", - "Web": "Sieć internetowa", - "Web API": "Interfejs API sieci web", - "Web Loader Engine": "", - "Web Search": "Wyszukiwarka internetowa", - "Web Search Engine": "Silnik wyszukiweania w sieci", - "Web Search in Chat": "Wyszukiwanie w sieci Web na czacie", - "Web Search Query Generation": "Generowanie zapytań Wyszukiwania Sieciowego", - "Webhook URL": "Adres URL webhooka", - "Webpage URLs": "", - "WebUI Settings": "Ustawienia interfejsu WebUI", - "WebUI URL": "Adres URL interfejsu internetowego", + "Voice mode": "Tryb głosowy", + "Voice Mode Custom Prompt": "Własny prompt trybu głosowego", + "Voice Mode Prompt": "Prompt trybu głosowego", + "Warning": "Ostrzeżenie", + "Warning:": "Ostrzeżenie:", + "Warning: Enabling this will allow users to upload arbitrary code on the server.": "Ostrzeżenie: Włączenie tego pozwoli na przesyłanie dowolnego kodu na serwer.", + "Warning: Jupyter execution enables arbitrary code execution, posing severe security risks—proceed with extreme caution.": "Ostrzeżenie: Jupyter umożliwia wykonanie dowolnego kodu (ryzyko bezpieczeństwa).", + "Web": "Web", + "Web API": "Web API", + "Web Loader Engine": "Silnik Web Loader", + "Web Search": "Wyszukiwanie w sieci", + "Web Search Engine": "Silnik wyszukiwania", + "Web Search in Chat": "Wyszukiwanie w czacie", + "Web Search Query Generation": "Generowanie zapytań wyszukiwania", + "Webhook URL": "URL Webhooka", + "Webpage URLs": "Adresy URL stron", + "WebUI Settings": "Ustawienia WebUI", + "WebUI URL": "URL WebUI", "WebUI will make requests to \"{{url}}\"": "WebUI będzie wysyłać żądania do \"{{url}}\"", "WebUI will make requests to \"{{url}}/api/chat\"": "WebUI będzie wysyłać żądania do \"{{url}}/api/chat\"", "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI będzie wysyłać żądania do \"{{url}}/chat/completions\"", - "What are you trying to achieve?": "Do czego dążysz?", + "What are you trying to achieve?": "Co chcesz osiągnąć?", "What are you working on?": "Nad czym pracujesz?", "What's New in": "Co nowego w", - "What's on your mind?": "", - "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.": "Gdy jest włączony, model będzie reagował na każdą wiadomość czatu w czasie rzeczywistym, generując odpowiedź tak szybko, jak użytkownik wyśle wiadomość. Ten tryb jest przydatny dla aplikacji czatu na żywo, ale może wpływać na wydajność na wolniejszym sprzęcie.", + "What's on your mind?": "O czym myślisz?", + "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.": "Gdy włączone, model odpowiada w czasie rzeczywistym.", "wherever you are": "gdziekolwiek jesteś", - "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", - "Whisper (Local)": "Szept (Lokalny)", + "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Czy stronicować wyjście. Domyślnie Fałsz.", + "Whisper (Local)": "Whisper (Lokalny)", "Why?": "Dlaczego?", - "Widescreen Mode": "Tryb panoramiczny", - "Width": "", - "Won": "Wygrał", - "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.": "", + "Widescreen Mode": "Tryb szerokoekranowy", + "Width": "Szerokość", + "Won": "Wygrano", + "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.": "Działa razem z top-k. Wyższa wartość = większa różnorodność.", "Workspace": "Obszar roboczy", - "Workspace Permissions": "Uprawnienia do przestrzeni roboczej", - "Write": "Napisz", - "Write a summary in 50 words that summarizes {{topic}}.": "Napisz krótkie podsumowanie w maksymalnie 50 słowach, które streszcza [temat lub słowo kluczowe].", + "Workspace Permissions": "Uprawnienia obszaru roboczego", + "Write": "Pisz", + "Write a summary in 50 words that summarizes {{topic}}.": "Napisz podsumowanie {{topic}} w 50 słowach.", "Write something...": "Napisz coś...", - "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "Wpisz tutaj treść systemowego promptu swojego modelu\nnp.: Jesteś Mario z Super Mario Bros i działasz jako asystent.", - "Yacy Instance URL": "", - "Yacy Password": "", - "Yacy Username": "", + "Write your model system prompt content here\ne.g.) You are Mario from Super Mario Bros, acting as an assistant.": "Wpisz treść promptu systemowego tutaj\nnp. Jesteś Mario, działasz jako asystent.", + "Yacy Instance URL": "URL instancji Yacy", + "Yacy Password": "Hasło Yacy", + "Yacy Username": "Nazwa użytkownika Yacy", "Yesterday": "Wczoraj", - "Yesterday at {{LOCALIZED_TIME}}": "", + "Yesterday at {{LOCALIZED_TIME}}": "Wczoraj o {{LOCALIZED_TIME}}", "You": "Ty", - "You are currently using a trial license. Please contact support to upgrade your license.": "Obecnie używasz licencji trial. Skontaktuj się z supportem, aby zupgradować Twoją licencję.", - "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Możesz rozmawiać jednocześnie maksymalnie z {{maxCount}} plikiem(i).", - "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Możesz spersonalizować swoje interakcje z LLM, dodając wspomnienia za pomocą przycisku 'Zarządzaj' poniżej, dzięki czemu będą one bardziej pomocne i dostosowane do Ciebie.", + "You are currently using a trial license. Please contact support to upgrade your license.": "Używasz licencji próbnej. Skontaktuj się ze wsparciem.", + "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Możesz rozmawiać z maksymalnie {{maxCount}} plikami naraz.", + "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Możesz personalizować interakcje dodając wspomnienia przyciskiem 'Zarządzaj'.", "You cannot upload an empty file.": "Nie możesz przesłać pustego pliku.", - "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 send messages in this channel.": "Nie masz uprawnień do wysyłania wiadomości w tym kanale.", + "You do not have permission to send messages in this thread.": "Nie masz uprawnień do wysyłania wiadomości w tym wątku.", + "You do not have permission to upload files to this knowledge base.": "Nie masz uprawnień do przesyłania plików do tej bazy wiedzy.", "You do not have permission to upload files.": "Nie masz uprawnień do przesyłania plików.", - "You have no archived conversations.": "Nie posiadasz zarchiwizowanych konwersacji.", - "You have shared this chat": "Udostępniłeś tę rozmowę", + "You have no archived conversations.": "Nie masz zarchiwizowanych rozmów.", + "You have shared this chat": "Udostępniłeś ten czat", "You're a helpful assistant.": "Jesteś pomocnym asystentem.", - "You're now logged in.": "Jesteś teraz zalogowany.", - "Your Account": "", - "Your account status is currently pending activation.": "Twoje konto oczekuje obecnie na aktywację.", - "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.": "Cała Twoja wpłata trafi bezpośrednio do dewelopera wtyczki; Open WebUI nie pobiera żadnej prowizji. Należy jednak pamiętać, że wybrana platforma finansowania może mieć własne opłaty.", - "YouTube": "Youtube", - "Youtube Language": "Język Youtube", - "Youtube Proxy URL": "URL proxy Youtube" + "You're now logged in.": "Zalogowano pomyślnie.", + "Your Account": "Twoje konto", + "Your account status is currently pending activation.": "Twoje konto oczekuje na aktywację.", + "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.": "Cała wpłata trafia do twórcy pluginu; Open WebUI nie pobiera prowizji.", + "YouTube": "YouTube", + "Youtube Language": "Język YouTube", + "Youtube Proxy URL": "URL Proxy YouTube" } From 732d9b484db97a81ff7c8f71b16ad08d05da2477 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 6 Jan 2026 18:26:14 +0100 Subject: [PATCH 155/254] fix: resolve N+1 query pattern in users endpoint (#20427) ## Summary Fixed N+1 query pattern in the `/api/v1/users` endpoint where groups were being fetched for each user individually. ### Problem The `GET /api/v1/users` endpoint called `Groups.get_groups_by_member_id()` for each user, resulting in: - 1 query for users - N queries for groups (one per user) ### Solution Added a new `Groups.get_groups_by_member_ids()` method that fetches groups for multiple users in a single query using SQL `IN` clause and `JOIN`. ### Changes - **[groups.py](open_webui/models/groups.py)**: Added `get_groups_by_member_ids()` method - **[users.py](open_webui/routers/users.py)**: Updated endpoint to use bulk method ### Result - Before: 1 + N queries - After: 2 queries total (1 for users, 1 for all groups) --- backend/open_webui/models/groups.py | 21 +++++++++++++++++++++ backend/open_webui/routers/users.py | 9 +++++---- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/backend/open_webui/models/groups.py b/backend/open_webui/models/groups.py index 053125a6d0..ae557f4daf 100644 --- a/backend/open_webui/models/groups.py +++ b/backend/open_webui/models/groups.py @@ -271,6 +271,27 @@ class GroupTable: .all() ] + def get_groups_by_member_ids( + self, user_ids: list[str], db: Optional[Session] = None + ) -> dict[str, list[GroupModel]]: + """Fetch groups for multiple users in a single query to avoid N+1.""" + with get_db_context(db) as db: + # Query GroupMember joined with Group, filtering by user_ids + results = ( + db.query(GroupMember.user_id, Group) + .join(Group, Group.id == GroupMember.group_id) + .filter(GroupMember.user_id.in_(user_ids)) + .order_by(Group.updated_at.desc()) + .all() + ) + + # Group groups by user_id + user_groups: dict[str, list[GroupModel]] = {uid: [] for uid in user_ids} + for user_id, group in results: + user_groups[user_id].append(GroupModel.model_validate(group)) + + return user_groups + def get_group_by_id( self, id: str, db: Optional[Session] = None ) -> Optional[GroupModel]: diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index f1758f26ac..3c3d22c613 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -84,15 +84,16 @@ async def get_users( users = result["users"] total = result["total"] + # Fetch groups for all users in a single query to avoid N+1 + user_ids = [user.id for user in users] + user_groups = Groups.get_groups_by_member_ids(user_ids, db=db) + return { "users": [ UserGroupIdsModel( **{ **user.model_dump(), - "group_ids": [ - group.id - for group in Groups.get_groups_by_member_id(user.id, db=db) - ], + "group_ids": [group.id for group in user_groups.get(user.id, [])], } ) for user in users From 502813c6c80a770669f8be21c8b0908f3a5fb6c7 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Tue, 6 Jan 2026 20:01:10 +0100 Subject: [PATCH 156/254] chore: aggregation (#20430) * Update EditGroupModal.svelte * Update Permissions.svelte * Create permissions.ts --- .../admin/Users/Groups/EditGroupModal.svelte | 72 +++---------------- .../admin/Users/Groups/Permissions.svelte | 62 +--------------- src/lib/constants/permissions.ts | 60 ++++++++++++++++ 3 files changed, 72 insertions(+), 122 deletions(-) create mode 100644 src/lib/constants/permissions.ts diff --git a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte index daf056d598..791aa9f0fc 100644 --- a/src/lib/components/admin/Users/Groups/EditGroupModal.svelte +++ b/src/lib/components/admin/Users/Groups/EditGroupModal.svelte @@ -8,6 +8,7 @@ import General from './General.svelte'; import Permissions from './Permissions.svelte'; import Users from './Users.svelte'; + import { DEFAULT_PERMISSIONS } from '$lib/constants/permissions'; import UserPlusSolid from '$lib/components/icons/UserPlusSolid.svelte'; import WrenchSolid from '$lib/components/icons/WrenchSolid.svelte'; import ConfirmDialog from '$lib/components/common/ConfirmDialog.svelte'; @@ -36,66 +37,7 @@ export let description = ''; export let data = {}; - export let permissions = { - workspace: { - models: false, - knowledge: false, - prompts: false, - tools: false, - models_import: false, - models_export: false, - prompts_import: false, - prompts_export: false, - tools_import: false, - tools_export: false - }, - sharing: { - models: false, - public_models: false, - knowledge: false, - public_knowledge: false, - prompts: false, - public_prompts: false, - tools: false, - public_tools: false, - notes: false, - public_notes: false - }, - chat: { - controls: true, - valves: true, - system_prompt: true, - params: true, - file_upload: true, - delete: true, - delete_message: true, - continue_response: true, - regenerate_response: true, - rate_response: true, - edit: true, - share: true, - export: true, - stt: true, - tts: true, - call: true, - multiple_models: true, - temporary: true, - temporary_enforced: false - }, - features: { - api_keys: false, - notes: true, - channels: true, - folders: true, - direct_tool_servers: false, - web_search: true, - image_generation: true, - code_interpreter: true - }, - settings: { - interface: true - } - }; + export let permissions = DEFAULT_PERMISSIONS; const submitHandler = async () => { loading = true; @@ -117,7 +59,15 @@ if (group) { name = group.name; description = group.description; - permissions = group?.permissions ?? {}; + const loadedPermissions = group?.permissions ?? {}; + // Create fresh object from defaults, then overlay loaded values + permissions = { + workspace: { ...DEFAULT_PERMISSIONS.workspace, ...loadedPermissions.workspace }, + sharing: { ...DEFAULT_PERMISSIONS.sharing, ...loadedPermissions.sharing }, + chat: { ...DEFAULT_PERMISSIONS.chat, ...loadedPermissions.chat }, + features: { ...DEFAULT_PERMISSIONS.features, ...loadedPermissions.features }, + settings: { ...DEFAULT_PERMISSIONS.settings, ...loadedPermissions.settings } + }; data = group?.data ?? {}; userCount = group?.member_count ?? 0; diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index db73ca3bee..28b7b4c2c8 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -5,67 +5,7 @@ import Switch from '$lib/components/common/Switch.svelte'; import Tooltip from '$lib/components/common/Tooltip.svelte'; - // Default values for permissions - const DEFAULT_PERMISSIONS = { - workspace: { - models: false, - knowledge: false, - prompts: false, - tools: false, - models_import: false, - models_export: false, - prompts_import: false, - prompts_export: false, - tools_import: false, - tools_export: false - }, - sharing: { - models: false, - public_models: false, - knowledge: false, - public_knowledge: false, - prompts: false, - public_prompts: false, - tools: false, - public_tools: false, - notes: false, - public_notes: false - }, - chat: { - controls: true, - valves: true, - system_prompt: true, - params: true, - file_upload: true, - delete: true, - delete_message: true, - continue_response: true, - regenerate_response: true, - rate_response: true, - edit: true, - share: true, - export: true, - stt: true, - tts: true, - call: true, - multiple_models: true, - temporary: true, - temporary_enforced: false - }, - features: { - api_keys: false, - notes: true, - channels: true, - folders: true, - direct_tool_servers: false, - web_search: true, - image_generation: true, - code_interpreter: true - }, - settings: { - interface: true - } - }; + import { DEFAULT_PERMISSIONS } from '$lib/constants/permissions'; export let permissions = {}; export let defaultPermissions = {}; diff --git a/src/lib/constants/permissions.ts b/src/lib/constants/permissions.ts new file mode 100644 index 0000000000..d40cda0908 --- /dev/null +++ b/src/lib/constants/permissions.ts @@ -0,0 +1,60 @@ +export const DEFAULT_PERMISSIONS = { + workspace: { + models: false, + knowledge: false, + prompts: false, + tools: false, + models_import: false, + models_export: false, + prompts_import: false, + prompts_export: false, + tools_import: false, + tools_export: false + }, + sharing: { + models: false, + public_models: false, + knowledge: false, + public_knowledge: false, + prompts: false, + public_prompts: false, + tools: false, + public_tools: false, + notes: false, + public_notes: false + }, + chat: { + controls: true, + valves: true, + system_prompt: true, + params: true, + file_upload: true, + delete: true, + delete_message: true, + continue_response: true, + regenerate_response: true, + rate_response: true, + edit: true, + share: true, + export: true, + stt: true, + tts: true, + call: true, + multiple_models: true, + temporary: true, + temporary_enforced: false + }, + features: { + api_keys: false, + notes: true, + channels: true, + folders: true, + direct_tool_servers: false, + web_search: true, + image_generation: true, + code_interpreter: true + }, + settings: { + interface: true + } +} as const; From 60e916d6c0c5f7db9e6d670e12be2d1d4abc2dd6 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Wed, 7 Jan 2026 06:22:17 -0500 Subject: [PATCH 157/254] enh: built-in tools toggle in model editor --- backend/open_webui/utils/middleware.py | 6 ++++-- src/lib/components/workspace/Models/Capabilities.svelte | 5 +++++ src/lib/components/workspace/Models/ModelEditor.svelte | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 412c33842a..162857ef43 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1556,8 +1556,10 @@ async def process_chat_payload(request, form_data, user, metadata, model): if mcp_clients: metadata["mcp_clients"] = mcp_clients - # Always inject builtin tools for native function calling based on enabled features - if metadata.get("params", {}).get("function_calling") == "native": + # Inject builtin tools for native function calling based on enabled features and model capability + # Check if builtin_tools capability is enabled for this model (defaults to True if not specified) + builtin_tools_enabled = model.get("info", {}).get("meta", {}).get("capabilities", {}).get("builtin_tools", True) + if metadata.get("params", {}).get("function_calling") == "native" and builtin_tools_enabled: builtin_tools = get_builtin_tools( request, { diff --git a/src/lib/components/workspace/Models/Capabilities.svelte b/src/lib/components/workspace/Models/Capabilities.svelte index f1e9741dfe..4f2c4988d1 100644 --- a/src/lib/components/workspace/Models/Capabilities.svelte +++ b/src/lib/components/workspace/Models/Capabilities.svelte @@ -40,6 +40,10 @@ status_updates: { label: $i18n.t('Status Updates'), description: $i18n.t('Displays status updates (e.g., web search progress) in the response') + }, + builtin_tools: { + label: $i18n.t('Builtin Tools'), + description: $i18n.t('Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)') } }; @@ -52,6 +56,7 @@ usage?: boolean; citations?: boolean; status_updates?: boolean; + builtin_tools?: boolean; } = {}; diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index af863cc860..8307cb5e41 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -99,7 +99,8 @@ code_interpreter: true, citations: true, status_updates: true, - usage: undefined + usage: undefined, + builtin_tools: true }; let defaultFeatureIds = []; From 2789f6a24d8405c30cd48ae460071f6a4f2c35f9 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Wed, 7 Jan 2026 07:00:32 -0500 Subject: [PATCH 158/254] enh: builtin tools --- backend/open_webui/utils/middleware.py | 182 ++++++++++++++++++------- backend/open_webui/utils/tools.py | 19 ++- 2 files changed, 142 insertions(+), 59 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 162857ef43..3675a9846f 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -142,6 +142,104 @@ DEFAULT_SOLUTION_TAGS = [("<|begin_of_solution|>", "<|end_of_solution|>")] DEFAULT_CODE_INTERPRETER_TAGS = [("", "")] +def get_citation_source_from_tool_result( + tool_name: str, + tool_params: dict, + tool_result: str, + tool_id: str = "" +) -> dict: + """ + Parse a tool's result and convert it to a source dict for citation display. + + For web_search: extracts title, link, snippet from each search result. + For other tools: wraps the raw result as a generic source. + """ + try: + if tool_name == "web_search": + # Parse JSON array: [{"title": "...", "link": "...", "snippet": "..."}] + results = json.loads(tool_result) + documents = [] + metadata = [] + + for result in results: + title = result.get("title", "") + link = result.get("link", "") + snippet = result.get("snippet", "") + + documents.append(f"{title}\n{snippet}") + metadata.append({ + "source": link, + "name": title, + "url": link, + }) + + return { + "source": {"name": "web_search", "id": "web_search"}, + "document": documents, + "metadata": metadata, + } + else: + # Fallback for other tools + return { + "source": {"name": tool_name, "id": tool_id or tool_name}, + "document": [str(tool_result)], + "metadata": [{"source": tool_id or tool_name, "parameters": tool_params}], + } + except Exception as e: + log.exception(f"Error parsing tool result for {tool_name}: {e}") + return { + "source": {"name": tool_name, "id": tool_id or tool_name}, + "document": [str(tool_result)], + "metadata": [{"source": tool_id or tool_name}], + } + + +def apply_source_context_to_messages( + request: Request, + messages: list, + sources: list, + user_message: str, +) -> list: + """ + Build source context from citation sources and apply to messages. + Uses RAG template to format context for model consumption. + """ + if not sources or not user_message: + return messages + + context_string = "" + citation_idx = {} + + for source in sources: + for doc, meta in zip(source.get("document", []), source.get("metadata", [])): + src_id = meta.get("source") or source.get("source", {}).get("id") or "N/A" + if src_id not in citation_idx: + citation_idx[src_id] = len(citation_idx) + 1 + src_name = source.get("source", {}).get("name") + context_string += ( + f'{doc}\n" + ) + + context_string = context_string.strip() + if not context_string: + return messages + + if RAG_SYSTEM_CONTEXT: + return add_or_update_system_message( + rag_template(request.app.state.config.RAG_TEMPLATE, context_string, user_message), + messages, + append=True, + ) + else: + return add_or_update_user_message( + rag_template(request.app.state.config.RAG_TEMPLATE, context_string, user_message), + messages, + append=False, + ) + + def process_tool_result( request, tool_function_name, @@ -1567,6 +1665,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): "__event_emitter__": event_emitter, }, features, + model, ) for name, tool_dict in builtin_tools.items(): if name not in tools_dict: @@ -1599,58 +1698,10 @@ async def process_chat_payload(request, form_data, user, metadata, model): log.exception(e) # If context is not empty, insert it into the messages - if len(sources) > 0: - context_string = "" - citation_idx_map = {} - - for source in sources: - if "document" in source: - for document_text, document_metadata in zip( - source["document"], source["metadata"] - ): - source_name = source.get("source", {}).get("name", None) - source_id = ( - document_metadata.get("source", None) - or source.get("source", {}).get("id", None) - or "N/A" - ) - - if source_id not in citation_idx_map: - citation_idx_map[source_id] = len(citation_idx_map) + 1 - - context_string += ( - f'{document_text}\n" - ) - - context_string = context_string.strip() - if prompt is None: - raise Exception("No user message found") - - if context_string != "": - if RAG_SYSTEM_CONTEXT: - # Inject into system message for KV prefix caching - form_data["messages"] = add_or_update_system_message( - rag_template( - request.app.state.config.RAG_TEMPLATE, - context_string, - prompt, - ), - form_data["messages"], - append=True, - ) - else: - # Inject into user message - form_data["messages"] = add_or_update_user_message( - rag_template( - request.app.state.config.RAG_TEMPLATE, - context_string, - prompt, - ), - form_data["messages"], - append=False, - ) + if sources and prompt: + form_data["messages"] = apply_source_context_to_messages( + request, form_data["messages"], sources, prompt + ) # If there are citations, add them to the data_items sources = [ @@ -2977,6 +3028,7 @@ async def process_chat_response( await stream_body_handler(response, form_data) tool_call_retries = 0 + tool_call_sources = [] # Track citation sources from tool results while ( len(tool_calls) > 0 @@ -3111,6 +3163,19 @@ async def process_chat_response( ) ) + # Extract citation sources from web_search results + if tool_function_name == "web_search" and tool_result: + try: + citation_source = get_citation_source_from_tool_result( + tool_name=tool_function_name, + tool_params=tool_function_params, + tool_result=tool_result, + tool_id=tool.get("tool_id", "") if tool else "" + ) + tool_call_sources.append(citation_source) + except Exception as e: + log.exception(f"Error extracting citation source: {e}") + results.append( { "tool_call_id": tool_call_id, @@ -3136,6 +3201,19 @@ async def process_chat_response( } ) + # Emit citation sources for UI display + for source in tool_call_sources: + await event_emitter({"type": "source", "data": source}) + + # Apply source context to messages for model + if tool_call_sources: + user_msg = get_last_user_message(form_data["messages"]) + if user_msg: + form_data["messages"] = apply_source_context_to_messages( + request, form_data["messages"], tool_call_sources, user_msg + ) + tool_call_sources.clear() + await event_emitter( { "type": "chat:completion", diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 4027a0a831..8a970e1c56 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -342,15 +342,20 @@ async def get_tools( def get_builtin_tools( - request: Request, extra_params: dict, features: dict = None + request: Request, extra_params: dict, features: dict = None, model: dict = None ) -> dict[str, dict]: """ Get built-in tools for native function calling. - Only returns tools when BOTH the global config is enabled AND the feature is enabled for this chat. + Only returns tools when BOTH the global config is enabled AND the model capability allows it. """ tools_dict = {} builtin_functions = [] features = features or {} + model = model or {} + + # Helper to get model capabilities (defaults to True if not specified) + def get_model_capability(name: str, default: bool = True) -> bool: + return model.get("info", {}).get("meta", {}).get("capabilities", {}).get(name, default) # Time utilities - always available for date calculations builtin_functions.extend([get_current_timestamp, calculate_timestamp]) @@ -362,18 +367,18 @@ def get_builtin_tools( if features.get("memory"): builtin_functions.extend([search_memories, add_memory, replace_memory_content]) - # Add web search tools if enabled globally AND for this chat - if getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) and features.get( + # Add web search tools if enabled globally AND model has web_search capability + if getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) and get_model_capability( "web_search" ): builtin_functions.extend([web_search, fetch_url]) - # Add image generation/edit tools if enabled globally AND for this chat + # Add image generation/edit tools if enabled globally AND model has image_generation capability if getattr( request.app.state.config, "ENABLE_IMAGE_GENERATION", False - ) and features.get("image_generation"): + ) and get_model_capability("image_generation"): builtin_functions.append(generate_image) - if getattr(request.app.state.config, "ENABLE_IMAGE_EDIT", False) and features.get( + if getattr(request.app.state.config, "ENABLE_IMAGE_EDIT", False) and get_model_capability( "image_generation" ): builtin_functions.append(edit_image) From c8622adcb01f3091b17ca50f8c8e2f20c7b9cd2a Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Wed, 7 Jan 2026 08:58:58 -0500 Subject: [PATCH 159/254] feat: builtin kb tools --- backend/open_webui/tools/builtin.py | 366 ++++++++++++++++++++++++++++ backend/open_webui/utils/tools.py | 12 +- 2 files changed, 377 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 11069ae014..b8cda36012 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -1148,3 +1148,369 @@ async def view_channel_thread( except Exception as e: log.exception(f"view_channel_thread error: {e}") return json.dumps({"error": str(e)}) + + +# ============================================================================= +# KNOWLEDGE BASE TOOLS +# ============================================================================= + + +async def list_knowledge_bases( + count: int = 10, + skip: int = 0, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + List the user's accessible knowledge bases. + + :param count: Maximum number of KBs to return (default: 10) + :param skip: Number of results to skip for pagination (default: 0) + :return: JSON with KBs containing id, name, description, and file_count + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + from open_webui.models.knowledge import Knowledges + + user_id = __user__.get("id") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + result = Knowledges.search_knowledge_bases( + user_id, + filter={ + "query": "", # Empty query to get all + "user_id": user_id, + "group_ids": user_group_ids, + }, + skip=skip, + limit=count, + ) + + knowledge_bases = [] + for knowledge_base in result.items: + # Get file count for this KB + files = Knowledges.get_files_by_id(knowledge_base.id) + file_count = len(files) if files else 0 + + knowledge_bases.append( + { + "id": knowledge_base.id, + "name": knowledge_base.name, + "description": knowledge_base.description or "", + "file_count": file_count, + "updated_at": knowledge_base.updated_at, + } + ) + + return json.dumps(knowledge_bases, ensure_ascii=False) + except Exception as e: + log.exception(f"list_knowledge_bases error: {e}") + return json.dumps({"error": str(e)}) + +async def search_knowledge_bases( + query: str, + count: int = 5, + skip: int = 0, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search the user's accessible knowledge bases by name and description. + + :param query: The search query to find matching knowledge bases + :param count: Maximum number of results to return (default: 5) + :param skip: Number of results to skip for pagination (default: 0) + :return: JSON with matching KBs containing id, name, description, and file_count + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + from open_webui.models.knowledge import Knowledges + + user_id = __user__.get("id") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + result = Knowledges.search_knowledge_bases( + user_id, + filter={ + "query": query, + "user_id": user_id, + "group_ids": user_group_ids, + }, + skip=skip, + limit=count, + ) + + knowledge_bases = [] + for knowledge_base in result.items: + # Get file count for this KB + files = Knowledges.get_files_by_id(knowledge_base.id) + file_count = len(files) if files else 0 + + knowledge_bases.append( + { + "id": knowledge_base.id, + "name": knowledge_base.name, + "description": knowledge_base.description or "", + "file_count": file_count, + "updated_at": knowledge_base.updated_at, + } + ) + + return json.dumps(knowledge_bases, ensure_ascii=False) + except Exception as e: + log.exception(f"search_knowledge_bases error: {e}") + return json.dumps({"error": str(e)}) + + +async def search_knowledge_files( + query: str, + knowledge_id: Optional[str] = None, + count: int = 5, + skip: int = 0, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search files across knowledge bases the user has access to. + + :param query: The search query to find matching files by filename + :param knowledge_id: Optional KB id to limit search to a specific knowledge base + :param count: Maximum number of results to return (default: 5) + :param skip: Number of results to skip for pagination (default: 0) + :return: JSON with matching files containing id, filename, knowledge_id, knowledge_name, and updated_at + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + from open_webui.models.knowledge import Knowledges + + user_id = __user__.get("id") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + if knowledge_id: + # Search within a specific KB + result = Knowledges.search_files_by_id( + knowledge_id=knowledge_id, + user_id=user_id, + filter={"query": query}, + skip=skip, + limit=count, + ) + else: + # Search across all accessible KBs + result = Knowledges.search_knowledge_files( + filter={ + "query": query, + "user_id": user_id, + "group_ids": user_group_ids, + }, + skip=skip, + limit=count, + ) + + files = [] + for file in result.items: + file_info = { + "id": file.id, + "filename": file.filename, + "updated_at": file.updated_at, + } + + # Add KB info if available (from search_knowledge_files) + if hasattr(file, "collection") and file.collection: + file_info["knowledge_id"] = file.collection.get("id", "") + file_info["knowledge_name"] = file.collection.get("name", "") + + files.append(file_info) + + return json.dumps(files, ensure_ascii=False) + except Exception as e: + log.exception(f"search_knowledge_files error: {e}") + return json.dumps({"error": str(e)}) + + +async def view_knowledge_file( + file_id: str, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Get the full content of a file from a knowledge base. + + :param file_id: The ID of the file to retrieve + :return: JSON with the file's id, filename, and full text content + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + from open_webui.models.files import Files + from open_webui.models.knowledge import Knowledges + from open_webui.utils.access_control import has_access + + user_id = __user__.get("id") + user_role = __user__.get("role", "user") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + # Get the file + file = Files.get_file_by_id(file_id) + if not file: + return json.dumps({"error": "File not found"}) + + # Check if user has access via any KB containing this file + knowledges = Knowledges.get_knowledges_by_file_id(file_id) + + has_knowledge_access = False + knowledge_info = None + for knowledge_base in knowledges: + if ( + user_role == "admin" + or knowledge_base.user_id == user_id + or has_access(user_id, "read", knowledge_base.access_control, user_group_ids) + ): + has_knowledge_access = True + knowledge_info = {"id": knowledge_base.id, "name": knowledge_base.name} + break + + if not has_knowledge_access: + # Also allow if user owns the file directly + if file.user_id != user_id and user_role != "admin": + return json.dumps({"error": "Access denied"}) + + # Get file content (extracted text stored during upload) + content = "" + if file.data: + content = file.data.get("content", "") + + result = { + "id": file.id, + "filename": file.filename, + "content": content, + "updated_at": file.updated_at, + "created_at": file.created_at, + } + + if knowledge_info: + result["knowledge_id"] = knowledge_info["id"] + result["knowledge_name"] = knowledge_info["name"] + + return json.dumps(result, ensure_ascii=False) + except Exception as e: + log.exception(f"view_knowledge_file error: {e}") + return json.dumps({"error": str(e)}) + + +async def query_knowledge_bases( + query: str, + knowledge_ids: Optional[list[str]] = None, + count: int = 5, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search knowledge bases using semantic/vector search to find relevant content chunks. + + :param query: The search query to find semantically relevant content + :param knowledge_ids: Optional list of KB ids to limit search to specific knowledge bases + :param count: Maximum number of results to return (default: 5) + :return: JSON with relevant chunks containing content, source filename, and relevance score + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + from open_webui.models.knowledge import Knowledges + from open_webui.retrieval.utils import query_collection + from open_webui.utils.access_control import has_access + + user_id = __user__.get("id") + user_role = __user__.get("role", "user") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + + # Get embedding function from app state + embedding_function = __request__.app.state.EMBEDDING_FUNCTION + if not embedding_function: + return json.dumps({"error": "Embedding function not configured"}) + + # Determine which KB collections to search + collection_names = [] + + if knowledge_ids: + # Search specific KBs - verify access for each + for knowledge_id in knowledge_ids: + knowledge = Knowledges.get_knowledge_by_id(knowledge_id) + if knowledge and ( + user_role == "admin" + or knowledge.user_id == user_id + or has_access(user_id, "read", knowledge.access_control, user_group_ids) + ): + collection_names.append(knowledge_id) + else: + # Search all accessible KBs + result = Knowledges.search_knowledge_bases( + user_id, + filter={ + "query": "", + "user_id": user_id, + "group_ids": user_group_ids, + }, + skip=0, + limit=50, # Get up to 50 accessible KBs + ) + collection_names = [knowledge_base.id for knowledge_base in result.items] + + if not collection_names: + return json.dumps([]) + + # Perform vector search across collections + query_results = await query_collection( + collection_names=collection_names, + queries=[query], + embedding_function=embedding_function, + k=count, + ) + + # Format results + chunks = [] + if query_results and "documents" in query_results: + documents = query_results.get("documents", [[]])[0] + metadatas = query_results.get("metadatas", [[]])[0] + distances = query_results.get("distances", [[]])[0] + + for idx, doc in enumerate(documents): + chunk_info = { + "content": doc, + "source": metadatas[idx].get("source", metadatas[idx].get("name", "Unknown")), + "file_id": metadatas[idx].get("file_id", ""), + } + + # Add relevance score if available + if idx < len(distances): + chunk_info["distance"] = distances[idx] + + chunks.append(chunk_info) + + return json.dumps(chunks, ensure_ascii=False) + except Exception as e: + log.exception(f"query_knowledge_bases 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 8a970e1c56..fdfdbc5fb9 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -63,6 +63,11 @@ from open_webui.tools.builtin import ( view_channel_thread, replace_note_content, write_note, + list_knowledge_bases, + search_knowledge_bases, + search_knowledge_files, + view_knowledge_file, + query_knowledge_bases, ) import copy @@ -360,9 +365,14 @@ def get_builtin_tools( # Time utilities - always available for date calculations builtin_functions.extend([get_current_timestamp, calculate_timestamp]) - # Chats tools - search and fetch user's chat history (always available) + # Chats tools - search and fetch user's chat history builtin_functions.extend([search_chats, view_chat]) + # Knowledge base tools - list, search, query, and view user's accessible knowledge bases + builtin_functions.extend( + [list_knowledge_bases, search_knowledge_bases, search_knowledge_files, view_knowledge_file, query_knowledge_bases] + ) + # Add memory tools if enabled for this chat if features.get("memory"): builtin_functions.extend([search_memories, add_memory, replace_memory_content]) From 961136413f596154d7073cac2b5241d34d0942bf Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Wed, 7 Jan 2026 09:46:07 -0500 Subject: [PATCH 160/254] refac --- backend/open_webui/tools/builtin.py | 126 ++++++++++++++++--------- backend/open_webui/utils/middleware.py | 2 +- backend/open_webui/utils/tools.py | 17 +++- 3 files changed, 93 insertions(+), 52 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index b8cda36012..257805f380 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -1183,7 +1183,7 @@ async def list_knowledge_bases( result = Knowledges.search_knowledge_bases( user_id, filter={ - "query": "", # Empty query to get all + "query": "", "user_id": user_id, "group_ids": user_group_ids, }, @@ -1193,7 +1193,6 @@ async def list_knowledge_bases( knowledge_bases = [] for knowledge_base in result.items: - # Get file count for this KB files = Knowledges.get_files_by_id(knowledge_base.id) file_count = len(files) if files else 0 @@ -1212,6 +1211,7 @@ async def list_knowledge_bases( log.exception(f"list_knowledge_bases error: {e}") return json.dumps({"error": str(e)}) + async def search_knowledge_bases( query: str, count: int = 5, @@ -1252,7 +1252,6 @@ async def search_knowledge_bases( knowledge_bases = [] for knowledge_base in result.items: - # Get file count for this KB files = Knowledges.get_files_by_id(knowledge_base.id) file_count = len(files) if files else 0 @@ -1287,7 +1286,7 @@ async def search_knowledge_files( :param knowledge_id: Optional KB id to limit search to a specific knowledge base :param count: Maximum number of results to return (default: 5) :param skip: Number of results to skip for pagination (default: 0) - :return: JSON with matching files containing id, filename, knowledge_id, knowledge_name, and updated_at + :return: JSON with matching files containing id, filename, and updated_at """ if __request__ is None: return json.dumps({"error": "Request context not available"}) @@ -1302,7 +1301,6 @@ async def search_knowledge_files( user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] if knowledge_id: - # Search within a specific KB result = Knowledges.search_files_by_id( knowledge_id=knowledge_id, user_id=user_id, @@ -1311,7 +1309,6 @@ async def search_knowledge_files( limit=count, ) else: - # Search across all accessible KBs result = Knowledges.search_knowledge_files( filter={ "query": query, @@ -1329,12 +1326,9 @@ async def search_knowledge_files( "filename": file.filename, "updated_at": file.updated_at, } - - # Add KB info if available (from search_knowledge_files) if hasattr(file, "collection") and file.collection: file_info["knowledge_id"] = file.collection.get("id", "") file_info["knowledge_name"] = file.collection.get("name", "") - files.append(file_info) return json.dumps(files, ensure_ascii=False) @@ -1369,16 +1363,15 @@ async def view_knowledge_file( user_role = __user__.get("role", "user") user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] - # Get the file file = Files.get_file_by_id(file_id) if not file: return json.dumps({"error": "File not found"}) - # Check if user has access via any KB containing this file + # Check access via any KB containing this file knowledges = Knowledges.get_knowledges_by_file_id(file_id) - has_knowledge_access = False knowledge_info = None + for knowledge_base in knowledges: if ( user_role == "admin" @@ -1390,11 +1383,9 @@ async def view_knowledge_file( break if not has_knowledge_access: - # Also allow if user owns the file directly if file.user_id != user_id and user_role != "admin": return json.dumps({"error": "Access denied"}) - # Get file content (extracted text stored during upload) content = "" if file.data: content = file.data.get("content", "") @@ -1406,7 +1397,6 @@ async def view_knowledge_file( "updated_at": file.updated_at, "created_at": file.created_at, } - if knowledge_info: result["knowledge_id"] = knowledge_info["id"] result["knowledge_name"] = knowledge_info["name"] @@ -1423,9 +1413,11 @@ async def query_knowledge_bases( count: int = 5, __request__: Request = None, __user__: dict = None, + __model_knowledge__: list[dict] = None, ) -> str: """ Search knowledge bases using semantic/vector search to find relevant content chunks. + Handles collections (KBs), individual files, and notes. :param query: The search query to find semantically relevant content :param knowledge_ids: Optional list of KB ids to limit search to specific knowledge bases @@ -1440,6 +1432,8 @@ async def query_knowledge_bases( try: from open_webui.models.knowledge import Knowledges + from open_webui.models.files import Files + from open_webui.models.notes import Notes from open_webui.retrieval.utils import query_collection from open_webui.utils.access_control import has_access @@ -1447,16 +1441,53 @@ async def query_knowledge_bases( user_role = __user__.get("role", "user") user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] - # Get embedding function from app state embedding_function = __request__.app.state.EMBEDDING_FUNCTION if not embedding_function: return json.dumps({"error": "Embedding function not configured"}) - # Determine which KB collections to search collection_names = [] + note_results = [] # Notes aren't vectorized, handle separately - if knowledge_ids: - # Search specific KBs - verify access for each + # If model has attached knowledge, use those + if __model_knowledge__: + for item in __model_knowledge__: + item_type = item.get("type") + item_id = item.get("id") + + if item_type == "collection": + # Knowledge base - use KB ID as collection name + knowledge = Knowledges.get_knowledge_by_id(item_id) + if knowledge and ( + user_role == "admin" + or knowledge.user_id == user_id + or has_access(user_id, "read", knowledge.access_control, user_group_ids) + ): + collection_names.append(item_id) + + elif item_type == "file": + # Individual file - use file-{id} as collection name + file = Files.get_file_by_id(item_id) + if file and (user_role == "admin" or file.user_id == user_id): + collection_names.append(f"file-{item_id}") + + elif item_type == "note": + # Note - always return full content as context + note = Notes.get_note_by_id(item_id) + if note and ( + user_role == "admin" + or note.user_id == user_id + or has_access(user_id, "read", note.access_control) + ): + content = note.data.get("content", {}).get("md", "") + note_results.append({ + "content": content, + "source": note.title, + "note_id": note.id, + "type": "note", + }) + + elif knowledge_ids: + # User specified specific KBs for knowledge_id in knowledge_ids: knowledge = Knowledges.get_knowledge_by_id(knowledge_id) if knowledge and ( @@ -1466,7 +1497,7 @@ async def query_knowledge_bases( ): collection_names.append(knowledge_id) else: - # Search all accessible KBs + # No model knowledge and no specific IDs - search all accessible KBs result = Knowledges.search_knowledge_bases( user_id, filter={ @@ -1475,40 +1506,41 @@ async def query_knowledge_bases( "group_ids": user_group_ids, }, skip=0, - limit=50, # Get up to 50 accessible KBs + limit=50, ) collection_names = [knowledge_base.id for knowledge_base in result.items] - if not collection_names: - return json.dumps([]) - - # Perform vector search across collections - query_results = await query_collection( - collection_names=collection_names, - queries=[query], - embedding_function=embedding_function, - k=count, - ) - - # Format results chunks = [] - if query_results and "documents" in query_results: - documents = query_results.get("documents", [[]])[0] - metadatas = query_results.get("metadatas", [[]])[0] - distances = query_results.get("distances", [[]])[0] - for idx, doc in enumerate(documents): - chunk_info = { - "content": doc, - "source": metadatas[idx].get("source", metadatas[idx].get("name", "Unknown")), - "file_id": metadatas[idx].get("file_id", ""), - } + # Add note results first + chunks.extend(note_results) - # Add relevance score if available - if idx < len(distances): - chunk_info["distance"] = distances[idx] + # Query vector collections if any + if collection_names: + query_results = await query_collection( + collection_names=collection_names, + queries=[query], + embedding_function=embedding_function, + k=count, + ) - chunks.append(chunk_info) + if query_results and "documents" in query_results: + documents = query_results.get("documents", [[]])[0] + metadatas = query_results.get("metadatas", [[]])[0] + distances = query_results.get("distances", [[]])[0] + + for idx, doc in enumerate(documents): + chunk_info = { + "content": doc, + "source": metadatas[idx].get("source", metadatas[idx].get("name", "Unknown")), + "file_id": metadatas[idx].get("file_id", ""), + } + if idx < len(distances): + chunk_info["distance"] = distances[idx] + chunks.append(chunk_info) + + # Limit to requested count + chunks = chunks[:count] return json.dumps(chunks, ensure_ascii=False) except Exception as e: diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 3675a9846f..844a4e66d4 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1343,7 +1343,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): user_message = get_last_user_message(form_data["messages"]) model_knowledge = model.get("info", {}).get("meta", {}).get("knowledge", False) - if model_knowledge: + if model_knowledge and metadata.get("params", {}).get("function_calling") != "native": await event_emitter( { "type": "status", diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index fdfdbc5fb9..8d30b6ee8d 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -368,10 +368,18 @@ def get_builtin_tools( # Chats tools - search and fetch user's chat history builtin_functions.extend([search_chats, view_chat]) - # Knowledge base tools - list, search, query, and view user's accessible knowledge bases - builtin_functions.extend( - [list_knowledge_bases, search_knowledge_bases, search_knowledge_files, view_knowledge_file, query_knowledge_bases] - ) + # Knowledge base tools - conditional injection based on model knowledge + # If model has attached knowledge (any type), only provide query_knowledge_bases + # Otherwise, provide all KB browsing tools + model_knowledge = model.get("info", {}).get("meta", {}).get("knowledge", []) + if model_knowledge: + # Model has attached knowledge - only allow semantic search within it + builtin_functions.append(query_knowledge_bases) + else: + # No model knowledge - allow full KB browsing + builtin_functions.extend( + [list_knowledge_bases, search_knowledge_bases, search_knowledge_files, view_knowledge_file, query_knowledge_bases] + ) # Add memory tools if enabled for this chat if features.get("memory"): @@ -419,6 +427,7 @@ def get_builtin_tools( "__event_emitter__": extra_params.get("__event_emitter__"), "__chat_id__": extra_params.get("__chat_id__"), "__message_id__": extra_params.get("__message_id__"), + "__model_knowledge__": model_knowledge, }, ) From ab400e3eae569a5e09fe391d4b4bab104423bb0b Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Wed, 7 Jan 2026 10:14:45 -0500 Subject: [PATCH 161/254] enh: native tool citations Co-Authored-By: Jannik S. --- backend/open_webui/utils/middleware.py | 105 ++++++++++++++++++++----- 1 file changed, 87 insertions(+), 18 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 844a4e66d4..c8751bba2c 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -147,12 +147,16 @@ def get_citation_source_from_tool_result( tool_params: dict, tool_result: str, tool_id: str = "" -) -> dict: +) -> list[dict]: """ - Parse a tool's result and convert it to a source dict for citation display. + Parse a tool's result and convert it to source dicts for citation display. - For web_search: extracts title, link, snippet from each search result. - For other tools: wraps the raw result as a generic source. + Follows the source format conventions from get_sources_from_items: + - source: file/item info object with id, name, type + - document: list of document contents + - metadata: list of metadata objects with source, file_id, name fields + + Returns a list of sources (usually one, but query_knowledge_bases may return multiple). """ try: if tool_name == "web_search": @@ -173,25 +177,90 @@ def get_citation_source_from_tool_result( "url": link, }) - return { + return [{ "source": {"name": "web_search", "id": "web_search"}, "document": documents, "metadata": metadata, - } + }] + + elif tool_name == "view_knowledge_file": + file_data = json.loads(tool_result) + filename = file_data.get("filename", "Unknown File") + file_id = file_data.get("id", "") + knowledge_name = file_data.get("knowledge_name", "") + + return [{ + "source": { + "id": file_id, + "name": filename, + "type": "file", + }, + "document": [file_data.get("content", "")], + "metadata": [{ + "file_id": file_id, + "name": filename, + "source": filename, + **({"knowledge_name": knowledge_name} if knowledge_name else {}), + }], + }] + + elif tool_name == "query_knowledge_bases": + chunks = json.loads(tool_result) + + # Group chunks by source for better citation display + # Each unique source becomes a separate source entry + sources_by_file = {} + + for chunk in chunks: + source_name = chunk.get("source", "Unknown") + file_id = chunk.get("file_id", "") + note_id = chunk.get("note_id", "") + chunk_type = chunk.get("type", "file") + content = chunk.get("content", "") + + # Use file_id or note_id as the key + key = file_id or note_id or source_name + + if key not in sources_by_file: + sources_by_file[key] = { + "source": { + "id": file_id or note_id, + "name": source_name, + "type": chunk_type, + }, + "document": [], + "metadata": [], + } + + sources_by_file[key]["document"].append(content) + sources_by_file[key]["metadata"].append({ + "file_id": file_id, + "name": source_name, + "source": source_name, + **({"note_id": note_id} if note_id else {}), + }) + + # Return all grouped sources as a list + if sources_by_file: + return list(sources_by_file.values()) + + # Empty result fallback + return [] + else: # Fallback for other tools - return { - "source": {"name": tool_name, "id": tool_id or tool_name}, + return [{ + "source": {"name": tool_name, "type": "tool", "id": tool_id or tool_name}, "document": [str(tool_result)], - "metadata": [{"source": tool_id or tool_name, "parameters": tool_params}], - } + "metadata": [{"source": tool_name, "name": tool_name}], + }] except Exception as e: log.exception(f"Error parsing tool result for {tool_name}: {e}") - return { - "source": {"name": tool_name, "id": tool_id or tool_name}, + return [{ + "source": {"name": tool_name, "type": "tool"}, "document": [str(tool_result)], - "metadata": [{"source": tool_id or tool_name}], - } + "metadata": [{"source": tool_name}], + }] def apply_source_context_to_messages( @@ -3163,16 +3232,16 @@ async def process_chat_response( ) ) - # Extract citation sources from web_search results - if tool_function_name == "web_search" and tool_result: + # Extract citation sources from tool results + if tool_function_name in ["web_search", "view_knowledge_file", "query_knowledge_bases"] and tool_result: try: - citation_source = get_citation_source_from_tool_result( + citation_sources = get_citation_source_from_tool_result( tool_name=tool_function_name, tool_params=tool_function_params, tool_result=tool_result, tool_id=tool.get("tool_id", "") if tool else "" ) - tool_call_sources.append(citation_source) + tool_call_sources.extend(citation_sources) except Exception as e: log.exception(f"Error extracting citation source: {e}") From 35d385e9cc7e3aa7000a4c3b413135177e598dcb Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Wed, 7 Jan 2026 10:21:05 -0500 Subject: [PATCH 162/254] refac --- backend/open_webui/tools/builtin.py | 17 ++++++++++------- backend/open_webui/utils/middleware.py | 6 +++--- backend/open_webui/utils/tools.py | 4 ++-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 257805f380..8f3c2a2dfb 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -15,7 +15,7 @@ from typing import Optional from fastapi import Request from open_webui.models.users import UserModel -from open_webui.routers.retrieval import search_web +from open_webui.routers.retrieval import search_web as _search_web from open_webui.retrieval.utils import get_content_from_url from open_webui.routers.images import ( image_generations, @@ -142,14 +142,16 @@ async def calculate_timestamp( # ============================================================================= -async def web_search( +async def search_web( query: str, count: int = 5, __request__: Request = None, __user__: dict = None, ) -> str: """ - Search the web for information on a given topic. + Search the public web for information. Best for current events, external references, + or topics not covered in internal documents. If knowledge base tools are available, + consider checking those first for internal information. :param query: The search query to look up :param count: Number of results to return (default: 5) @@ -162,7 +164,7 @@ async def web_search( engine = __request__.app.state.config.WEB_SEARCH_ENGINE user = UserModel(**__user__) if __user__ else None - results = search_web(__request__, engine, query, user) + results = _search_web(__request__, engine, query, user) # Limit results results = results[:count] if results else [] @@ -172,7 +174,7 @@ async def web_search( ensure_ascii=False, ) except Exception as e: - log.exception(f"web_search error: {e}") + log.exception(f"search_web error: {e}") return json.dumps({"error": str(e)}) @@ -1416,8 +1418,9 @@ async def query_knowledge_bases( __model_knowledge__: list[dict] = None, ) -> str: """ - Search knowledge bases using semantic/vector search to find relevant content chunks. - Handles collections (KBs), individual files, and notes. + Search internal knowledge bases using semantic/vector search. This should be your first + choice for finding information before searching the web. Searches across collections (KBs), + individual files, and notes that the user has access to. :param query: The search query to find semantically relevant content :param knowledge_ids: Optional list of KB ids to limit search to specific knowledge bases diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index c8751bba2c..edbf866266 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -159,7 +159,7 @@ def get_citation_source_from_tool_result( Returns a list of sources (usually one, but query_knowledge_bases may return multiple). """ try: - if tool_name == "web_search": + if tool_name == "search_web": # Parse JSON array: [{"title": "...", "link": "...", "snippet": "..."}] results = json.loads(tool_result) documents = [] @@ -178,7 +178,7 @@ def get_citation_source_from_tool_result( }) return [{ - "source": {"name": "web_search", "id": "web_search"}, + "source": {"name": "search_web", "id": "search_web"}, "document": documents, "metadata": metadata, }] @@ -3233,7 +3233,7 @@ async def process_chat_response( ) # Extract citation sources from tool results - if tool_function_name in ["web_search", "view_knowledge_file", "query_knowledge_bases"] and tool_result: + if tool_function_name in ["search_web", "view_knowledge_file", "query_knowledge_bases"] and tool_result: try: citation_sources = get_citation_source_from_tool_result( tool_name=tool_function_name, diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 8d30b6ee8d..75b2b9aeac 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -44,7 +44,7 @@ from open_webui.env import ( AIOHTTP_CLIENT_SESSION_TOOL_SERVER_SSL, ) from open_webui.tools.builtin import ( - web_search, + search_web, fetch_url, generate_image, edit_image, @@ -389,7 +389,7 @@ def get_builtin_tools( if getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) and get_model_capability( "web_search" ): - builtin_functions.extend([web_search, fetch_url]) + builtin_functions.extend([search_web, fetch_url]) # Add image generation/edit tools if enabled globally AND model has image_generation capability if getattr( From 0654df7bdb2c21cf6e0e694307d0ea3b135dda77 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Wed, 7 Jan 2026 10:25:13 -0500 Subject: [PATCH 163/254] refac --- backend/open_webui/utils/tools.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 75b2b9aeac..3bdb6d0cc0 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -365,9 +365,6 @@ def get_builtin_tools( # Time utilities - always available for date calculations builtin_functions.extend([get_current_timestamp, calculate_timestamp]) - # Chats tools - search and fetch user's chat history - builtin_functions.extend([search_chats, view_chat]) - # Knowledge base tools - conditional injection based on model knowledge # If model has attached knowledge (any type), only provide query_knowledge_bases # Otherwise, provide all KB browsing tools @@ -381,6 +378,9 @@ def get_builtin_tools( [list_knowledge_bases, search_knowledge_bases, search_knowledge_files, view_knowledge_file, query_knowledge_bases] ) + # Chats tools - search and fetch user's chat history + builtin_functions.extend([search_chats, view_chat]) + # Add memory tools if enabled for this chat if features.get("memory"): builtin_functions.extend([search_memories, add_memory, replace_memory_content]) From 0e1edc4c019efc2bb854a7289a40210cdaad3b63 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:27:25 -0500 Subject: [PATCH 164/254] feat: add search bar to admin settings sidebar (#20434) --- src/lib/components/admin/Settings.svelte | 748 ++++++++++++----------- 1 file changed, 403 insertions(+), 345 deletions(-) diff --git a/src/lib/components/admin/Settings.svelte b/src/lib/components/admin/Settings.svelte index 36e87df26a..d47b68ddee 100644 --- a/src/lib/components/admin/Settings.svelte +++ b/src/lib/components/admin/Settings.svelte @@ -18,12 +18,15 @@ import Documents from './Settings/Documents.svelte'; import WebSearch from './Settings/WebSearch.svelte'; - import ChartBar from '../icons/ChartBar.svelte'; - import DocumentChartBar from '../icons/DocumentChartBar.svelte'; import Evaluations from './Settings/Evaluations.svelte'; import CodeExecution from './Settings/CodeExecution.svelte'; import Tools from './Settings/Tools.svelte'; + import ChartBar from '../icons/ChartBar.svelte'; + import DocumentChartBar from '../icons/DocumentChartBar.svelte'; + import Search from '../icons/Search.svelte'; + import XMark from '../icons/XMark.svelte'; + const i18n = getContext('i18n'); let selectedTab = 'general'; @@ -63,6 +66,207 @@ } }; + let search = ''; + let searchDebounceTimeout; + let filteredSettings = []; + + const allSettings = [ + { + id: 'general', + title: 'General', + route: '/admin/settings/general', + keywords: [ + 'general', + 'admin', + 'settings', + 'version', + 'update', + 'language', + 'theme', + 'data', + 'users', + 'roles', + 'ldap', + 'authentication', + 'reverse proxy', + 'webhook', + 'community', + 'channels' + ] + }, + { + id: 'connections', + title: 'Connections', + route: '/admin/settings/connections', + keywords: [ + 'connections', + 'ollama', + 'openai', + 'api', + 'base url', + 'direct connections', + 'proxy', + 'key' + ] + }, + { + id: 'models', + title: 'Models', + route: '/admin/settings/models', + keywords: [ + 'models', + 'pull', + 'delete', + 'create', + 'edit', + 'modelfile', + 'gguf', + 'import', + 'export' + ] + }, + { + id: 'evaluations', + title: 'Evaluations', + route: '/admin/settings/evaluations', + keywords: ['evaluations', 'feedback', 'rating', 'arena', 'leaderboard', 'preference'] + }, + { + id: 'tools', + title: 'External Tools', + route: '/admin/settings/tools', + keywords: ['tools', 'plugins', 'extensions', 'functions', 'openapi', 'server'] + }, + { + id: 'documents', + title: 'Documents', + route: '/admin/settings/documents', + keywords: [ + 'documents', + 'files', + 'rag', + 'knowledge', + 'upload', + 'embedding', + 'vector db', + 'chunk', + 'overlap', + 'splitter', + 'pdf', + 'ocr', + 'tika', + 'docling', + 'unstructured' + ] + }, + { + id: 'web', + title: 'Web Search', + route: '/admin/settings/web', + keywords: [ + 'web search', + 'google', + 'bing', + 'duckduckgo', + 'serp', + 'searxng', + 'moojeh', + 'yacy', + 'serper', + 'serply', + 'tavily', + 'exa', + 'perplexity', + 'firecrawl' + ] + }, + { + id: 'code-execution', + title: 'Code Execution', + route: '/admin/settings/code-execution', + keywords: ['code execution', 'python', 'sandbox', 'compiler', 'jupyter', 'interpreter'] + }, + { + id: 'interface', + title: 'Interface', + route: '/admin/settings/interface', + keywords: [ + 'interface', + 'ui', + 'appearance', + 'banners', + 'tasks', + 'prompt suggestions', + 'title generation', + 'tags' + ] + }, + { + id: 'audio', + title: 'Audio', + route: '/admin/settings/audio', + keywords: [ + 'audio', + 'voice', + 'speech', + 'tts', + 'stt', + 'whisper', + 'deepgram', + 'azure', + 'openai', + 'elevenlabs' + ] + }, + { + id: 'images', + title: 'Images', + route: '/admin/settings/images', + keywords: [ + 'images', + 'generation', + 'dalle', + 'stable diffusion', + 'comfyui', + 'automatic1111', + 'gemini' + ] + }, + { + id: 'pipelines', + title: 'Pipelines', + route: '/admin/settings/pipelines', + keywords: ['pipelines', 'workflows', 'filters', 'valves', 'middleware'] + }, + { + id: 'db', + title: 'Database', + route: '/admin/settings/db', + keywords: ['database', 'export', 'import', 'backup', 'chats', 'users'] + } + ]; + + const setFilteredSettings = () => { + filteredSettings = allSettings.filter((tab) => { + const searchTerm = search.toLowerCase().trim(); + return ( + search === '' || + tab.title.toLowerCase().includes(searchTerm) || + tab.keywords.some((keyword) => keyword.includes(searchTerm)) + ); + }); + }; + + const searchDebounceHandler = () => { + if (searchDebounceTimeout) { + clearTimeout(searchDebounceTimeout); + } + + searchDebounceTimeout = setTimeout(() => { + setFilteredSettings(); + }, 100); + }; + onMount(() => { const containerElement = document.getElementById('admin-settings-tabs-container'); @@ -75,6 +279,7 @@ }); } + setFilteredSettings(); // Scroll to the selected tab on mount scrollToTab(selectedTab); }); @@ -85,352 +290,205 @@ id="admin-settings-tabs-container" class="tabs mx-[16px] lg:mx-0 lg:px-[16px] flex flex-row overflow-x-auto gap-2.5 max-w-full lg:gap-1 lg:flex-col lg:flex-none lg:w-50 dark:text-gray-200 text-sm font-medium text-left scrollbar-none" > - + + +
- - - - - - - - - - - - - - - - - - - - - - - + {#each filteredSettings as tab (tab.id)} + + {/each}
Date: Wed, 7 Jan 2026 23:32:56 +0400 Subject: [PATCH 165/254] fix(notes): eliminate N+1 query in get_notes endpoint Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com> --- backend/open_webui/routers/notes.py | 32 +++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/backend/open_webui/routers/notes.py b/backend/open_webui/routers/notes.py index f3f8b8cff8..56730e2b6a 100644 --- a/backend/open_webui/routers/notes.py +++ b/backend/open_webui/routers/notes.py @@ -70,21 +70,23 @@ async def get_notes( limit = 60 skip = (page - 1) * limit - notes = [] - for note in Notes.get_notes_by_user_id( - user.id, "read", skip=skip, limit=limit, db=db - ): - note_user = Users.get_user_by_id(note.user_id, db=db) - if note_user: - notes.append( - NoteUserResponse( - **{ - **note.model_dump(), - "user": UserResponse(**note_user.model_dump()), - } - ) - ) - return notes + notes = Notes.get_notes_by_user_id(user.id, "read", skip=skip, limit=limit, db=db) + if not notes: + return [] + + user_ids = list(set(note.user_id for note in notes)) + users = {user.id: user for user in Users.get_users_by_user_ids(user_ids, db=db)} + + return [ + NoteUserResponse( + **{ + **note.model_dump(), + "user": UserResponse(**users[note.user_id].model_dump()), + } + ) + for note in notes + if note.user_id in users + ] @router.get("/search", response_model=NoteListResponse) From 74974334a5d4bb3192ea3649357a0611fb6afdd2 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:34:19 +0100 Subject: [PATCH 166/254] fix: More n+1 channel perf fixes (#20460) --- backend/open_webui/routers/channels.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index 79aad9fb5d..ccee8d91a2 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -1414,14 +1414,16 @@ async def get_channel_thread_messages( ) message_list = Messages.get_messages_by_parent_id(id, message_id, skip, limit, db=db) - users = {} + + if not message_list: + return [] + + # Batch fetch all users in a single query (fixes N+1 problem) + user_ids = list(set(m.user_id for m in message_list)) + users = {u.id: u for u in Users.get_users_by_user_ids(user_ids, db=db)} messages = [] for message in message_list: - if message.user_id not in users: - user = Users.get_user_by_id(message.user_id, db=db) - users[message.user_id] = user - messages.append( MessageUserResponse( **{ From b8fb9e815bf313a1ffeaaec754ca6f9a0e70e589 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:36:12 +0100 Subject: [PATCH 167/254] fix(channels): eliminate N+1 query in get_channel_messages endpoint (#20458) Replaced per-message user lookup with batch fetch using SQL IN clause. Changes: - Fetch all message user_ids in a single pass - Use Users.get_users_by_user_ids() for batch lookup - Build user mapping to avoid DB calls in loop - Add early return for empty message lists Performance: Reduces N+1 queries to 2 queries (messages + users) --- backend/open_webui/routers/channels.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index ccee8d91a2..cda85fbcdc 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -773,14 +773,16 @@ async def get_channel_messages( ) # Ensure user is a member of the channel message_list = Messages.get_messages_by_channel_id(id, skip, limit, db=db) - users = {} + + if not message_list: + return [] + + # Batch fetch all users in a single query (fixes N+1 problem) + user_ids = list(set(m.user_id for m in message_list)) + users = {u.id: u for u in Users.get_users_by_user_ids(user_ids, db=db)} messages = [] for message in message_list: - if message.user_id not in users: - user = Users.get_user_by_id(message.user_id, db=db) - users[message.user_id] = user - thread_replies = Messages.get_thread_replies_by_message_id(message.id, db=db) latest_thread_reply_at = ( thread_replies[0].created_at if thread_replies else None From 48f1b2d5476d85cb4d2ec44242ac71372c64aba4 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Wed, 7 Jan 2026 20:36:38 +0100 Subject: [PATCH 168/254] fix(channels): eliminate N+1 query in get_pinned_messages endpoint (#20459) Replaced per-message user lookup with batch fetch using SQL IN clause. Changes: - Fetch all message user_ids in a single pass - Use Users.get_users_by_user_ids() for batch lookup - Build user mapping to avoid DB calls in loop - Add early return for empty message lists Performance: Reduces N+1 queries to 2 queries (messages + users) --- backend/open_webui/routers/channels.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index cda85fbcdc..fc0c048ab5 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -843,14 +843,16 @@ async def get_pinned_channel_messages( limit = PAGE_ITEM_COUNT_PINNED message_list = Messages.get_pinned_messages_by_channel_id(id, skip, limit, db=db) - users = {} + + if not message_list: + return [] + + # Batch fetch all users in a single query (fixes N+1 problem) + user_ids = list(set(m.user_id for m in message_list)) + users = {u.id: u for u in Users.get_users_by_user_ids(user_ids, db=db)} messages = [] for message in message_list: - if message.user_id not in users: - user = Users.get_user_by_id(message.user_id, db=db) - users[message.user_id] = user - messages.append( MessageWithReactionsResponse( **{ From b73d30b6df8b8a9487db07d6978e1bfd13265226 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Wed, 7 Jan 2026 14:50:04 -0500 Subject: [PATCH 169/254] feat: implement global memories toggle and permissions (#20462) --- backend/open_webui/config.py | 11 ++ backend/open_webui/main.py | 3 + backend/open_webui/routers/auths.py | 4 + backend/open_webui/routers/memories.py | 103 +++++++++++++++++- backend/open_webui/routers/users.py | 1 + .../components/admin/Settings/General.svelte | 8 ++ .../admin/Users/Groups/Permissions.svelte | 16 +++ src/lib/components/chat/SettingsModal.svelte | 7 ++ src/lib/constants/permissions.ts | 3 +- src/lib/stores/index.ts | 1 + 10 files changed, 152 insertions(+), 5 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 680ecbb861..3fee61f6e3 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1470,6 +1470,10 @@ USER_PERMISSIONS_FEATURES_API_KEYS = ( os.environ.get("USER_PERMISSIONS_FEATURES_API_KEYS", "False").lower() == "true" ) +USER_PERMISSIONS_FEATURES_MEMORIES = ( + os.environ.get("USER_PERMISSIONS_FEATURES_MEMORIES", "True").lower() == "true" +) + USER_PERMISSIONS_SETTINGS_INTERFACE = ( os.environ.get("USER_PERMISSIONS_SETTINGS_INTERFACE", "True").lower() == "true" @@ -1533,6 +1537,7 @@ DEFAULT_USER_PERMISSIONS = { "web_search": USER_PERMISSIONS_FEATURES_WEB_SEARCH, "image_generation": USER_PERMISSIONS_FEATURES_IMAGE_GENERATION, "code_interpreter": USER_PERMISSIONS_FEATURES_CODE_INTERPRETER, + "memories": USER_PERMISSIONS_FEATURES_MEMORIES, }, "settings": { "interface": USER_PERMISSIONS_SETTINGS_INTERFACE, @@ -2083,6 +2088,12 @@ ENABLE_CODE_INTERPRETER = PersistentConfig( os.environ.get("ENABLE_CODE_INTERPRETER", "True").lower() == "true", ) +ENABLE_MEMORIES = PersistentConfig( + "ENABLE_MEMORIES", + "memories.enable", + os.environ.get("ENABLE_MEMORIES", "True").lower() == "true", +) + CODE_INTERPRETER_ENGINE = PersistentConfig( "CODE_INTERPRETER_ENGINE", "code_interpreter.engine", diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 6a1d79e721..2f384ee7d3 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -145,6 +145,7 @@ from open_webui.config import ( CODE_INTERPRETER_JUPYTER_AUTH_TOKEN, CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD, CODE_INTERPRETER_JUPYTER_TIMEOUT, + ENABLE_MEMORIES, # Image AUTOMATIC1111_API_AUTH, AUTOMATIC1111_BASE_URL, @@ -1106,6 +1107,7 @@ app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT = CODE_INTERPRETER_JUPYTER_TIM app.state.config.IMAGE_GENERATION_ENGINE = IMAGE_GENERATION_ENGINE app.state.config.ENABLE_IMAGE_GENERATION = ENABLE_IMAGE_GENERATION app.state.config.ENABLE_IMAGE_PROMPT_GENERATION = ENABLE_IMAGE_PROMPT_GENERATION +app.state.config.ENABLE_MEMORIES = ENABLE_MEMORIES app.state.config.IMAGE_GENERATION_MODEL = IMAGE_GENERATION_MODEL app.state.config.IMAGE_SIZE = IMAGE_SIZE @@ -1935,6 +1937,7 @@ async def get_app_config(request: Request): "enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS, "enable_google_drive_integration": app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION, "enable_onedrive_integration": app.state.config.ENABLE_ONEDRIVE_INTEGRATION, + "enable_memories": app.state.config.ENABLE_MEMORIES, **( { "enable_onedrive_personal": ENABLE_ONEDRIVE_PERSONAL, diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index fb0c141379..2c6fc6108b 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -991,6 +991,7 @@ async def get_admin_config(request: Request, user=Depends(get_admin_user)): "ENABLE_FOLDERS": request.app.state.config.ENABLE_FOLDERS, "FOLDER_MAX_FILE_COUNT": request.app.state.config.FOLDER_MAX_FILE_COUNT, "ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS, + "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, "PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE, @@ -1015,6 +1016,7 @@ class AdminConfig(BaseModel): ENABLE_FOLDERS: bool FOLDER_MAX_FILE_COUNT: Optional[int | str] = None ENABLE_CHANNELS: bool + ENABLE_MEMORIES: bool ENABLE_NOTES: bool ENABLE_USER_WEBHOOKS: bool PENDING_USER_OVERLAY_TITLE: Optional[str] = None @@ -1046,6 +1048,7 @@ async def update_admin_config( else None ) request.app.state.config.ENABLE_CHANNELS = form_data.ENABLE_CHANNELS + request.app.state.config.ENABLE_MEMORIES = form_data.ENABLE_MEMORIES request.app.state.config.ENABLE_NOTES = form_data.ENABLE_NOTES if form_data.DEFAULT_USER_ROLE in ["pending", "user", "admin"]: @@ -1091,6 +1094,7 @@ async def update_admin_config( "ENABLE_FOLDERS": request.app.state.config.ENABLE_FOLDERS, "FOLDER_MAX_FILE_COUNT": request.app.state.config.FOLDER_MAX_FILE_COUNT, "ENABLE_CHANNELS": request.app.state.config.ENABLE_CHANNELS, + "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, "PENDING_USER_OVERLAY_TITLE": request.app.state.config.PENDING_USER_OVERLAY_TITLE, diff --git a/backend/open_webui/routers/memories.py b/backend/open_webui/routers/memories.py index ebb6280741..6e98247ced 100644 --- a/backend/open_webui/routers/memories.py +++ b/backend/open_webui/routers/memories.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends, HTTPException, Request +from fastapi import APIRouter, Depends, HTTPException, Request, status from pydantic import BaseModel import logging import asyncio @@ -10,11 +10,16 @@ from open_webui.utils.auth import get_verified_user from open_webui.internal.db import get_session from sqlalchemy.orm import Session +from open_webui.utils.access_control import has_permission +from open_webui.constants import ERROR_MESSAGES + log = logging.getLogger(__name__) router = APIRouter() + + @router.get("/ef") async def get_embeddings(request: Request): return {"result": await request.app.state.EMBEDDING_FUNCTION("hello world")} @@ -26,7 +31,21 @@ async def get_embeddings(request: Request): @router.get("/", response_model=list[MemoryModel]) -async def get_memories(user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_memories( + request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + if not request.app.state.config.ENABLE_MEMORIES: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + return Memories.get_memories_by_user_id(user.id, db=db) @@ -50,6 +69,18 @@ async def add_memory( user=Depends(get_verified_user), db: Session = Depends(get_session), ): + if not request.app.state.config.ENABLE_MEMORIES: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + memory = Memories.insert_new_memory(user.id, form_data.content, db=db) vector = await request.app.state.EMBEDDING_FUNCTION(memory.content, user=user) @@ -83,6 +114,18 @@ class QueryMemoryForm(BaseModel): async def query_memory( request: Request, form_data: QueryMemoryForm, user=Depends(get_verified_user), db: Session = Depends(get_session) ): + if not request.app.state.config.ENABLE_MEMORIES: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + memories = Memories.get_memories_by_user_id(user.id, db=db) if not memories: raise HTTPException(status_code=404, detail="No memories found for user") @@ -105,6 +148,18 @@ async def query_memory( async def reset_memory_from_vector_db( request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) ): + if not request.app.state.config.ENABLE_MEMORIES: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + VECTOR_DB_CLIENT.delete_collection(f"user-memory-{user.id}") memories = Memories.get_memories_by_user_id(user.id, db=db) @@ -142,7 +197,21 @@ async def reset_memory_from_vector_db( @router.delete("/delete/user", response_model=bool) -async def delete_memory_by_user_id(user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def delete_memory_by_user_id( + request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + if not request.app.state.config.ENABLE_MEMORIES: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + result = Memories.delete_memories_by_user_id(user.id, db=db) if result: @@ -168,6 +237,18 @@ async def update_memory_by_id( user=Depends(get_verified_user), db: Session = Depends(get_session), ): + if not request.app.state.config.ENABLE_MEMORIES: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + memory = Memories.update_memory_by_id_and_user_id( memory_id, user.id, form_data.content, db=db ) @@ -201,7 +282,21 @@ async def update_memory_by_id( @router.delete("/{memory_id}", response_model=bool) -async def delete_memory_by_id(memory_id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def delete_memory_by_id( + memory_id: str, request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) +): + if not request.app.state.config.ENABLE_MEMORIES: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.NOT_FOUND, + ) + + if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + raise HTTPException( + status_code=status.HTTP_403_FORBIDDEN, + detail=ERROR_MESSAGES.ACCESS_PROHIBITED, + ) + result = Memories.delete_memory_by_id_and_user_id(memory_id, user.id, db=db) if result: diff --git a/backend/open_webui/routers/users.py b/backend/open_webui/routers/users.py index 3c3d22c613..f10448458f 100644 --- a/backend/open_webui/routers/users.py +++ b/backend/open_webui/routers/users.py @@ -226,6 +226,7 @@ class FeaturesPermissions(BaseModel): web_search: bool = True image_generation: bool = True code_interpreter: bool = True + memories: bool = True class SettingsPermissions(BaseModel): diff --git a/src/lib/components/admin/Settings/General.svelte b/src/lib/components/admin/Settings/General.svelte index 0b56de20e8..c327937411 100644 --- a/src/lib/components/admin/Settings/General.svelte +++ b/src/lib/components/admin/Settings/General.svelte @@ -741,6 +741,14 @@
+
+
+ {$i18n.t('Memories')} ({$i18n.t('Beta')}) +
+ + +
+
{$i18n.t('User Webhooks')} diff --git a/src/lib/components/admin/Users/Groups/Permissions.svelte b/src/lib/components/admin/Users/Groups/Permissions.svelte index 28b7b4c2c8..3284f6171c 100644 --- a/src/lib/components/admin/Users/Groups/Permissions.svelte +++ b/src/lib/components/admin/Users/Groups/Permissions.svelte @@ -782,6 +782,22 @@
{/if}
+ +
+
+
+ {$i18n.t('Memories')} +
+ +
+ {#if defaultPermissions?.features?.memories && !permissions.features.memories} +
+
+ {$i18n.t('This is a default user permission and will remain enabled.')} +
+
+ {/if} +

diff --git a/src/lib/components/chat/SettingsModal.svelte b/src/lib/components/chat/SettingsModal.svelte index 9c601ca916..b9cdac92ac 100644 --- a/src/lib/components/chat/SettingsModal.svelte +++ b/src/lib/components/chat/SettingsModal.svelte @@ -491,6 +491,13 @@ return $user?.role === 'admin' || ($user?.permissions?.settings?.interface ?? true); } + if (tab.id === 'personalization') { + return ( + $config?.features?.enable_memories && + ($user?.role === 'admin' || ($user?.permissions?.features?.memories ?? true)) + ); + } + return true; }); }; diff --git a/src/lib/constants/permissions.ts b/src/lib/constants/permissions.ts index d40cda0908..8ef3426a7c 100644 --- a/src/lib/constants/permissions.ts +++ b/src/lib/constants/permissions.ts @@ -52,7 +52,8 @@ export const DEFAULT_PERMISSIONS = { direct_tool_servers: false, web_search: true, image_generation: true, - code_interpreter: true + code_interpreter: true, + memories: true }, settings: { interface: true diff --git a/src/lib/stores/index.ts b/src/lib/stores/index.ts index 9932dba052..5475480194 100644 --- a/src/lib/stores/index.ts +++ b/src/lib/stores/index.ts @@ -273,6 +273,7 @@ type Config = { enable_admin_export: boolean; enable_admin_chat_access: boolean; enable_community_sharing: boolean; + enable_memories: boolean; enable_autocomplete_generation: boolean; enable_direct_connections: boolean; enable_version_update_check: boolean; From e67891a374625d9888ec391da561f0b4ed79ed5d Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 8 Jan 2026 00:42:29 +0400 Subject: [PATCH 170/254] refac --- backend/open_webui/retrieval/utils.py | 13 +++- backend/open_webui/routers/configs.py | 6 +- backend/open_webui/routers/functions.py | 94 +++++++++++++++++++------ backend/open_webui/routers/tools.py | 73 +++++++++++++++---- backend/open_webui/utils/middleware.py | 46 ++++++++++++ backend/open_webui/utils/webhook.py | 6 +- 6 files changed, 197 insertions(+), 41 deletions(-) diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index c83c2d1207..56315c73fd 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -40,6 +40,7 @@ from open_webui.retrieval.loaders.youtube import YoutubeLoader from open_webui.env import ( + AIOHTTP_CLIENT_TIMEOUT, OFFLINE_MODE, ENABLE_FORWARD_USER_INFO_HEADERS, AIOHTTP_CLIENT_SESSION_SSL, @@ -596,7 +597,9 @@ async def agenerate_openai_batch_embeddings( if ENABLE_FORWARD_USER_INFO_HEADERS and user: headers = include_user_info_headers(headers, user) - async with aiohttp.ClientSession(trust_env=True) as session: + async with aiohttp.ClientSession( + trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) + ) as session: async with session.post( f"{url}/embeddings", headers=headers, json=form_data ) as r: @@ -685,7 +688,9 @@ async def agenerate_azure_openai_batch_embeddings( if ENABLE_FORWARD_USER_INFO_HEADERS and user: headers = include_user_info_headers(headers, user) - async with aiohttp.ClientSession(trust_env=True) as session: + async with aiohttp.ClientSession( + trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) + ) as session: async with session.post(full_url, headers=headers, json=form_data) as r: r.raise_for_status() data = await r.json() @@ -761,7 +766,9 @@ async def agenerate_ollama_batch_embeddings( if ENABLE_FORWARD_USER_INFO_HEADERS and user: headers = include_user_info_headers(headers, user) - async with aiohttp.ClientSession(trust_env=True) as session: + async with aiohttp.ClientSession( + trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) + ) as session: async with session.post( f"{url}/api/embed", headers=headers, diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 3ac9949eb3..180d23c1c8 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -6,6 +6,7 @@ import aiohttp from typing import Optional +from backend.open_webui.env import AIOHTTP_CLIENT_TIMEOUT from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.config import get_config, save_config from open_webui.config import BannerModel @@ -228,7 +229,10 @@ async def verify_tool_servers_config( log.debug( f"Trying to fetch OAuth 2.1 discovery document from {discovery_url}" ) - async with aiohttp.ClientSession(trust_env=True) as session: + async with aiohttp.ClientSession( + trust_env=True, + timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT), + ) as session: async with session.get( discovery_url ) as oauth_server_metadata_response: diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index b6dd07d736..8c098b9163 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -6,6 +6,7 @@ import aiohttp from pathlib import Path from typing import Optional +from backend.open_webui.env import AIOHTTP_CLIENT_TIMEOUT from open_webui.models.functions import ( FunctionForm, FunctionModel, @@ -39,12 +40,16 @@ router = APIRouter() @router.get("/", response_model=list[FunctionResponse]) -async def get_functions(user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_functions( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): return Functions.get_functions(db=db) @router.get("/list", response_model=list[FunctionUserResponse]) -async def get_function_list(user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def get_function_list( + user=Depends(get_admin_user), db: Session = Depends(get_session) +): return Functions.get_function_list(db=db) @@ -54,7 +59,11 @@ async def get_function_list(user=Depends(get_admin_user), db: Session = Depends( @router.get("/export", response_model=list[FunctionModel | FunctionWithValvesModel]) -async def get_functions(include_valves: bool = False, user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def get_functions( + include_valves: bool = False, + user=Depends(get_admin_user), + db: Session = Depends(get_session), +): return Functions.get_functions(include_valves=include_valves, db=db) @@ -112,7 +121,9 @@ async def load_function_from_url( ) try: - async with aiohttp.ClientSession(trust_env=True) as session: + 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"} ) as resp: @@ -144,7 +155,10 @@ class SyncFunctionsForm(BaseModel): @router.post("/sync", response_model=list[FunctionWithValvesModel]) async def sync_functions( - request: Request, form_data: SyncFunctionsForm, user=Depends(get_admin_user), db: Session = Depends(get_session) + request: Request, + form_data: SyncFunctionsForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): try: for function in form_data.functions: @@ -182,7 +196,10 @@ async def sync_functions( @router.post("/create", response_model=Optional[FunctionResponse]) async def create_new_function( - request: Request, form_data: FunctionForm, user=Depends(get_admin_user), db: Session = Depends(get_session) + request: Request, + form_data: FunctionForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): if not form_data.id.isidentifier(): raise HTTPException( @@ -205,13 +222,17 @@ async def create_new_function( FUNCTIONS = request.app.state.FUNCTIONS FUNCTIONS[form_data.id] = function_module - function = Functions.insert_new_function(user.id, function_type, form_data, db=db) + function = Functions.insert_new_function( + user.id, function_type, form_data, db=db + ) function_cache_dir = CACHE_DIR / "functions" / form_data.id function_cache_dir.mkdir(parents=True, exist_ok=True) if function_type == "filter" and getattr(function_module, "toggle", None): - Functions.update_function_metadata_by_id(form_data.id, {"toggle": True}, db=db) + Functions.update_function_metadata_by_id( + form_data.id, {"toggle": True}, db=db + ) if function: return function @@ -239,7 +260,9 @@ async def create_new_function( @router.get("/id/{id}", response_model=Optional[FunctionModel]) -async def get_function_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def get_function_by_id( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): function = Functions.get_function_by_id(id, db=db) if function: @@ -257,7 +280,9 @@ async def get_function_by_id(id: str, user=Depends(get_admin_user), db: Session @router.post("/id/{id}/toggle", response_model=Optional[FunctionModel]) -async def toggle_function_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def toggle_function_by_id( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): function = Functions.get_function_by_id(id, db=db) if function: function = Functions.update_function_by_id( @@ -284,7 +309,9 @@ async def toggle_function_by_id(id: str, user=Depends(get_admin_user), db: Sessi @router.post("/id/{id}/toggle/global", response_model=Optional[FunctionModel]) -async def toggle_global_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def toggle_global_by_id( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): function = Functions.get_function_by_id(id, db=db) if function: function = Functions.update_function_by_id( @@ -312,7 +339,11 @@ async def toggle_global_by_id(id: str, user=Depends(get_admin_user), db: Session @router.post("/id/{id}/update", response_model=Optional[FunctionModel]) async def update_function_by_id( - request: Request, id: str, form_data: FunctionForm, user=Depends(get_admin_user), db: Session = Depends(get_session) + request: Request, + id: str, + form_data: FunctionForm, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): try: form_data.content = replace_imports(form_data.content) @@ -354,7 +385,10 @@ async def update_function_by_id( @router.delete("/id/{id}/delete", response_model=bool) async def delete_function_by_id( - request: Request, id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) + request: Request, + id: str, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): result = Functions.delete_function_by_id(id, db=db) @@ -372,7 +406,9 @@ async def delete_function_by_id( @router.get("/id/{id}/valves", response_model=Optional[dict]) -async def get_function_valves_by_id(id: str, user=Depends(get_admin_user), db: Session = Depends(get_session)): +async def get_function_valves_by_id( + id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) +): function = Functions.get_function_by_id(id, db=db) if function: try: @@ -397,7 +433,10 @@ async def get_function_valves_by_id(id: str, user=Depends(get_admin_user), db: S @router.get("/id/{id}/valves/spec", response_model=Optional[dict]) async def get_function_valves_spec_by_id( - request: Request, id: str, user=Depends(get_admin_user), db: Session = Depends(get_session) + request: Request, + id: str, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): function = Functions.get_function_by_id(id, db=db) if function: @@ -423,7 +462,11 @@ async def get_function_valves_spec_by_id( @router.post("/id/{id}/valves/update", response_model=Optional[dict]) async def update_function_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_admin_user), db: Session = Depends(get_session) + request: Request, + id: str, + form_data: dict, + user=Depends(get_admin_user), + db: Session = Depends(get_session), ): function = Functions.get_function_by_id(id, db=db) if function: @@ -466,11 +509,15 @@ async def update_function_valves_by_id( @router.get("/id/{id}/valves/user", response_model=Optional[dict]) -async def get_function_user_valves_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_function_user_valves_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): function = Functions.get_function_by_id(id, db=db) if function: try: - user_valves = Functions.get_user_valves_by_id_and_user_id(id, user.id, db=db) + user_valves = Functions.get_user_valves_by_id_and_user_id( + id, user.id, db=db + ) return user_valves except Exception as e: raise HTTPException( @@ -486,7 +533,10 @@ async def get_function_user_valves_by_id(id: str, user=Depends(get_verified_user @router.get("/id/{id}/valves/user/spec", response_model=Optional[dict]) async def get_function_user_valves_spec_by_id( - request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): function = Functions.get_function_by_id(id, db=db) if function: @@ -507,7 +557,11 @@ async def get_function_user_valves_spec_by_id( @router.post("/id/{id}/valves/user/update", response_model=Optional[dict]) async def update_function_user_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + id: str, + form_data: dict, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): function = Functions.get_function_by_id(id, db=db) diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index d919debc38..6dd156e567 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -54,7 +54,11 @@ def get_tool_module(request, tool_id, load_from_db=True): @router.get("/", response_model=list[ToolUserResponse]) -async def get_tools(request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_tools( + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): tools = [] # Local Tools @@ -143,7 +147,9 @@ async def get_tools(request: Request, user=Depends(get_verified_user), db: Sessi # Admin can see all tools return tools else: - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user.id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user.id, db=db) + } tools = [ tool for tool in tools @@ -159,7 +165,9 @@ async def get_tools(request: Request, user=Depends(get_verified_user), db: Sessi @router.get("/list", response_model=list[ToolAccessResponse]) -async def get_tool_list(user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_tool_list( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: tools = Tools.get_tools(db=db) else: @@ -232,7 +240,9 @@ async def load_tool_from_url( ) try: - async with aiohttp.ClientSession(trust_env=True) as session: + 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"} ) as resp: @@ -259,9 +269,16 @@ async def load_tool_from_url( @router.get("/export", response_model=list[ToolModel]) -async def export_tools(request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def export_tools( + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), +): if user.role != "admin" and not has_permission( - user.id, "workspace.tools_export", request.app.state.config.USER_PERMISSIONS, db=db + user.id, + "workspace.tools_export", + request.app.state.config.USER_PERMISSIONS, + db=db, ): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -291,7 +308,10 @@ async def create_new_tools( user.id, "workspace.tools", request.app.state.config.USER_PERMISSIONS, db=db ) or has_permission( - user.id, "workspace.tools_import", request.app.state.config.USER_PERMISSIONS, db=db + user.id, + "workspace.tools_import", + request.app.state.config.USER_PERMISSIONS, + db=db, ) ): raise HTTPException( @@ -351,7 +371,9 @@ async def create_new_tools( @router.get("/id/{id}", response_model=Optional[ToolAccessResponse]) -async def get_tools_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_tools_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): tools = Tools.get_tool_by_id(id, db=db) if tools: @@ -451,7 +473,10 @@ async def update_tools_by_id( @router.delete("/id/{id}/delete", response_model=bool) async def delete_tools_by_id( - request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): tools = Tools.get_tool_by_id(id, db=db) if not tools: @@ -485,7 +510,9 @@ async def delete_tools_by_id( @router.get("/id/{id}/valves", response_model=Optional[dict]) -async def get_tools_valves_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_tools_valves_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): tools = Tools.get_tool_by_id(id, db=db) if tools: try: @@ -510,7 +537,10 @@ async def get_tools_valves_by_id(id: str, user=Depends(get_verified_user), db: S @router.get("/id/{id}/valves/spec", response_model=Optional[dict]) async def get_tools_valves_spec_by_id( - request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): tools = Tools.get_tool_by_id(id, db=db) if tools: @@ -538,7 +568,11 @@ async def get_tools_valves_spec_by_id( @router.post("/id/{id}/valves/update", response_model=Optional[dict]) async def update_tools_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + id: str, + form_data: dict, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): tools = Tools.get_tool_by_id(id, db=db) if not tools: @@ -590,7 +624,9 @@ async def update_tools_valves_by_id( @router.get("/id/{id}/valves/user", response_model=Optional[dict]) -async def get_tools_user_valves_by_id(id: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_tools_user_valves_by_id( + id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): tools = Tools.get_tool_by_id(id, db=db) if tools: try: @@ -610,7 +646,10 @@ async def get_tools_user_valves_by_id(id: str, user=Depends(get_verified_user), @router.get("/id/{id}/valves/user/spec", response_model=Optional[dict]) async def get_tools_user_valves_spec_by_id( - request: Request, id: str, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + id: str, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): tools = Tools.get_tool_by_id(id, db=db) if tools: @@ -633,7 +672,11 @@ async def get_tools_user_valves_spec_by_id( @router.post("/id/{id}/valves/user/update", response_model=Optional[dict]) async def update_tools_user_valves_by_id( - request: Request, id: str, form_data: dict, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + id: str, + form_data: dict, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): tools = Tools.get_tool_by_id(id, db=db) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index edbf866266..15dec7bedd 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -923,6 +923,48 @@ def get_image_urls(delta_images, request, metadata, user) -> list[str]: return image_urls +def inject_file_context_into_messages(messages: list) -> None: + """ + Inject file context into each user message that has files. + Modifies messages in-place by prepending file info to message content. + """ + for message in messages: + if message.get("role") != "user": + continue + + files = message.get("files", []) + if not files: + continue + + # Build XML context for this message's files + file_entries = [] + for file in files: + if not file.get("url"): + continue + + attrs = [f'type="{file.get("type", "file")}"'] + if file.get("content_type"): + attrs.append(f'content_type="{file["content_type"]}"') + if file.get("name"): + attrs.append(f'name="{file["name"]}"') + attrs.append(f'url="{file["url"]}"') + file_entries.append(f'') + + if not file_entries: + continue + + files_context = "\n" + "\n".join(file_entries) + "\n\n\n" + + # Prepend to message content + content = message.get("content", "") + if isinstance(content, str): + message["content"] = files_context + content + elif isinstance(content, list): + # For multimodal content, prepend as text item + message["content"] = [{"type": "text", "text": files_context}] + content + + + async def chat_image_generation_handler( request: Request, form_data: dict, extra_params: dict, user ): @@ -1748,6 +1790,10 @@ async def process_chat_payload(request, form_data, user, metadata, model): {"type": "function", "function": tool.get("spec", {})} for tool in tools_dict.values() ] + # Inject file context into each user message that has files attached + inject_file_context_into_messages(form_data.get("messages", [])) + + else: # If the function calling is not native, then call the tools function calling handler try: diff --git a/backend/open_webui/utils/webhook.py b/backend/open_webui/utils/webhook.py index b617abc06c..eb2688851f 100644 --- a/backend/open_webui/utils/webhook.py +++ b/backend/open_webui/utils/webhook.py @@ -3,7 +3,7 @@ import logging import aiohttp from open_webui.config import WEBUI_FAVICON_URL -from open_webui.env import VERSION +from open_webui.env import AIOHTTP_CLIENT_TIMEOUT, VERSION log = logging.getLogger(__name__) @@ -50,7 +50,9 @@ async def post_webhook(name: str, url: str, message: str, event_data: dict) -> b payload = {**event_data} log.debug(f"payload: {payload}") - async with aiohttp.ClientSession(trust_env=True) as session: + async with aiohttp.ClientSession( + trust_env=True, timeout=aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT) + ) as session: async with session.post(url, json=payload) as r: r_text = await r.text() r.raise_for_status() From aa084f804d3880b8a24ed5e5faa6298e8a0cc1e7 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 8 Jan 2026 00:53:21 +0400 Subject: [PATCH 171/254] refac --- backend/open_webui/routers/configs.py | 2 +- backend/open_webui/routers/functions.py | 2 +- backend/open_webui/routers/tools.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/routers/configs.py b/backend/open_webui/routers/configs.py index 180d23c1c8..152e2c3edc 100644 --- a/backend/open_webui/routers/configs.py +++ b/backend/open_webui/routers/configs.py @@ -6,7 +6,7 @@ import aiohttp from typing import Optional -from backend.open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_TIMEOUT from open_webui.utils.auth import get_admin_user, get_verified_user from open_webui.config import get_config, save_config from open_webui.config import BannerModel diff --git a/backend/open_webui/routers/functions.py b/backend/open_webui/routers/functions.py index 8c098b9163..ad47318911 100644 --- a/backend/open_webui/routers/functions.py +++ b/backend/open_webui/routers/functions.py @@ -6,7 +6,7 @@ import aiohttp from pathlib import Path from typing import Optional -from backend.open_webui.env import AIOHTTP_CLIENT_TIMEOUT +from open_webui.env import AIOHTTP_CLIENT_TIMEOUT from open_webui.models.functions import ( FunctionForm, FunctionModel, diff --git a/backend/open_webui/routers/tools.py b/backend/open_webui/routers/tools.py index 6dd156e567..03018d24a1 100644 --- a/backend/open_webui/routers/tools.py +++ b/backend/open_webui/routers/tools.py @@ -4,6 +4,7 @@ from typing import Optional import time import re import aiohttp +from open_webui.env import AIOHTTP_CLIENT_TIMEOUT from open_webui.models.groups import Groups from pydantic import BaseModel, HttpUrl from fastapi import APIRouter, Depends, HTTPException, Request, status From b6cef30bfc04f0338f1813f4b338943bc4daba3c Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 8 Jan 2026 01:24:31 +0400 Subject: [PATCH 172/254] refac --- src/lib/components/chat/Messages/UserMessage.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/components/chat/Messages/UserMessage.svelte b/src/lib/components/chat/Messages/UserMessage.svelte index 126b3732c9..417c6737f6 100644 --- a/src/lib/components/chat/Messages/UserMessage.svelte +++ b/src/lib/components/chat/Messages/UserMessage.svelte @@ -222,10 +222,14 @@
{#each editedFiles as file, fileIdx} {#if file.type === 'image' || (file?.content_type ?? '').startsWith('image/')} + {@const fileUrl = + file.url?.startsWith('data') || file.url?.startsWith('http') + ? file.url + : `${WEBUI_API_BASE_URL}/files/${file.url}${file?.content_type ? '/content' : ''}`}
From c417fdd94d86bd5738d6cde951d0495e68e120fa Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 8 Jan 2026 01:38:40 +0400 Subject: [PATCH 173/254] refac --- backend/open_webui/utils/middleware.py | 259 +++++++++++++++---------- 1 file changed, 156 insertions(+), 103 deletions(-) diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 15dec7bedd..34e34f21c3 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -143,19 +143,16 @@ DEFAULT_CODE_INTERPRETER_TAGS = [("", "")] def get_citation_source_from_tool_result( - tool_name: str, - tool_params: dict, - tool_result: str, - tool_id: str = "" + tool_name: str, tool_params: dict, tool_result: str, tool_id: str = "" ) -> list[dict]: """ Parse a tool's result and convert it to source dicts for citation display. - + Follows the source format conventions from get_sources_from_items: - source: file/item info object with id, name, type - - document: list of document contents + - document: list of document contents - metadata: list of metadata objects with source, file_id, name fields - + Returns a list of sources (usually one, but query_knowledge_bases may return multiple). """ try: @@ -171,56 +168,68 @@ def get_citation_source_from_tool_result( snippet = result.get("snippet", "") documents.append(f"{title}\n{snippet}") - metadata.append({ - "source": link, - "name": title, - "url": link, - }) + metadata.append( + { + "source": link, + "name": title, + "url": link, + } + ) - return [{ - "source": {"name": "search_web", "id": "search_web"}, - "document": documents, - "metadata": metadata, - }] + return [ + { + "source": {"name": "search_web", "id": "search_web"}, + "document": documents, + "metadata": metadata, + } + ] elif tool_name == "view_knowledge_file": file_data = json.loads(tool_result) filename = file_data.get("filename", "Unknown File") file_id = file_data.get("id", "") knowledge_name = file_data.get("knowledge_name", "") - - return [{ - "source": { - "id": file_id, - "name": filename, - "type": "file", - }, - "document": [file_data.get("content", "")], - "metadata": [{ - "file_id": file_id, - "name": filename, - "source": filename, - **({"knowledge_name": knowledge_name} if knowledge_name else {}), - }], - }] + + return [ + { + "source": { + "id": file_id, + "name": filename, + "type": "file", + }, + "document": [file_data.get("content", "")], + "metadata": [ + { + "file_id": file_id, + "name": filename, + "source": filename, + **( + {"knowledge_name": knowledge_name} + if knowledge_name + else {} + ), + } + ], + } + ] elif tool_name == "query_knowledge_bases": chunks = json.loads(tool_result) - + # Group chunks by source for better citation display # Each unique source becomes a separate source entry sources_by_file = {} - + for chunk in chunks: source_name = chunk.get("source", "Unknown") file_id = chunk.get("file_id", "") note_id = chunk.get("note_id", "") chunk_type = chunk.get("type", "file") content = chunk.get("content", "") - + # Use file_id or note_id as the key key = file_id or note_id or source_name - + if key not in sources_by_file: sources_by_file[key] = { "source": { @@ -231,36 +240,46 @@ def get_citation_source_from_tool_result( "document": [], "metadata": [], } - + sources_by_file[key]["document"].append(content) - sources_by_file[key]["metadata"].append({ - "file_id": file_id, - "name": source_name, - "source": source_name, - **({"note_id": note_id} if note_id else {}), - }) - + sources_by_file[key]["metadata"].append( + { + "file_id": file_id, + "name": source_name, + "source": source_name, + **({"note_id": note_id} if note_id else {}), + } + ) + # Return all grouped sources as a list if sources_by_file: return list(sources_by_file.values()) - + # Empty result fallback return [] else: # Fallback for other tools - return [{ - "source": {"name": tool_name, "type": "tool", "id": tool_id or tool_name}, - "document": [str(tool_result)], - "metadata": [{"source": tool_name, "name": tool_name}], - }] + return [ + { + "source": { + "name": tool_name, + "type": "tool", + "id": tool_id or tool_name, + }, + "document": [str(tool_result)], + "metadata": [{"source": tool_name, "name": tool_name}], + } + ] except Exception as e: log.exception(f"Error parsing tool result for {tool_name}: {e}") - return [{ - "source": {"name": tool_name, "type": "tool"}, - "document": [str(tool_result)], - "metadata": [{"source": tool_name}], - }] + return [ + { + "source": {"name": tool_name, "type": "tool"}, + "document": [str(tool_result)], + "metadata": [{"source": tool_name}], + } + ] def apply_source_context_to_messages( @@ -297,13 +316,17 @@ def apply_source_context_to_messages( if RAG_SYSTEM_CONTEXT: return add_or_update_system_message( - rag_template(request.app.state.config.RAG_TEMPLATE, context_string, user_message), + rag_template( + request.app.state.config.RAG_TEMPLATE, context_string, user_message + ), messages, append=True, ) else: return add_or_update_user_message( - rag_template(request.app.state.config.RAG_TEMPLATE, context_string, user_message), + rag_template( + request.app.state.config.RAG_TEMPLATE, context_string, user_message + ), messages, append=False, ) @@ -923,46 +946,52 @@ def get_image_urls(delta_images, request, metadata, user) -> list[str]: return image_urls -def inject_file_context_into_messages(messages: list) -> None: +def add_file_context(messages: list, chat_id: str, user) -> list: """ - Inject file context into each user message that has files. - Modifies messages in-place by prepending file info to message content. + Add file URLs to user messages for native function calling. """ - for message in messages: - if message.get("role") != "user": - continue - - files = message.get("files", []) - if not files: - continue - - # Build XML context for this message's files - file_entries = [] - for file in files: - if not file.get("url"): - continue - - attrs = [f'type="{file.get("type", "file")}"'] - if file.get("content_type"): - attrs.append(f'content_type="{file["content_type"]}"') - if file.get("name"): - attrs.append(f'name="{file["name"]}"') - attrs.append(f'url="{file["url"]}"') - file_entries.append(f'') - - if not file_entries: - continue - - files_context = "\n" + "\n".join(file_entries) + "\n\n\n" - - # Prepend to message content - content = message.get("content", "") - if isinstance(content, str): - message["content"] = files_context + content - elif isinstance(content, list): - # For multimodal content, prepend as text item - message["content"] = [{"type": "text", "text": files_context}] + content + if not chat_id or chat_id.startswith("local:"): + return messages + chat = Chats.get_chat_by_id_and_user_id(chat_id, user.id) + if not chat: + return messages + + history = chat.chat.get("history", {}) + stored_messages = get_message_list( + history.get("messages", {}), history.get("currentId") + ) + stored_user_messages = [msg for msg in stored_messages if msg.get("role") == "user"] + + def format_file_tag(file): + attrs = f'type="{file.get("type", "file")}" url="{file["url"]}"' + if file.get("content_type"): + attrs += f' content_type="{file["content_type"]}"' + if file.get("name"): + attrs += f' name="{file["name"]}"' + return f"" + + user_messages = [msg for msg in messages if msg.get("role") == "user"] + + for message, stored_message in zip(user_messages, stored_user_messages): + files_with_urls = [ + file for file in stored_message.get("files", []) if file.get("url") + ] + if not files_with_urls: + continue + + file_tags = [format_file_tag(file) for file in files_with_urls] + file_context = ( + "\n" + "\n".join(file_tags) + "\n\n\n" + ) + + content = message.get("content", "") + if isinstance(content, list): + message["content"] = [{"type": "text", "text": file_context}] + content + else: + message["content"] = file_context + content + + return messages async def chat_image_generation_handler( @@ -1454,7 +1483,10 @@ async def process_chat_payload(request, form_data, user, metadata, model): user_message = get_last_user_message(form_data["messages"]) model_knowledge = model.get("info", {}).get("meta", {}).get("knowledge", False) - if model_knowledge and metadata.get("params", {}).get("function_calling") != "native": + if ( + model_knowledge + and metadata.get("params", {}).get("function_calling") != "native" + ): await event_emitter( { "type": "status", @@ -1767,8 +1799,21 @@ async def process_chat_payload(request, form_data, user, metadata, model): # Inject builtin tools for native function calling based on enabled features and model capability # Check if builtin_tools capability is enabled for this model (defaults to True if not specified) - builtin_tools_enabled = model.get("info", {}).get("meta", {}).get("capabilities", {}).get("builtin_tools", True) - if metadata.get("params", {}).get("function_calling") == "native" and builtin_tools_enabled: + builtin_tools_enabled = ( + model.get("info", {}) + .get("meta", {}) + .get("capabilities", {}) + .get("builtin_tools", True) + ) + if ( + metadata.get("params", {}).get("function_calling") == "native" + and builtin_tools_enabled + ): + # Add file context to user messages + chat_id = metadata.get("chat_id") + form_data["messages"] = add_file_context( + form_data.get("messages", []), chat_id, user + ) builtin_tools = get_builtin_tools( request, { @@ -1790,9 +1835,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): {"type": "function", "function": tool.get("spec", {})} for tool in tools_dict.values() ] - # Inject file context into each user message that has files attached - inject_file_context_into_messages(form_data.get("messages", [])) - else: # If the function calling is not native, then call the tools function calling handler @@ -3279,13 +3321,21 @@ async def process_chat_response( ) # Extract citation sources from tool results - if tool_function_name in ["search_web", "view_knowledge_file", "query_knowledge_bases"] and tool_result: + if ( + tool_function_name + in [ + "search_web", + "view_knowledge_file", + "query_knowledge_bases", + ] + and tool_result + ): try: citation_sources = get_citation_source_from_tool_result( tool_name=tool_function_name, tool_params=tool_function_params, tool_result=tool_result, - tool_id=tool.get("tool_id", "") if tool else "" + tool_id=tool.get("tool_id", "") if tool else "", ) tool_call_sources.extend(citation_sources) except Exception as e: @@ -3325,7 +3375,10 @@ async def process_chat_response( user_msg = get_last_user_message(form_data["messages"]) if user_msg: form_data["messages"] = apply_source_context_to_messages( - request, form_data["messages"], tool_call_sources, user_msg + request, + form_data["messages"], + tool_call_sources, + user_msg, ) tool_call_sources.clear() From 700349064d228193e455e5308a77bb45656bd36e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 8 Jan 2026 01:55:56 +0400 Subject: [PATCH 174/254] chore: format --- backend/open_webui/env.py | 4 +- backend/open_webui/models/auths.py | 16 +- backend/open_webui/models/feedbacks.py | 32 ++- backend/open_webui/models/folders.py | 26 ++- backend/open_webui/models/functions.py | 35 +++- backend/open_webui/models/knowledge.py | 64 ++++-- backend/open_webui/models/memories.py | 16 +- backend/open_webui/models/messages.py | 13 +- backend/open_webui/models/models.py | 31 ++- backend/open_webui/models/notes.py | 12 +- backend/open_webui/models/oauth_sessions.py | 20 +- backend/open_webui/models/prompts.py | 13 +- backend/open_webui/models/tags.py | 12 +- backend/open_webui/models/tools.py | 26 ++- backend/open_webui/models/users.py | 56 +++-- backend/open_webui/routers/channels.py | 108 +++++++--- backend/open_webui/routers/chats.py | 2 +- backend/open_webui/routers/memories.py | 54 +++-- backend/open_webui/routers/ollama.py | 20 +- backend/open_webui/routers/openai.py | 5 +- backend/open_webui/routers/prompts.py | 26 ++- backend/open_webui/socket/main.py | 12 +- backend/open_webui/tools/builtin.py | 30 ++- backend/open_webui/utils/middleware.py | 7 +- backend/open_webui/utils/tools.py | 27 ++- src/lib/apis/index.ts | 2 +- src/lib/components/ChangelogModal.svelte | 6 +- .../admin/Settings/WebSearch.svelte | 60 +++--- src/lib/components/chat/MessageInput.svelte | 2 +- .../Messages/Citations/CitationModal.svelte | 10 +- .../components/common/FileItemModal.svelte | 5 +- .../common/RichTextInput/Collaboration.ts | 5 +- src/lib/components/notes/Notes.svelte | 10 +- src/lib/components/workspace/Models.svelte | 194 +++++++++--------- .../workspace/Models/Capabilities.svelte | 4 +- src/lib/components/workspace/Tools.svelte | 158 +++++++------- src/lib/constants/permissions.ts | 118 +++++------ src/lib/i18n/locales/ar-BH/translation.json | 76 ++++++- src/lib/i18n/locales/ar/translation.json | 76 ++++++- src/lib/i18n/locales/bg-BG/translation.json | 76 ++++++- src/lib/i18n/locales/bn-BD/translation.json | 76 ++++++- src/lib/i18n/locales/bo-TB/translation.json | 76 ++++++- src/lib/i18n/locales/bs-BA/translation.json | 76 ++++++- src/lib/i18n/locales/ca-ES/translation.json | 76 ++++++- src/lib/i18n/locales/ceb-PH/translation.json | 76 ++++++- src/lib/i18n/locales/cs-CZ/translation.json | 76 ++++++- src/lib/i18n/locales/da-DK/translation.json | 76 ++++++- src/lib/i18n/locales/de-DE/translation.json | 76 ++++++- src/lib/i18n/locales/dg-DG/translation.json | 76 ++++++- src/lib/i18n/locales/el-GR/translation.json | 76 ++++++- src/lib/i18n/locales/en-GB/translation.json | 76 ++++++- src/lib/i18n/locales/en-US/translation.json | 75 ++++++- src/lib/i18n/locales/es-ES/translation.json | 76 ++++++- src/lib/i18n/locales/et-EE/translation.json | 76 ++++++- src/lib/i18n/locales/eu-ES/translation.json | 76 ++++++- src/lib/i18n/locales/fa-IR/translation.json | 76 ++++++- src/lib/i18n/locales/fi-FI/translation.json | 76 ++++++- src/lib/i18n/locales/fr-CA/translation.json | 76 ++++++- src/lib/i18n/locales/fr-FR/translation.json | 76 ++++++- src/lib/i18n/locales/gl-ES/translation.json | 76 ++++++- src/lib/i18n/locales/he-IL/translation.json | 76 ++++++- src/lib/i18n/locales/hi-IN/translation.json | 76 ++++++- src/lib/i18n/locales/hr-HR/translation.json | 76 ++++++- src/lib/i18n/locales/hu-HU/translation.json | 76 ++++++- src/lib/i18n/locales/id-ID/translation.json | 76 ++++++- src/lib/i18n/locales/ie-GA/translation.json | 76 ++++++- src/lib/i18n/locales/it-IT/translation.json | 76 ++++++- src/lib/i18n/locales/ja-JP/translation.json | 76 ++++++- src/lib/i18n/locales/ka-GE/translation.json | 76 ++++++- src/lib/i18n/locales/kab-DZ/translation.json | 76 ++++++- src/lib/i18n/locales/ko-KR/translation.json | 76 ++++++- src/lib/i18n/locales/lt-LT/translation.json | 76 ++++++- src/lib/i18n/locales/ms-MY/translation.json | 76 ++++++- src/lib/i18n/locales/nb-NO/translation.json | 76 ++++++- src/lib/i18n/locales/nl-NL/translation.json | 76 ++++++- src/lib/i18n/locales/pa-IN/translation.json | 76 ++++++- src/lib/i18n/locales/pl-PL/translation.json | 76 ++++++- src/lib/i18n/locales/pt-BR/translation.json | 76 ++++++- src/lib/i18n/locales/pt-PT/translation.json | 76 ++++++- src/lib/i18n/locales/ro-RO/translation.json | 76 ++++++- src/lib/i18n/locales/ru-RU/translation.json | 76 ++++++- src/lib/i18n/locales/sk-SK/translation.json | 76 ++++++- src/lib/i18n/locales/sr-RS/translation.json | 76 ++++++- src/lib/i18n/locales/sv-SE/translation.json | 76 ++++++- src/lib/i18n/locales/th-TH/translation.json | 76 ++++++- src/lib/i18n/locales/tk-TM/translation.json | 76 ++++++- src/lib/i18n/locales/tr-TR/translation.json | 76 ++++++- src/lib/i18n/locales/ug-CN/translation.json | 76 ++++++- src/lib/i18n/locales/uk-UA/translation.json | 76 ++++++- src/lib/i18n/locales/ur-PK/translation.json | 76 ++++++- .../i18n/locales/uz-Cyrl-UZ/translation.json | 76 ++++++- .../i18n/locales/uz-Latn-Uz/translation.json | 76 ++++++- src/lib/i18n/locales/vi-VN/translation.json | 76 ++++++- src/lib/i18n/locales/zh-CN/translation.json | 61 +++++- src/lib/i18n/locales/zh-TW/translation.json | 61 +++++- src/lib/utils/index.ts | 14 +- src/lib/utils/marked/citation-extension.ts | 4 +- 97 files changed, 4650 insertions(+), 986 deletions(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 51f62b7ff1..b934462dc8 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -356,9 +356,7 @@ ENABLE_REALTIME_CHAT_SAVE = ( ENABLE_QUERIES_CACHE = os.environ.get("ENABLE_QUERIES_CACHE", "False").lower() == "true" -RAG_SYSTEM_CONTEXT = ( - os.environ.get("RAG_SYSTEM_CONTEXT", "False").lower() == "true" -) +RAG_SYSTEM_CONTEXT = os.environ.get("RAG_SYSTEM_CONTEXT", "False").lower() == "true" #################################### # REDIS diff --git a/backend/open_webui/models/auths.py b/backend/open_webui/models/auths.py index bb74fb7ded..93f17dff11 100644 --- a/backend/open_webui/models/auths.py +++ b/backend/open_webui/models/auths.py @@ -135,7 +135,9 @@ class AuthsTable: except Exception: return None - def authenticate_user_by_api_key(self, api_key: str, db: Optional[Session] = None) -> Optional[UserModel]: + def authenticate_user_by_api_key( + self, api_key: str, db: Optional[Session] = None + ) -> Optional[UserModel]: log.info(f"authenticate_user_by_api_key: {api_key}") # if no api_key, return None if not api_key: @@ -147,7 +149,9 @@ class AuthsTable: except Exception: return False - def authenticate_user_by_email(self, email: str, db: Optional[Session] = None) -> Optional[UserModel]: + def authenticate_user_by_email( + self, email: str, db: Optional[Session] = None + ) -> Optional[UserModel]: log.info(f"authenticate_user_by_email: {email}") try: with get_db_context(db) as db: @@ -158,7 +162,9 @@ class AuthsTable: except Exception: return None - def update_user_password_by_id(self, id: str, new_password: str, db: Optional[Session] = None) -> bool: + def update_user_password_by_id( + self, id: str, new_password: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: result = ( @@ -169,7 +175,9 @@ class AuthsTable: except Exception: return False - def update_email_by_id(self, id: str, email: str, db: Optional[Session] = None) -> bool: + def update_email_by_id( + self, id: str, email: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: result = db.query(Auth).filter_by(id=id).update({"email": email}) diff --git a/backend/open_webui/models/feedbacks.py b/backend/open_webui/models/feedbacks.py index fa2629a684..02379cd87e 100644 --- a/backend/open_webui/models/feedbacks.py +++ b/backend/open_webui/models/feedbacks.py @@ -149,7 +149,9 @@ class FeedbackTable: log.exception(f"Error creating a new feedback: {e}") return None - def get_feedback_by_id(self, id: str, db: Optional[Session] = None) -> Optional[FeedbackModel]: + def get_feedback_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[FeedbackModel]: try: with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id).first() @@ -172,7 +174,11 @@ class FeedbackTable: return None def get_feedback_items( - self, filter: dict = {}, skip: int = 0, limit: int = 30, db: Optional[Session] = None + self, + filter: dict = {}, + skip: int = 0, + limit: int = 30, + db: Optional[Session] = None, ) -> FeedbackListResponse: with get_db_context(db) as db: query = db.query(Feedback, User).join(User, Feedback.user_id == User.id) @@ -244,7 +250,9 @@ class FeedbackTable: .all() ] - def get_feedbacks_by_type(self, type: str, db: Optional[Session] = None) -> list[FeedbackModel]: + def get_feedbacks_by_type( + self, type: str, db: Optional[Session] = None + ) -> list[FeedbackModel]: with get_db_context(db) as db: return [ FeedbackModel.model_validate(feedback) @@ -254,7 +262,9 @@ class FeedbackTable: .all() ] - def get_feedbacks_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[FeedbackModel]: + def get_feedbacks_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[FeedbackModel]: with get_db_context(db) as db: return [ FeedbackModel.model_validate(feedback) @@ -285,7 +295,11 @@ class FeedbackTable: return FeedbackModel.model_validate(feedback) def update_feedback_by_id_and_user_id( - self, id: str, user_id: str, form_data: FeedbackForm, db: Optional[Session] = None + self, + id: str, + user_id: str, + form_data: FeedbackForm, + db: Optional[Session] = None, ) -> Optional[FeedbackModel]: with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id, user_id=user_id).first() @@ -313,7 +327,9 @@ class FeedbackTable: db.commit() return True - def delete_feedback_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: + def delete_feedback_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: feedback = db.query(Feedback).filter_by(id=id, user_id=user_id).first() if not feedback: @@ -322,7 +338,9 @@ class FeedbackTable: db.commit() return True - def delete_feedbacks_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + def delete_feedbacks_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: feedbacks = db.query(Feedback).filter_by(user_id=user_id).all() if not feedbacks: diff --git a/backend/open_webui/models/folders.py b/backend/open_webui/models/folders.py index 1744c29454..3455208944 100644 --- a/backend/open_webui/models/folders.py +++ b/backend/open_webui/models/folders.py @@ -84,7 +84,11 @@ class FolderUpdateForm(BaseModel): class FolderTable: def insert_new_folder( - self, user_id: str, form_data: FolderForm, parent_id: Optional[str] = None, db: Optional[Session] = None + self, + user_id: str, + form_data: FolderForm, + parent_id: Optional[str] = None, + db: Optional[Session] = None, ) -> Optional[FolderModel]: with get_db_context(db) as db: id = str(uuid.uuid4()) @@ -149,7 +153,9 @@ class FolderTable: except Exception: return None - def get_folders_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[FolderModel]: + def get_folders_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[FolderModel]: with get_db_context(db) as db: return [ FolderModel.model_validate(folder) @@ -157,7 +163,11 @@ class FolderTable: ] def get_folder_by_parent_id_and_user_id_and_name( - self, parent_id: Optional[str], user_id: str, name: str, db: Optional[Session] = None + self, + parent_id: Optional[str], + user_id: str, + name: str, + db: Optional[Session] = None, ) -> Optional[FolderModel]: try: with get_db_context(db) as db: @@ -213,7 +223,11 @@ class FolderTable: return def update_folder_by_id_and_user_id( - self, id: str, user_id: str, form_data: FolderUpdateForm, db: Optional[Session] = None + self, + id: str, + user_id: str, + form_data: FolderUpdateForm, + db: Optional[Session] = None, ) -> Optional[FolderModel]: try: with get_db_context(db) as db: @@ -278,7 +292,9 @@ class FolderTable: log.error(f"update_folder: {e}") return - def delete_folder_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> list[str]: + def delete_folder_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> list[str]: try: folder_ids = [] with get_db_context(db) as db: diff --git a/backend/open_webui/models/functions.py b/backend/open_webui/models/functions.py index f6d2aa3375..8e23bac093 100644 --- a/backend/open_webui/models/functions.py +++ b/backend/open_webui/models/functions.py @@ -104,7 +104,11 @@ class FunctionValves(BaseModel): class FunctionsTable: def insert_new_function( - self, user_id: str, type: str, form_data: FunctionForm, db: Optional[Session] = None + self, + user_id: str, + type: str, + form_data: FunctionForm, + db: Optional[Session] = None, ) -> Optional[FunctionModel]: function = FunctionModel( **{ @@ -131,7 +135,10 @@ class FunctionsTable: return None def sync_functions( - self, user_id: str, functions: list[FunctionWithValvesModel], db: Optional[Session] = None + self, + user_id: str, + functions: list[FunctionWithValvesModel], + db: Optional[Session] = None, ) -> list[FunctionWithValvesModel]: # Synchronize functions for a user by updating existing ones, inserting new ones, and removing those that are no longer present. try: @@ -178,7 +185,9 @@ class FunctionsTable: log.exception(f"Error syncing functions for user {user_id}: {e}") return [] - def get_function_by_id(self, id: str, db: Optional[Session] = None) -> Optional[FunctionModel]: + def get_function_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[FunctionModel]: try: with get_db_context(db) as db: function = db.get(Function, id) @@ -206,7 +215,9 @@ class FunctionsTable: FunctionModel.model_validate(function) for function in functions ] - def get_function_list(self, db: Optional[Session] = None) -> list[FunctionUserResponse]: + def get_function_list( + self, db: Optional[Session] = None + ) -> list[FunctionUserResponse]: with get_db_context(db) as db: functions = db.query(Function).order_by(Function.updated_at.desc()).all() user_ids = list(set(func.user_id for func in functions)) @@ -245,7 +256,9 @@ class FunctionsTable: for function in db.query(Function).filter_by(type=type).all() ] - def get_global_filter_functions(self, db: Optional[Session] = None) -> list[FunctionModel]: + def get_global_filter_functions( + self, db: Optional[Session] = None + ) -> list[FunctionModel]: with get_db_context(db) as db: return [ FunctionModel.model_validate(function) @@ -254,7 +267,9 @@ class FunctionsTable: .all() ] - def get_global_action_functions(self, db: Optional[Session] = None) -> list[FunctionModel]: + def get_global_action_functions( + self, db: Optional[Session] = None + ) -> list[FunctionModel]: with get_db_context(db) as db: return [ FunctionModel.model_validate(function) @@ -263,7 +278,9 @@ class FunctionsTable: .all() ] - def get_function_valves_by_id(self, id: str, db: Optional[Session] = None) -> Optional[dict]: + def get_function_valves_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[dict]: with get_db_context(db) as db: try: function = db.get(Function, id) @@ -352,7 +369,9 @@ class FunctionsTable: ) return None - def update_function_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[FunctionModel]: + def update_function_by_id( + self, id: str, updated: dict, db: Optional[Session] = None + ) -> Optional[FunctionModel]: with get_db_context(db) as db: try: db.query(Function).filter_by(id=id).update( diff --git a/backend/open_webui/models/knowledge.py b/backend/open_webui/models/knowledge.py index 724936d469..7f99f828c7 100644 --- a/backend/open_webui/models/knowledge.py +++ b/backend/open_webui/models/knowledge.py @@ -1,4 +1,3 @@ - import json import logging import time @@ -210,7 +209,12 @@ class KnowledgeTable: return knowledge_bases def search_knowledge_bases( - self, user_id: str, filter: dict, skip: int = 0, limit: int = 30, db: Optional[Session] = None + self, + user_id: str, + filter: dict, + skip: int = 0, + limit: int = 30, + db: Optional[Session] = None, ) -> KnowledgeListResponse: try: with get_db_context(db) as db: @@ -320,7 +324,9 @@ class KnowledgeTable: if user else None ), - collection=KnowledgeModel.model_validate(knowledge).model_dump(), + collection=KnowledgeModel.model_validate( + knowledge + ).model_dump(), ) ) @@ -330,20 +336,26 @@ class KnowledgeTable: print("search_knowledge_files error:", e) return KnowledgeFileListResponse(items=[], total=0) - def check_access_by_user_id(self, id, user_id, permission="write", db: Optional[Session] = None) -> bool: + def check_access_by_user_id( + self, id, user_id, permission="write", db: Optional[Session] = None + ) -> bool: knowledge = self.get_knowledge_by_id(id, db=db) if not knowledge: return False if knowledge.user_id == user_id: return True - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user_id, db=db) + } return has_access(user_id, permission, knowledge.access_control, user_group_ids) def get_knowledge_bases_by_user_id( self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[KnowledgeUserModel]: knowledge_bases = self.get_knowledge_bases(db=db) - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user_id, db=db) + } return [ knowledge_base for knowledge_base in knowledge_bases @@ -353,7 +365,9 @@ class KnowledgeTable: ) ] - def get_knowledge_by_id(self, id: str, db: Optional[Session] = None) -> Optional[KnowledgeModel]: + def get_knowledge_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[KnowledgeModel]: try: with get_db_context(db) as db: knowledge = db.query(Knowledge).filter_by(id=id).first() @@ -371,12 +385,16 @@ class KnowledgeTable: if knowledge.user_id == user_id: return knowledge - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user_id, db=db) + } if has_access(user_id, "write", knowledge.access_control, user_group_ids): return knowledge return None - def get_knowledges_by_file_id(self, file_id: str, db: Optional[Session] = None) -> list[KnowledgeModel]: + def get_knowledges_by_file_id( + self, file_id: str, db: Optional[Session] = None + ) -> list[KnowledgeModel]: try: with get_db_context(db) as db: knowledges = ( @@ -474,7 +492,9 @@ class KnowledgeTable: print(e) return KnowledgeFileListResponse(items=[], total=0) - def get_files_by_id(self, knowledge_id: str, db: Optional[Session] = None) -> list[FileModel]: + def get_files_by_id( + self, knowledge_id: str, db: Optional[Session] = None + ) -> list[FileModel]: try: with get_db_context(db) as db: files = ( @@ -487,7 +507,9 @@ class KnowledgeTable: except Exception: return [] - def get_file_metadatas_by_id(self, knowledge_id: str, db: Optional[Session] = None) -> list[FileMetadataResponse]: + def get_file_metadatas_by_id( + self, knowledge_id: str, db: Optional[Session] = None + ) -> list[FileMetadataResponse]: try: with get_db_context(db) as db: files = self.get_files_by_id(knowledge_id, db=db) @@ -496,7 +518,11 @@ class KnowledgeTable: return [] def add_file_to_knowledge_by_id( - self, knowledge_id: str, file_id: str, user_id: str, db: Optional[Session] = None + self, + knowledge_id: str, + file_id: str, + user_id: str, + db: Optional[Session] = None, ) -> Optional[KnowledgeFileModel]: with get_db_context(db) as db: knowledge_file = KnowledgeFileModel( @@ -522,7 +548,9 @@ class KnowledgeTable: except Exception: return None - def remove_file_from_knowledge_by_id(self, knowledge_id: str, file_id: str, db: Optional[Session] = None) -> bool: + def remove_file_from_knowledge_by_id( + self, knowledge_id: str, file_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(KnowledgeFile).filter_by( @@ -533,7 +561,9 @@ class KnowledgeTable: except Exception: return False - def reset_knowledge_by_id(self, id: str, db: Optional[Session] = None) -> Optional[KnowledgeModel]: + def reset_knowledge_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[KnowledgeModel]: try: with get_db_context(db) as db: # Delete all knowledge_file entries for this knowledge_id @@ -554,7 +584,11 @@ class KnowledgeTable: return None def update_knowledge_by_id( - self, id: str, form_data: KnowledgeForm, overwrite: bool = False, db: Optional[Session] = None + self, + id: str, + form_data: KnowledgeForm, + overwrite: bool = False, + db: Optional[Session] = None, ) -> Optional[KnowledgeModel]: try: with get_db_context(db) as db: diff --git a/backend/open_webui/models/memories.py b/backend/open_webui/models/memories.py index c0faed2c62..2dc9656856 100644 --- a/backend/open_webui/models/memories.py +++ b/backend/open_webui/models/memories.py @@ -94,7 +94,9 @@ class MemoriesTable: except Exception: return None - def get_memories_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[MemoryModel]: + def get_memories_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[MemoryModel]: with get_db_context(db) as db: try: memories = db.query(Memory).filter_by(user_id=user_id).all() @@ -102,7 +104,9 @@ class MemoriesTable: except Exception: return None - def get_memory_by_id(self, id: str, db: Optional[Session] = None) -> Optional[MemoryModel]: + def get_memory_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[MemoryModel]: with get_db_context(db) as db: try: memory = db.get(Memory, id) @@ -121,7 +125,9 @@ class MemoriesTable: except Exception: return False - def delete_memories_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + def delete_memories_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: try: db.query(Memory).filter_by(user_id=user_id).delete() @@ -131,7 +137,9 @@ class MemoriesTable: except Exception: return False - def delete_memory_by_id_and_user_id(self, id: str, user_id: str, db: Optional[Session] = None) -> bool: + def delete_memory_by_id_and_user_id( + self, id: str, user_id: str, db: Optional[Session] = None + ) -> bool: with get_db_context(db) as db: try: memory = db.get(Memory, id) diff --git a/backend/open_webui/models/messages.py b/backend/open_webui/models/messages.py index 3a27069f38..a4c91f3acb 100644 --- a/backend/open_webui/models/messages.py +++ b/backend/open_webui/models/messages.py @@ -538,15 +538,16 @@ class MessageTable: ) if start_timestamp: - query_builder = query_builder.filter(Message.created_at >= start_timestamp) + query_builder = query_builder.filter( + Message.created_at >= start_timestamp + ) if end_timestamp: - query_builder = query_builder.filter(Message.created_at <= end_timestamp) + query_builder = query_builder.filter( + Message.created_at <= end_timestamp + ) messages = ( - query_builder - .order_by(Message.created_at.desc()) - .limit(limit) - .all() + query_builder.order_by(Message.created_at.desc()).limit(limit).all() ) return [MessageModel.model_validate(msg) for msg in messages] diff --git a/backend/open_webui/models/models.py b/backend/open_webui/models/models.py index d8ac589d79..5457413f0d 100755 --- a/backend/open_webui/models/models.py +++ b/backend/open_webui/models/models.py @@ -222,7 +222,9 @@ class ModelsTable: self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[ModelUserResponse]: models = self.get_models(db=db) - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user_id, db=db) + } return [ model for model in models @@ -273,7 +275,12 @@ class ModelsTable: return query def search_models( - self, user_id: str, filter: dict = {}, skip: int = 0, limit: int = 30, db: Optional[Session] = None + self, + user_id: str, + filter: dict = {}, + skip: int = 0, + limit: int = 30, + db: Optional[Session] = None, ) -> ModelListResponse: with get_db_context(db) as db: # Join GroupMember so we can order by group_id when requested @@ -359,7 +366,9 @@ class ModelsTable: return ModelListResponse(items=models, total=total) - def get_model_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ModelModel]: + def get_model_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ModelModel]: try: with get_db_context(db) as db: model = db.get(Model, id) @@ -367,7 +376,9 @@ class ModelsTable: except Exception: return None - def get_models_by_ids(self, ids: list[str], db: Optional[Session] = None) -> list[ModelModel]: + def get_models_by_ids( + self, ids: list[str], db: Optional[Session] = None + ) -> list[ModelModel]: try: with get_db_context(db) as db: models = db.query(Model).filter(Model.id.in_(ids)).all() @@ -375,7 +386,9 @@ class ModelsTable: except Exception: return [] - def toggle_model_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ModelModel]: + def toggle_model_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ModelModel]: with get_db_context(db) as db: try: is_active = db.query(Model).filter_by(id=id).first().is_active @@ -392,7 +405,9 @@ class ModelsTable: except Exception: return None - def update_model_by_id(self, id: str, model: ModelForm, db: Optional[Session] = None) -> Optional[ModelModel]: + def update_model_by_id( + self, id: str, model: ModelForm, db: Optional[Session] = None + ) -> Optional[ModelModel]: try: with get_db_context(db) as db: # update only the fields that are present in the model @@ -428,7 +443,9 @@ class ModelsTable: except Exception: return False - def sync_models(self, user_id: str, models: list[ModelModel], db: Optional[Session] = None) -> list[ModelModel]: + def sync_models( + self, user_id: str, models: list[ModelModel], db: Optional[Session] = None + ) -> list[ModelModel]: try: with get_db_context(db) as db: # Get existing models diff --git a/backend/open_webui/models/notes.py b/backend/open_webui/models/notes.py index 425cd9e2cc..bd23530785 100644 --- a/backend/open_webui/models/notes.py +++ b/backend/open_webui/models/notes.py @@ -260,8 +260,16 @@ class NoteTable: normalized_query = query_key.replace("-", "").replace(" ", "") query = query.filter( or_( - func.replace(func.replace(Note.title, "-", ""), " ", "").ilike(f"%{normalized_query}%"), - func.replace(func.replace(cast(Note.data["content"]["md"], Text), "-", ""), " ", "").ilike(f"%{normalized_query}%"), + func.replace( + func.replace(Note.title, "-", ""), " ", "" + ).ilike(f"%{normalized_query}%"), + func.replace( + func.replace( + cast(Note.data["content"]["md"], Text), "-", "" + ), + " ", + "", + ).ilike(f"%{normalized_query}%"), ) ) diff --git a/backend/open_webui/models/oauth_sessions.py b/backend/open_webui/models/oauth_sessions.py index 4221987faa..f7ee5cceb8 100644 --- a/backend/open_webui/models/oauth_sessions.py +++ b/backend/open_webui/models/oauth_sessions.py @@ -143,7 +143,9 @@ class OAuthSessionTable: log.error(f"Error creating OAuth session: {e}") return None - def get_session_by_id(self, session_id: str, db: Optional[Session] = None) -> Optional[OAuthSessionModel]: + def get_session_by_id( + self, session_id: str, db: Optional[Session] = None + ) -> Optional[OAuthSessionModel]: """Get OAuth session by ID""" try: with get_db_context(db) as db: @@ -197,7 +199,9 @@ class OAuthSessionTable: log.error(f"Error getting OAuth session by provider and user ID: {e}") return None - def get_sessions_by_user_id(self, user_id: str, db: Optional[Session] = None) -> List[OAuthSessionModel]: + def get_sessions_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> List[OAuthSessionModel]: """Get all OAuth sessions for a user""" try: with get_db_context(db) as db: @@ -241,7 +245,9 @@ class OAuthSessionTable: log.error(f"Error updating OAuth session tokens: {e}") return None - def delete_session_by_id(self, session_id: str, db: Optional[Session] = None) -> bool: + def delete_session_by_id( + self, session_id: str, db: Optional[Session] = None + ) -> bool: """Delete an OAuth session""" try: with get_db_context(db) as db: @@ -252,7 +258,9 @@ class OAuthSessionTable: log.error(f"Error deleting OAuth session: {e}") return False - def delete_sessions_by_user_id(self, user_id: str, db: Optional[Session] = None) -> bool: + def delete_sessions_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> bool: """Delete all OAuth sessions for a user""" try: with get_db_context(db) as db: @@ -263,7 +271,9 @@ class OAuthSessionTable: log.error(f"Error deleting OAuth sessions by user ID: {e}") return False - def delete_sessions_by_provider(self, provider: str, db: Optional[Session] = None) -> bool: + def delete_sessions_by_provider( + self, provider: str, db: Optional[Session] = None + ) -> bool: """Delete all OAuth sessions for a provider""" try: with get_db_context(db) as db: diff --git a/backend/open_webui/models/prompts.py b/backend/open_webui/models/prompts.py index 89c49ccc80..847597bc65 100644 --- a/backend/open_webui/models/prompts.py +++ b/backend/open_webui/models/prompts.py @@ -1,4 +1,3 @@ - import time from typing import Optional @@ -100,7 +99,9 @@ class PromptsTable: except Exception: return None - def get_prompt_by_command(self, command: str, db: Optional[Session] = None) -> Optional[PromptModel]: + def get_prompt_by_command( + self, command: str, db: Optional[Session] = None + ) -> Optional[PromptModel]: try: with get_db_context(db) as db: prompt = db.query(Prompt).filter_by(command=command).first() @@ -135,7 +136,9 @@ class PromptsTable: self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[PromptUserResponse]: prompts = self.get_prompts(db=db) - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user_id, db=db) + } return [ prompt @@ -159,7 +162,9 @@ class PromptsTable: except Exception: return None - def delete_prompt_by_command(self, command: str, db: Optional[Session] = None) -> bool: + def delete_prompt_by_command( + self, command: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(Prompt).filter_by(command=command).delete() diff --git a/backend/open_webui/models/tags.py b/backend/open_webui/models/tags.py index 950c475ba3..64cb559547 100644 --- a/backend/open_webui/models/tags.py +++ b/backend/open_webui/models/tags.py @@ -51,7 +51,9 @@ class TagChatIdForm(BaseModel): class TagTable: - def insert_new_tag(self, name: str, user_id: str, db: Optional[Session] = None) -> Optional[TagModel]: + def insert_new_tag( + self, name: str, user_id: str, db: Optional[Session] = None + ) -> Optional[TagModel]: with get_db_context(db) as db: id = name.replace(" ", "_").lower() tag = TagModel(**{"id": id, "user_id": user_id, "name": name}) @@ -79,7 +81,9 @@ class TagTable: except Exception: return None - def get_tags_by_user_id(self, user_id: str, db: Optional[Session] = None) -> list[TagModel]: + def get_tags_by_user_id( + self, user_id: str, db: Optional[Session] = None + ) -> list[TagModel]: with get_db_context(db) as db: return [ TagModel.model_validate(tag) @@ -97,7 +101,9 @@ class TagTable: ) ] - def delete_tag_by_name_and_user_id(self, name: str, user_id: str, db: Optional[Session] = None) -> bool: + def delete_tag_by_name_and_user_id( + self, name: str, user_id: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: id = name.replace(" ", "_").lower() diff --git a/backend/open_webui/models/tools.py b/backend/open_webui/models/tools.py index ab62c658c3..cd7d0bd1a0 100644 --- a/backend/open_webui/models/tools.py +++ b/backend/open_webui/models/tools.py @@ -115,7 +115,11 @@ class ToolValves(BaseModel): class ToolsTable: def insert_new_tool( - self, user_id: str, form_data: ToolForm, specs: list[dict], db: Optional[Session] = None + self, + user_id: str, + form_data: ToolForm, + specs: list[dict], + db: Optional[Session] = None, ) -> Optional[ToolModel]: with get_db_context(db) as db: tool = ToolModel( @@ -141,7 +145,9 @@ class ToolsTable: log.exception(f"Error creating a new tool: {e}") return None - def get_tool_by_id(self, id: str, db: Optional[Session] = None) -> Optional[ToolModel]: + def get_tool_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[ToolModel]: try: with get_db_context(db) as db: tool = db.get(Tool, id) @@ -175,7 +181,9 @@ class ToolsTable: self, user_id: str, permission: str = "write", db: Optional[Session] = None ) -> list[ToolUserModel]: tools = self.get_tools(db=db) - user_group_ids = {group.id for group in Groups.get_groups_by_member_id(user_id, db=db)} + user_group_ids = { + group.id for group in Groups.get_groups_by_member_id(user_id, db=db) + } return [ tool @@ -184,7 +192,9 @@ class ToolsTable: or has_access(user_id, permission, tool.access_control, user_group_ids) ] - def get_tool_valves_by_id(self, id: str, db: Optional[Session] = None) -> Optional[dict]: + def get_tool_valves_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[dict]: try: with get_db_context(db) as db: tool = db.get(Tool, id) @@ -193,7 +203,9 @@ class ToolsTable: log.exception(f"Error getting tool valves by id {id}") return None - def update_tool_valves_by_id(self, id: str, valves: dict, db: Optional[Session] = None) -> Optional[ToolValves]: + def update_tool_valves_by_id( + self, id: str, valves: dict, db: Optional[Session] = None + ) -> Optional[ToolValves]: try: with get_db_context(db) as db: db.query(Tool).filter_by(id=id).update( @@ -249,7 +261,9 @@ class ToolsTable: ) return None - def update_tool_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[ToolModel]: + def update_tool_by_id( + self, id: str, updated: dict, db: Optional[Session] = None + ) -> Optional[ToolModel]: try: with get_db_context(db) as db: db.query(Tool).filter_by(id=id).update( diff --git a/backend/open_webui/models/users.py b/backend/open_webui/models/users.py index b19f3809b3..0d36d94b8f 100644 --- a/backend/open_webui/models/users.py +++ b/backend/open_webui/models/users.py @@ -269,7 +269,9 @@ class UsersTable: else: return None - def get_user_by_id(self, id: str, db: Optional[Session] = None) -> Optional[UserModel]: + def get_user_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: user = db.query(User).filter_by(id=id).first() @@ -277,7 +279,9 @@ class UsersTable: except Exception: return None - def get_user_by_api_key(self, api_key: str, db: Optional[Session] = None) -> Optional[UserModel]: + def get_user_by_api_key( + self, api_key: str, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: user = ( @@ -290,7 +294,9 @@ class UsersTable: except Exception: return None - def get_user_by_email(self, email: str, db: Optional[Session] = None) -> Optional[UserModel]: + def get_user_by_email( + self, email: str, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: user = db.query(User).filter_by(email=email).first() @@ -298,7 +304,9 @@ class UsersTable: except Exception: return None - def get_user_by_oauth_sub(self, provider: str, sub: str, db: Optional[Session] = None) -> Optional[UserModel]: + def get_user_by_oauth_sub( + self, provider: str, sub: str, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: # type: Session dialect_name = db.bind.dialect.name @@ -455,7 +463,9 @@ class UsersTable: "total": total, } - def get_users_by_group_id(self, group_id: str, db: Optional[Session] = None) -> list[UserModel]: + def get_users_by_group_id( + self, group_id: str, db: Optional[Session] = None + ) -> list[UserModel]: with get_db_context(db) as db: users = ( db.query(User) @@ -465,7 +475,9 @@ class UsersTable: ) return [UserModel.model_validate(user) for user in users] - def get_users_by_user_ids(self, user_ids: list[str], db: Optional[Session] = None) -> list[UserStatusModel]: + def get_users_by_user_ids( + self, user_ids: list[str], db: Optional[Session] = None + ) -> list[UserStatusModel]: with get_db_context(db) as db: users = db.query(User).filter(User.id.in_(user_ids)).all() return [UserModel.model_validate(user) for user in users] @@ -486,7 +498,9 @@ class UsersTable: except Exception: return None - def get_user_webhook_url_by_id(self, id: str, db: Optional[Session] = None) -> Optional[str]: + def get_user_webhook_url_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[str]: try: with get_db_context(db) as db: user = db.query(User).filter_by(id=id).first() @@ -511,7 +525,9 @@ class UsersTable: ) return query.count() - def update_user_role_by_id(self, id: str, role: str, db: Optional[Session] = None) -> Optional[UserModel]: + def update_user_role_by_id( + self, id: str, role: str, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: db.query(User).filter_by(id=id).update({"role": role}) @@ -552,7 +568,9 @@ class UsersTable: return None @throttle(DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL) - def update_last_active_by_id(self, id: str, db: Optional[Session] = None) -> Optional[UserModel]: + def update_last_active_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: db.query(User).filter_by(id=id).update( @@ -597,7 +615,9 @@ class UsersTable: except Exception: return None - def update_user_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[UserModel]: + def update_user_by_id( + self, id: str, updated: dict, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: db.query(User).filter_by(id=id).update(updated) @@ -610,7 +630,9 @@ class UsersTable: print(e) return None - def update_user_settings_by_id(self, id: str, updated: dict, db: Optional[Session] = None) -> Optional[UserModel]: + def update_user_settings_by_id( + self, id: str, updated: dict, db: Optional[Session] = None + ) -> Optional[UserModel]: try: with get_db_context(db) as db: user = db.query(User).filter_by(id=id).first() @@ -651,7 +673,9 @@ class UsersTable: except Exception: return False - def get_user_api_key_by_id(self, id: str, db: Optional[Session] = None) -> Optional[str]: + def get_user_api_key_by_id( + self, id: str, db: Optional[Session] = None + ) -> Optional[str]: try: with get_db_context(db) as db: api_key = db.query(ApiKey).filter_by(user_id=id).first() @@ -659,7 +683,9 @@ class UsersTable: except Exception: return None - def update_user_api_key_by_id(self, id: str, api_key: str, db: Optional[Session] = None) -> bool: + def update_user_api_key_by_id( + self, id: str, api_key: str, db: Optional[Session] = None + ) -> bool: try: with get_db_context(db) as db: db.query(ApiKey).filter_by(user_id=id).delete() @@ -690,7 +716,9 @@ class UsersTable: except Exception: return False - def get_valid_user_ids(self, user_ids: list[str], db: Optional[Session] = None) -> list[str]: + def get_valid_user_ids( + self, user_ids: list[str], db: Optional[Session] = None + ) -> list[str]: with get_db_context(db) as db: users = db.query(User).filter(User.id.in_(user_ids)).all() return [user.id for user in users] diff --git a/backend/open_webui/routers/channels.py b/backend/open_webui/routers/channels.py index fc0c048ab5..a2ff614524 100644 --- a/backend/open_webui/routers/channels.py +++ b/backend/open_webui/routers/channels.py @@ -117,7 +117,9 @@ async def get_channels( last_message = Messages.get_last_message_by_channel_id(channel.id, db=db) last_message_at = last_message.created_at if last_message else None - channel_member = Channels.get_member_by_channel_and_user_id(channel.id, user.id, db=db) + channel_member = Channels.get_member_by_channel_and_user_id( + channel.id, user.id, db=db + ) unread_count = ( Messages.get_unread_message_count( channel.id, user.id, channel_member.last_read_at, db=db @@ -135,7 +137,10 @@ async def get_channels( ] users = [ UserIdNameStatusResponse( - **{**user.model_dump(), "is_active": Users.is_user_active(user.id, db=db)} + **{ + **user.model_dump(), + "is_active": Users.is_user_active(user.id, db=db), + } ) for user in Users.get_users_by_user_ids(user_ids, db=db) ] @@ -187,11 +192,15 @@ async def get_dm_channel_by_user_id( ) try: - existing_channel = Channels.get_dm_channel_by_user_ids([user.id, user_id], db=db) + existing_channel = Channels.get_dm_channel_by_user_ids( + [user.id, user_id], db=db + ) if existing_channel: participant_ids = [ member.user_id - for member in Channels.get_members_by_channel_id(existing_channel.id, db=db) + for member in Channels.get_members_by_channel_id( + existing_channel.id, db=db + ) ] await emit_to_users( @@ -203,7 +212,9 @@ async def get_dm_channel_by_user_id( f"channel:{existing_channel.id}", participant_ids ) - Channels.update_member_active_status(existing_channel.id, user.id, True, db=db) + Channels.update_member_active_status( + existing_channel.id, user.id, True, db=db + ) return ChannelModel(**existing_channel.model_dump()) channel = Channels.insert_new_channel( @@ -288,7 +299,9 @@ async def create_new_channel( f"channel:{existing_channel.id}", participant_ids ) - Channels.update_member_active_status(existing_channel.id, user.id, True, db=db) + Channels.update_member_active_status( + existing_channel.id, user.id, True, db=db + ) return ChannelModel(**existing_channel.model_dump()) channel = Channels.insert_new_channel(form_data, user.id, db=db) @@ -353,17 +366,23 @@ async def get_channel_by_id( ) user_ids = [ - member.user_id for member in Channels.get_members_by_channel_id(channel.id, db=db) + member.user_id + for member in Channels.get_members_by_channel_id(channel.id, db=db) ] users = [ UserIdNameStatusResponse( - **{**user.model_dump(), "is_active": Users.is_user_active(user.id, db=db)} + **{ + **user.model_dump(), + "is_active": Users.is_user_active(user.id, db=db), + } ) for user in Users.get_users_by_user_ids(user_ids, db=db) ] - channel_member = Channels.get_member_by_channel_and_user_id(channel.id, user.id, db=db) + channel_member = Channels.get_member_by_channel_and_user_id( + channel.id, user.id, db=db + ) unread_count = Messages.get_unread_message_count( channel.id, user.id, channel_member.last_read_at if channel_member else None ) @@ -373,7 +392,9 @@ async def get_channel_by_id( **channel.model_dump(), "user_ids": user_ids, "users": users, - "is_manager": Channels.is_user_channel_manager(channel.id, user.id, db=db), + "is_manager": Channels.is_user_channel_manager( + channel.id, user.id, db=db + ), "write_access": True, "user_count": len(user_ids), "last_read_at": channel_member.last_read_at if channel_member else None, @@ -389,12 +410,18 @@ async def get_channel_by_id( ) write_access = has_access( - user.id, type="write", access_control=channel.access_control, strict=False, db=db + user.id, + type="write", + access_control=channel.access_control, + strict=False, + db=db, ) user_count = len(get_users_with_access("read", channel.access_control)) - channel_member = Channels.get_member_by_channel_and_user_id(channel.id, user.id, db=db) + channel_member = Channels.get_member_by_channel_and_user_id( + channel.id, user.id, db=db + ) unread_count = Messages.get_unread_message_count( channel.id, user.id, channel_member.last_read_at if channel_member else None ) @@ -404,7 +431,9 @@ async def get_channel_by_id( **channel.model_dump(), "user_ids": user_ids, "users": users, - "is_manager": Channels.is_user_channel_manager(channel.id, user.id, db=db), + "is_manager": Channels.is_user_channel_manager( + channel.id, user.id, db=db + ), "write_access": write_access or user.role == "admin", "user_count": user_count, "last_read_at": channel_member.last_read_at if channel_member else None, @@ -453,7 +482,8 @@ async def get_channel_members_by_id( if channel.type == "dm": user_ids = [ - member.user_id for member in Channels.get_members_by_channel_id(channel.id, db=db) + member.user_id + for member in Channels.get_members_by_channel_id(channel.id, db=db) ] users = Users.get_users_by_user_ids(user_ids, db=db) total = len(users) @@ -533,7 +563,9 @@ async def update_is_active_member_by_id_and_user_id( status_code=status.HTTP_404_NOT_FOUND, detail=ERROR_MESSAGES.NOT_FOUND ) - Channels.update_member_active_status(channel.id, user.id, form_data.is_active, db=db) + Channels.update_member_active_status( + channel.id, user.id, form_data.is_active, db=db + ) return True @@ -626,7 +658,9 @@ async def remove_members_by_id( ) try: - deleted = Channels.remove_members_from_channel(channel.id, form_data.user_ids, db=db) + deleted = Channels.remove_members_from_channel( + channel.id, form_data.user_ids, db=db + ) return deleted except Exception as e: @@ -794,7 +828,9 @@ async def get_channel_messages( **message.model_dump(), "reply_count": len(thread_replies), "latest_reply_at": latest_thread_reply_at, - "reactions": Messages.get_reactions_by_message_id(message.id, db=db), + "reactions": Messages.get_reactions_by_message_id( + message.id, db=db + ), "user": UserNameResponse(**users[message.user_id].model_dump()), } ) @@ -857,7 +893,9 @@ async def get_pinned_channel_messages( MessageWithReactionsResponse( **{ **message.model_dump(), - "reactions": Messages.get_reactions_by_message_id(message.id, db=db), + "reactions": Messages.get_reactions_by_message_id( + message.id, db=db + ), "user": UserNameResponse(**users[message.user_id].model_dump()), } ) @@ -871,7 +909,9 @@ async def get_pinned_channel_messages( ############################ -async def send_notification(name, webui_url, channel, message, active_user_ids, db=None): +async def send_notification( + name, webui_url, channel, message, active_user_ids, db=None +): users = get_users_with_access("read", channel.access_control) for user in users: @@ -966,7 +1006,9 @@ async def model_response_handler(request, channel, message, user, db=None): for thread_message in thread_messages: message_user = None if thread_message.user_id not in message_users: - message_user = Users.get_user_by_id(thread_message.user_id, db=db) + message_user = Users.get_user_by_id( + thread_message.user_id, db=db + ) message_users[thread_message.user_id] = message_user else: message_user = message_users[thread_message.user_id] @@ -1098,7 +1140,11 @@ async def new_message_handler( ) else: if user.role != "admin" and not has_access( - user.id, type="write", access_control=channel.access_control, strict=False, db=db + user.id, + type="write", + access_control=channel.access_control, + strict=False, + db=db, ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() @@ -1417,7 +1463,9 @@ async def get_channel_thread_messages( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() ) - message_list = Messages.get_messages_by_parent_id(id, message_id, skip, limit, db=db) + message_list = Messages.get_messages_by_parent_id( + id, message_id, skip, limit, db=db + ) if not message_list: return [] @@ -1434,7 +1482,9 @@ async def get_channel_thread_messages( **message.model_dump(), "reply_count": 0, "latest_reply_at": None, - "reactions": Messages.get_reactions_by_message_id(message.id, db=db), + "reactions": Messages.get_reactions_by_message_id( + message.id, db=db + ), "user": UserNameResponse(**users[message.user_id].model_dump()), } ) @@ -1554,7 +1604,11 @@ async def add_reaction_to_message( ) else: if user.role != "admin" and not has_access( - user.id, type="write", access_control=channel.access_control, strict=False, db=db + user.id, + type="write", + access_control=channel.access_control, + strict=False, + db=db, ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() @@ -1629,7 +1683,11 @@ async def remove_reaction_by_id_and_user_id_and_name( ) else: if user.role != "admin" and not has_access( - user.id, type="write", access_control=channel.access_control, strict=False, db=db + user.id, + type="write", + access_control=channel.access_control, + strict=False, + db=db, ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.DEFAULT() diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index ccbae22e36..9a43234aa6 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -383,7 +383,7 @@ def calculate_chat_stats( def generate_chat_stats_jsonl_generator(user_id, filter): """ Synchronous generator for streaming chat stats export. - + NOTE: We intentionally do NOT pass a shared db session here. Instead, we let each batch create its own short-lived session via get_db_context(None). This is critical for SQLite in low-resource environments because: diff --git a/backend/open_webui/routers/memories.py b/backend/open_webui/routers/memories.py index 6e98247ced..e0ba36c76f 100644 --- a/backend/open_webui/routers/memories.py +++ b/backend/open_webui/routers/memories.py @@ -18,8 +18,6 @@ log = logging.getLogger(__name__) router = APIRouter() - - @router.get("/ef") async def get_embeddings(request: Request): return {"result": await request.app.state.EMBEDDING_FUNCTION("hello world")} @@ -32,7 +30,9 @@ async def get_embeddings(request: Request): @router.get("/", response_model=list[MemoryModel]) async def get_memories( - request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if not request.app.state.config.ENABLE_MEMORIES: raise HTTPException( @@ -40,7 +40,9 @@ async def get_memories( detail=ERROR_MESSAGES.NOT_FOUND, ) - if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + if not has_permission( + user.id, "features.memories", request.app.state.config.USER_PERMISSIONS + ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -75,7 +77,9 @@ async def add_memory( detail=ERROR_MESSAGES.NOT_FOUND, ) - if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + if not has_permission( + user.id, "features.memories", request.app.state.config.USER_PERMISSIONS + ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -112,7 +116,10 @@ class QueryMemoryForm(BaseModel): @router.post("/query") async def query_memory( - request: Request, form_data: QueryMemoryForm, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + form_data: QueryMemoryForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if not request.app.state.config.ENABLE_MEMORIES: raise HTTPException( @@ -120,7 +127,9 @@ async def query_memory( detail=ERROR_MESSAGES.NOT_FOUND, ) - if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + if not has_permission( + user.id, "features.memories", request.app.state.config.USER_PERMISSIONS + ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -146,7 +155,9 @@ async def query_memory( ############################ @router.post("/reset", response_model=bool) async def reset_memory_from_vector_db( - request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if not request.app.state.config.ENABLE_MEMORIES: raise HTTPException( @@ -154,12 +165,14 @@ async def reset_memory_from_vector_db( detail=ERROR_MESSAGES.NOT_FOUND, ) - if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + if not has_permission( + user.id, "features.memories", request.app.state.config.USER_PERMISSIONS + ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - + VECTOR_DB_CLIENT.delete_collection(f"user-memory-{user.id}") memories = Memories.get_memories_by_user_id(user.id, db=db) @@ -198,7 +211,9 @@ async def reset_memory_from_vector_db( @router.delete("/delete/user", response_model=bool) async def delete_memory_by_user_id( - request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if not request.app.state.config.ENABLE_MEMORIES: raise HTTPException( @@ -206,7 +221,9 @@ async def delete_memory_by_user_id( detail=ERROR_MESSAGES.NOT_FOUND, ) - if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + if not has_permission( + user.id, "features.memories", request.app.state.config.USER_PERMISSIONS + ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -243,7 +260,9 @@ async def update_memory_by_id( detail=ERROR_MESSAGES.NOT_FOUND, ) - if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + if not has_permission( + user.id, "features.memories", request.app.state.config.USER_PERMISSIONS + ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, @@ -283,7 +302,10 @@ async def update_memory_by_id( @router.delete("/{memory_id}", response_model=bool) async def delete_memory_by_id( - memory_id: str, request: Request, user=Depends(get_verified_user), db: Session = Depends(get_session) + memory_id: str, + request: Request, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if not request.app.state.config.ENABLE_MEMORIES: raise HTTPException( @@ -291,7 +313,9 @@ async def delete_memory_by_id( detail=ERROR_MESSAGES.NOT_FOUND, ) - if not has_permission(user.id, "features.memories", request.app.state.config.USER_PERMISSIONS): + if not has_permission( + user.id, "features.memories", request.app.state.config.USER_PERMISSIONS + ): raise HTTPException( status_code=status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index 7760c422cc..4f0563bf30 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -1302,7 +1302,10 @@ async def generate_chat_completion( if not ( user.id == model_info.user_id or has_access( - user.id, type="read", access_control=model_info.access_control, db=db + user.id, + type="read", + access_control=model_info.access_control, + db=db, ) ): raise HTTPException( @@ -1409,7 +1412,10 @@ async def generate_openai_completion( if not ( user.id == model_info.user_id or has_access( - user.id, type="read", access_control=model_info.access_control, db=db + user.id, + type="read", + access_control=model_info.access_control, + db=db, ) ): raise HTTPException( @@ -1493,7 +1499,10 @@ async def generate_openai_chat_completion( if not ( user.id == model_info.user_id or has_access( - user.id, type="read", access_control=model_info.access_control, db=db + user.id, + type="read", + access_control=model_info.access_control, + db=db, ) ): raise HTTPException( @@ -1592,7 +1601,10 @@ async def get_openai_models( model_info = Models.get_model_by_id(model["id"], db=db) if model_info: if user.id == model_info.user_id or has_access( - user.id, type="read", access_control=model_info.access_control, db=db + user.id, + type="read", + access_control=model_info.access_control, + db=db, ): filtered_models.append(model) models = filtered_models diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index 18f937f369..6e43bd0034 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -837,7 +837,10 @@ async def generate_chat_completion( if not ( user.id == model_info.user_id or has_access( - user.id, type="read", access_control=model_info.access_control, db=db + user.id, + type="read", + access_control=model_info.access_control, + db=db, ) ): raise HTTPException( diff --git a/backend/open_webui/routers/prompts.py b/backend/open_webui/routers/prompts.py index 645cfe83ab..19d25685ad 100644 --- a/backend/open_webui/routers/prompts.py +++ b/backend/open_webui/routers/prompts.py @@ -23,7 +23,9 @@ router = APIRouter() @router.get("/", response_model=list[PromptModel]) -async def get_prompts(user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_prompts( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: prompts = Prompts.get_prompts(db=db) else: @@ -33,7 +35,9 @@ async def get_prompts(user=Depends(get_verified_user), db: Session = Depends(get @router.get("/list", response_model=list[PromptAccessResponse]) -async def get_prompt_list(user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_prompt_list( + user=Depends(get_verified_user), db: Session = Depends(get_session) +): if user.role == "admin" and BYPASS_ADMIN_ACCESS_CONTROL: prompts = Prompts.get_prompts(db=db) else: @@ -59,11 +63,17 @@ async def get_prompt_list(user=Depends(get_verified_user), db: Session = Depends @router.post("/create", response_model=Optional[PromptModel]) async def create_new_prompt( - request: Request, form_data: PromptForm, user=Depends(get_verified_user), db: Session = Depends(get_session) + request: Request, + form_data: PromptForm, + user=Depends(get_verified_user), + db: Session = Depends(get_session), ): if user.role != "admin" and not ( has_permission( - user.id, "workspace.prompts", request.app.state.config.USER_PERMISSIONS, db=db + user.id, + "workspace.prompts", + request.app.state.config.USER_PERMISSIONS, + db=db, ) or has_permission( user.id, @@ -99,7 +109,9 @@ async def create_new_prompt( @router.get("/command/{command}", response_model=Optional[PromptAccessResponse]) -async def get_prompt_by_command(command: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def get_prompt_by_command( + command: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): prompt = Prompts.get_prompt_by_command(f"/{command}", db=db) if prompt: @@ -169,7 +181,9 @@ async def update_prompt_by_command( @router.delete("/command/{command}/delete", response_model=bool) -async def delete_prompt_by_command(command: str, user=Depends(get_verified_user), db: Session = Depends(get_session)): +async def delete_prompt_by_command( + command: str, user=Depends(get_verified_user), db: Session = Depends(get_session) +): prompt = Prompts.get_prompt_by_command(f"/{command}", db=db) if not prompt: raise HTTPException( diff --git a/backend/open_webui/socket/main.py b/backend/open_webui/socket/main.py index ec59156630..67e04e69c3 100644 --- a/backend/open_webui/socket/main.py +++ b/backend/open_webui/socket/main.py @@ -246,11 +246,13 @@ def get_user_ids_from_room(room): active_session_ids = get_session_ids_from_room(room) active_user_ids = list( - set([ - SESSION_POOL.get(session_id)["id"] - for session_id in active_session_ids - if SESSION_POOL.get(session_id) is not None - ]) + set( + [ + SESSION_POOL.get(session_id)["id"] + for session_id in active_session_ids + if SESSION_POOL.get(session_id) is not None + ] + ) ) return active_user_ids diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 8f3c2a2dfb..f477a500ee 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -1378,7 +1378,9 @@ async def view_knowledge_file( if ( user_role == "admin" or knowledge_base.user_id == user_id - or has_access(user_id, "read", knowledge_base.access_control, user_group_ids) + or has_access( + user_id, "read", knowledge_base.access_control, user_group_ids + ) ): has_knowledge_access = True knowledge_info = {"id": knowledge_base.id, "name": knowledge_base.name} @@ -1463,7 +1465,9 @@ async def query_knowledge_bases( if knowledge and ( user_role == "admin" or knowledge.user_id == user_id - or has_access(user_id, "read", knowledge.access_control, user_group_ids) + or has_access( + user_id, "read", knowledge.access_control, user_group_ids + ) ): collection_names.append(item_id) @@ -1482,12 +1486,14 @@ async def query_knowledge_bases( or has_access(user_id, "read", note.access_control) ): content = note.data.get("content", {}).get("md", "") - note_results.append({ - "content": content, - "source": note.title, - "note_id": note.id, - "type": "note", - }) + note_results.append( + { + "content": content, + "source": note.title, + "note_id": note.id, + "type": "note", + } + ) elif knowledge_ids: # User specified specific KBs @@ -1496,7 +1502,9 @@ async def query_knowledge_bases( if knowledge and ( user_role == "admin" or knowledge.user_id == user_id - or has_access(user_id, "read", knowledge.access_control, user_group_ids) + or has_access( + user_id, "read", knowledge.access_control, user_group_ids + ) ): collection_names.append(knowledge_id) else: @@ -1535,7 +1543,9 @@ async def query_knowledge_bases( for idx, doc in enumerate(documents): chunk_info = { "content": doc, - "source": metadatas[idx].get("source", metadatas[idx].get("name", "Unknown")), + "source": metadatas[idx].get( + "source", metadatas[idx].get("name", "Unknown") + ), "file_id": metadatas[idx].get("file_id", ""), } if idx < len(distances): diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index 34e34f21c3..d7d8a4fcee 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -948,7 +948,7 @@ def get_image_urls(delta_images, request, metadata, user) -> list[str]: def add_file_context(messages: list, chat_id: str, user) -> list: """ - Add file URLs to user messages for native function calling. + Add file URLs to messages for native function calling. """ if not chat_id or chat_id.startswith("local:"): return messages @@ -961,7 +961,6 @@ def add_file_context(messages: list, chat_id: str, user) -> list: stored_messages = get_message_list( history.get("messages", {}), history.get("currentId") ) - stored_user_messages = [msg for msg in stored_messages if msg.get("role") == "user"] def format_file_tag(file): attrs = f'type="{file.get("type", "file")}" url="{file["url"]}"' @@ -971,9 +970,7 @@ def add_file_context(messages: list, chat_id: str, user) -> list: attrs += f' name="{file["name"]}"' return f"" - user_messages = [msg for msg in messages if msg.get("role") == "user"] - - for message, stored_message in zip(user_messages, stored_user_messages): + for message, stored_message in zip(messages, stored_messages): files_with_urls = [ file for file in stored_message.get("files", []) if file.get("url") ] diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 3bdb6d0cc0..478c29c44d 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -360,7 +360,12 @@ def get_builtin_tools( # Helper to get model capabilities (defaults to True if not specified) def get_model_capability(name: str, default: bool = True) -> bool: - return model.get("info", {}).get("meta", {}).get("capabilities", {}).get(name, default) + return ( + model.get("info", {}) + .get("meta", {}) + .get("capabilities", {}) + .get(name, default) + ) # Time utilities - always available for date calculations builtin_functions.extend([get_current_timestamp, calculate_timestamp]) @@ -375,7 +380,13 @@ def get_builtin_tools( else: # No model knowledge - allow full KB browsing builtin_functions.extend( - [list_knowledge_bases, search_knowledge_bases, search_knowledge_files, view_knowledge_file, query_knowledge_bases] + [ + list_knowledge_bases, + search_knowledge_bases, + search_knowledge_files, + view_knowledge_file, + query_knowledge_bases, + ] ) # Chats tools - search and fetch user's chat history @@ -386,9 +397,9 @@ def get_builtin_tools( builtin_functions.extend([search_memories, add_memory, replace_memory_content]) # Add web search tools if enabled globally AND model has web_search capability - if getattr(request.app.state.config, "ENABLE_WEB_SEARCH", False) and get_model_capability( - "web_search" - ): + if getattr( + request.app.state.config, "ENABLE_WEB_SEARCH", False + ) and get_model_capability("web_search"): builtin_functions.extend([search_web, fetch_url]) # Add image generation/edit tools if enabled globally AND model has image_generation capability @@ -396,9 +407,9 @@ def get_builtin_tools( request.app.state.config, "ENABLE_IMAGE_GENERATION", False ) and get_model_capability("image_generation"): builtin_functions.append(generate_image) - if getattr(request.app.state.config, "ENABLE_IMAGE_EDIT", False) and get_model_capability( - "image_generation" - ): + if getattr( + request.app.state.config, "ENABLE_IMAGE_EDIT", False + ) and get_model_capability("image_generation"): builtin_functions.append(edit_image) # Notes tools - search, view, create, and update user's notes (if notes enabled globally) diff --git a/src/lib/apis/index.ts b/src/lib/apis/index.ts index 6b5e67e47b..8f35fbf881 100644 --- a/src/lib/apis/index.ts +++ b/src/lib/apis/index.ts @@ -1674,7 +1674,7 @@ export interface ModelMeta { profile_image_url?: string; } -export interface ModelParams { } +export interface ModelParams {} export type GlobalModelConfig = ModelConfig[]; diff --git a/src/lib/components/ChangelogModal.svelte b/src/lib/components/ChangelogModal.svelte index fc170501c4..fa8381f7f9 100644 --- a/src/lib/components/ChangelogModal.svelte +++ b/src/lib/components/ChangelogModal.svelte @@ -43,11 +43,7 @@ {$WEBUI_NAME}
-
{/if} - {#if webConfig.WEB_SEARCH_ENGINE === 'duckduckgo'} -
-
-
- {$i18n.t('DDGS Backend')} -
+ {#if webConfig.WEB_SEARCH_ENGINE === 'duckduckgo'} +
+
+
+ {$i18n.t('DDGS Backend')} +
-
-
- +
+
+ +
-
+ {/if} {/if} - {/if} {#if webConfig.ENABLE_WEB_SEARCH}
diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index e2f13538b2..fa88acd5b5 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -200,7 +200,7 @@ } } - text = text.replaceAll('{{CLIPBOARD}}', clipboardText.replaceAll('\r\n', '\n')); + text = text.replaceAll('{{CLIPBOARD}}', clipboardText.replaceAll('\r\n', '\n')); } if (text.includes('{{USER_LOCATION}}')) { diff --git a/src/lib/components/chat/Messages/Citations/CitationModal.svelte b/src/lib/components/chat/Messages/Citations/CitationModal.svelte index 2dd4967a12..a90abd2590 100644 --- a/src/lib/components/chat/Messages/Citations/CitationModal.svelte +++ b/src/lib/components/chat/Messages/Citations/CitationModal.svelte @@ -161,7 +161,8 @@ href={snippetUrl} target="_blank" class="underline hover:text-gray-500 dark:hover:text-gray-100" - >{$i18n.t('Content')} + >{$i18n.t('Content')} {:else} {$i18n.t('Content')} {/if} @@ -207,7 +208,10 @@ {#if document.metadata?.html} @@ -215,7 +219,7 @@
{document.document
 										.trim()
 										.replace(/\n\n+/g, '\n\n')}
- {/if} + {/if}
{/each} diff --git a/src/lib/components/common/FileItemModal.svelte b/src/lib/components/common/FileItemModal.svelte index 709d622624..7db775865e 100644 --- a/src/lib/components/common/FileItemModal.svelte +++ b/src/lib/components/common/FileItemModal.svelte @@ -92,7 +92,10 @@ const loadExcelContent = async () => { try { excelError = ''; - const [arrayBuffer, { read }] = await Promise.all([getFileContentById(item.id), import('xlsx')]); + const [arrayBuffer, { read }] = await Promise.all([ + getFileContentById(item.id), + import('xlsx') + ]); excelWorkbook = read(arrayBuffer, { type: 'array' }); excelSheetNames = excelWorkbook.SheetNames; diff --git a/src/lib/components/common/RichTextInput/Collaboration.ts b/src/lib/components/common/RichTextInput/Collaboration.ts index dc2de6b70c..e261af01a1 100644 --- a/src/lib/components/common/RichTextInput/Collaboration.ts +++ b/src/lib/components/common/RichTextInput/Collaboration.ts @@ -138,7 +138,10 @@ export class SocketIOCollaborationProvider { // The Yjs plugin will automatically sync the content } else { // JSON content - use the existing approach - const editorYdoc = prosemirrorJSONToYDoc(this.editor.schema, this.initialContent); + const editorYdoc = prosemirrorJSONToYDoc( + this.editor.schema, + this.initialContent + ); if (editorYdoc) { Y.applyUpdate(this.doc, Y.encodeStateAsUpdate(editorYdoc)); } diff --git a/src/lib/components/notes/Notes.svelte b/src/lib/components/notes/Notes.svelte index 61247b32fd..6074c7f063 100644 --- a/src/lib/components/notes/Notes.svelte +++ b/src/lib/components/notes/Notes.svelte @@ -221,7 +221,7 @@ // Build the grouped object while tracking order const grouped: Record = {}; const orderedKeys: string[] = []; - + for (const note of res) { const timeRange = getTimeRange(note.updated_at / 1000000000); if (!grouped[timeRange]) { @@ -233,9 +233,9 @@ timeRange }); } - + // Return as array of [timeRange, notes] to preserve insertion order - return orderedKeys.map(key => [key, grouped[key]] as [string, any[]]); + return orderedKeys.map((key) => [key, grouped[key]] as [string, any[]]); }; let dragged = false; @@ -455,9 +455,7 @@ {#if displayOption === null}
{#each notesList as note, idx (note.id)}
{ if (model.write_access) { @@ -504,110 +506,110 @@ {/if} {#if model.write_access || $user?.role === 'admin'} -
-
- {#if shiftKey} - - + + + + + + {:else} + { + goto( + `/workspace/models/edit?id=${encodeURIComponent(model.id)}` + ); + }} + shareHandler={() => { + shareModelHandler(model); + }} + cloneHandler={() => { + cloneModelHandler(model); + }} + exportHandler={() => { + exportModelHandler(model); + }} + hideHandler={() => { hideModelHandler(model); }} - > - {#if model?.meta?.hidden} - - {:else} - - {/if} - - - - - - - {:else} - { - goto( - `/workspace/models/edit?id=${encodeURIComponent(model.id)}` - ); - }} - shareHandler={() => { - shareModelHandler(model); - }} - cloneHandler={() => { - cloneModelHandler(model); - }} - exportHandler={() => { - exportModelHandler(model); - }} - hideHandler={() => { - hideModelHandler(model); - }} - pinModelHandler={() => { - pinModelHandler(model.id); - }} - copyLinkHandler={() => { - copyLinkHandler(model); - }} - deleteHandler={() => { - selectedModel = model; - showModelDeleteConfirm = true; - }} - onClose={() => {}} - > -
- -
-
- {/if} +
+ +
+
+ {/if} +
-
{/if} {#if model.write_access} - + + { + toggleModelById(localStorage.token, model.id); + _models.set( + await getModels( + localStorage.token, + $config?.features?.enable_direct_connections && + ($settings?.directConnections ?? null) + ) + ); + }} + /> + + {/if}
diff --git a/src/lib/components/workspace/Models/Capabilities.svelte b/src/lib/components/workspace/Models/Capabilities.svelte index 4f2c4988d1..b5dc7a02c9 100644 --- a/src/lib/components/workspace/Models/Capabilities.svelte +++ b/src/lib/components/workspace/Models/Capabilities.svelte @@ -43,7 +43,9 @@ }, builtin_tools: { label: $i18n.t('Builtin Tools'), - description: $i18n.t('Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)') + description: $i18n.t( + 'Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)' + ) } }; diff --git a/src/lib/components/workspace/Tools.svelte b/src/lib/components/workspace/Tools.svelte index d179896936..7ca7437758 100644 --- a/src/lib/components/workspace/Tools.svelte +++ b/src/lib/components/workspace/Tools.svelte @@ -358,7 +358,9 @@ {#each filteredItems as tool}
{#if tool.write_access} {:else} -
+
@@ -438,94 +438,94 @@
{/if} {#if tool.write_access} -
- {#if shiftKey} - - - - {:else} - {#if tool?.meta?.manifest?.funding_url ?? false} - +
+ {#if shiftKey} + + + + {:else} + {#if tool?.meta?.manifest?.funding_url ?? false} + + + + {/if} + + - {/if} - - - - - { - goto(`/workspace/tools/edit?id=${encodeURIComponent(tool.id)}`); - }} - shareHandler={() => { - shareHandler(tool); - }} - cloneHandler={() => { - cloneHandler(tool); - }} - exportHandler={() => { - exportHandler(tool); - }} - deleteHandler={async () => { - selectedTool = tool; - showDeleteConfirm = true; - }} - onClose={() => {}} - > - - - {/if} -
+ + + + {/if} +
{/if}
diff --git a/src/lib/constants/permissions.ts b/src/lib/constants/permissions.ts index 8ef3426a7c..58a362aad1 100644 --- a/src/lib/constants/permissions.ts +++ b/src/lib/constants/permissions.ts @@ -1,61 +1,61 @@ export const DEFAULT_PERMISSIONS = { - workspace: { - models: false, - knowledge: false, - prompts: false, - tools: false, - models_import: false, - models_export: false, - prompts_import: false, - prompts_export: false, - tools_import: false, - tools_export: false - }, - sharing: { - models: false, - public_models: false, - knowledge: false, - public_knowledge: false, - prompts: false, - public_prompts: false, - tools: false, - public_tools: false, - notes: false, - public_notes: false - }, - chat: { - controls: true, - valves: true, - system_prompt: true, - params: true, - file_upload: true, - delete: true, - delete_message: true, - continue_response: true, - regenerate_response: true, - rate_response: true, - edit: true, - share: true, - export: true, - stt: true, - tts: true, - call: true, - multiple_models: true, - temporary: true, - temporary_enforced: false - }, - features: { - api_keys: false, - notes: true, - channels: true, - folders: true, - direct_tool_servers: false, - web_search: true, - image_generation: true, - code_interpreter: true, - memories: true - }, - settings: { - interface: true - } + workspace: { + models: false, + knowledge: false, + prompts: false, + tools: false, + models_import: false, + models_export: false, + prompts_import: false, + prompts_export: false, + tools_import: false, + tools_export: false + }, + sharing: { + models: false, + public_models: false, + knowledge: false, + public_knowledge: false, + prompts: false, + public_prompts: false, + tools: false, + public_tools: false, + notes: false, + public_notes: false + }, + chat: { + controls: true, + valves: true, + system_prompt: true, + params: true, + file_upload: true, + delete: true, + delete_message: true, + continue_response: true, + regenerate_response: true, + rate_response: true, + edit: true, + share: true, + export: true, + stt: true, + tts: true, + call: true, + multiple_models: true, + temporary: true, + temporary_enforced: false + }, + features: { + api_keys: false, + notes: true, + channels: true, + folders: true, + direct_tool_servers: false, + web_search: true, + image_generation: true, + code_interpreter: true, + memories: true + }, + settings: { + interface: true + } } as const; diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index f84a6564c9..0e5b960209 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "سيؤدي ضبط هذه الإعدادات إلى تطبيق التغييرات بشكل عام على كافة المستخدمين", "admin": "المشرف", "Admin": "", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "و أنشئ رابط مشترك جديد.", "Android": "", + "Anyone": "", "API Base URL": "API الرابط الرئيسي", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API مفتاح", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "النسخ التلقائي للاستجابة إلى الحافظة", "Auto-playback response": "استجابة التشغيل التلقائي", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 الرابط الرئيسي", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 الرابط مطلوب", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "المستخدمون المتاحون", @@ -201,6 +204,7 @@ "before": "قبل", "Being lazy": "كون كسول", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "مفتاح واجهة برمجة تطبيقات البحث الشجاع", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "تحقق من التحديثات", "Checking for updates...": "البحث عن تحديثات", "Choose a model before saving...": "أختار موديل قبل الحفظ", + "Chunk Min Size Target": "", "Chunk Overlap": "Chunk تداخل", "Chunk Size": "Chunk حجم", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "اقتباس", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "الاتصال", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "متابعة الرد", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "قاعدة البيانات", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "ديسمبر", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "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.": "لا تجلب خطوط أنابيب عشوائية من مصادر غير موثوقة.", @@ -493,11 +502,14 @@ "Done": "", "Download": "تحميل", "Download & Delete": "تنزيل وحذف", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "تم اللغاء التحميل", "Download Database": "تحميل قاعدة البيانات", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "e.g. '30s','10m'. الوحدات الزمنية الصالحة هي 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "أدخل مفتاح واجهة برمجة تطبيقات البحث الشجاع", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "أدخل الChunk Overlap", "Enter Chunk Size": "أدخل Chunk الحجم", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "أدخل عنوان URL ل Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "(e.g. 512x512) أدخل حجم الصورة ", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "أدخل كود اللغة", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "فبراير", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "لا تتردد في إضافة تفاصيل محددة", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "تم اكتشاف انتحال بصمة الإصبع: غير قادر على استخدام الأحرف الأولى كصورة رمزية. الافتراضي لصورة الملف الشخصي الافتراضية.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "عام", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "إنشاء استعلام بحث", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "استجابة جيدة", + "Google": "", "Google Drive": "", "Google PSE API Key": "مفتاح واجهة برمجة تطبيقات PSE من Google", "Google PSE Engine Id": "معرف محرك PSE من Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "مجموعة", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "الصور", "Import": "", "Import Chats": "استيراد الدردشات", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "واجهه المستخدم", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "يناير", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "انضم إلى Discord للحصول على المساعدة.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "مارس", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "يمكن تنزيل 3 نماذج كحد أقصى في وقت واحد. الرجاء معاودة المحاولة في وقت لاحق.", "May": "مايو", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "سيتم عرض الذكريات التي يمكن الوصول إليها بواسطة LLMs هنا.", "Memory": "الذاكرة", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "نتيجة الردود المدمجة", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "لم تختار موديل", "Model Params": "معلمات النموذج", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "المزيد", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "لا توجد نتائج", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "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.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "الباسورد", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "خطوط الانابيب", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines عبارة عن نظام إضافات يتيح تنفيذًا عشوائيًا للتعليمات البرمجية —", "Pipelines Not Detected": "", "Pipelines Valves": "صمامات خطوط الأنابيب", @@ -1502,6 +1536,7 @@ "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.": "", "Setting": "", "Settings": "الاعدادات", + "Settings Permissions": "", "Settings saved successfully!": "تم حفظ الاعدادات بنجاح", "Share": "كشاركة", "Share Chat": "مشاركة الدردشة", @@ -1545,6 +1580,7 @@ "Speech recognition error: {{error}}": "{{error}} خطأ في التعرف على الكلام", "Speech-to-Text": "", "Speech-to-Text Engine": "محرك تحويل الكلام إلى نص", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "بداية القناة", "Start Tag": "", @@ -1555,6 +1591,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "وقف التسلسل", "Stream Chat Response": "", @@ -1575,7 +1612,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "النظام", "System Instructions": "", "System Prompt": "محادثة النظام", @@ -1620,6 +1664,7 @@ "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.": "", "Theme": "الثيم", + "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.": "", @@ -1734,6 +1779,7 @@ "Upload Pipeline": "", "Upload Progress": "جاري التحميل", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1751,6 +1797,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1800,15 +1847,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "ما هو الجديد", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "مساحة العمل", @@ -1820,6 +1871,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "أمس", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "انت", @@ -1827,6 +1880,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1838,6 +1894,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/ar/translation.json b/src/lib/i18n/locales/ar/translation.json index 7964c1e0ca..88fe7e1ef1 100644 --- a/src/lib/i18n/locales/ar/translation.json +++ b/src/lib/i18n/locales/ar/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "تعديل هذه الإعدادات سيطبق التغييرات على جميع المستخدمين بشكل عام.", "admin": "المسؤول", "Admin": "المسؤول", + "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.": "للمسؤولين الوصول إلى جميع الأدوات في جميع الأوقات؛ بينما يحتاج المستخدمون إلى تعيين أدوات لكل نموذج في مساحة العمل.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "السماح بتحميل الملفات", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "السماح بالأصوات غير المحلية", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "و{{COUNT}} المزيد", "and create a new shared link.": "وإنشاء رابط مشترك جديد.", "Android": "", + "Anyone": "", "API Base URL": "الرابط الأساسي لواجهة API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "مفتاح واجهة برمجة التطبيقات (API)", @@ -175,6 +176,7 @@ "Authenticate": "توثيق", "Authentication": "المصادقة", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "نسخ الرد تلقائيًا إلى الحافظة", "Auto-playback response": "تشغيل الرد تلقائيًا", "Autocomplete Generation": "توليد الإكمال التلقائي", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "سلسلة توثيق API لـ AUTOMATIC1111", "AUTOMATIC1111 Base URL": "الرابط الأساسي لـ AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "الرابط الأساسي لـ AUTOMATIC1111 مطلوب.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "القائمة المتاحة", "Available Tools": "", "available users": "المستخدمون المتاحون", @@ -201,6 +204,7 @@ "before": "قبل", "Being lazy": "كونك كسولاً", "Beta": "بيتا", + "Bing": "", "Bing Search V7 Endpoint": "نقطة نهاية Bing Search V7", "Bing Search V7 Subscription Key": "مفتاح اشتراك Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "مفتاح API لـ Bocha Search", "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 Search API Key": "مفتاح API لـ Brave Search", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "تحقق من التحديثات", "Checking for updates...": "جارٍ التحقق من التحديثات...", "Choose a model before saving...": "اختر نموذجًا قبل الحفظ...", + "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.": "", "Ciphers": "التشفيرات", "Citation": "اقتباس", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "تنفيذ الشيفرة", - "Code Execution": "تنفيذ الشيفرة", "Code Execution Engine": "محرك تنفيذ الشيفرة", "Code Execution Timeout": "مهلة تنفيذ الشيفرة", "Code formatted successfully": "تم تنسيق الشيفرة بنجاح", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "اتصل بالمسؤول للوصول إلى واجهة الويب", "Content": "المحتوى", "Content Extraction Engine": "محرك استخراج المحتوى", + "Content lengths (character counts only)": "", "Continue Response": "متابعة الرد", "Continue with {{provider}}": "متابعة مع {{provider}}", "Continue with Email": "متابعة باستخدام البريد الإلكتروني", @@ -393,6 +401,7 @@ "Database": "قاعدة البيانات", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "ديسمبر", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "التوثيق", - "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.": "لا تجلب خطوط أنابيب عشوائية من مصادر غير موثوقة.", @@ -493,11 +502,14 @@ "Done": "تم", "Download": "تحميل", "Download & Delete": "تنزيل وحذف", + "Download as JSON": "", "Download as SVG": "تنزيل بصيغة SVG", "Download canceled": "تم اللغاء التحميل", "Download Database": "تحميل قاعدة البيانات", + "Downloading stats...": "", "Draw": "ارسم", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "e.g. '30s','10m'. الوحدات الزمنية الصالحة هي 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "مثال: 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "أدخل مفتاح API لـ Bocha Search", "Enter Brave Search API Key": "أدخل مفتاح واجهة برمجة تطبيقات البحث الشجاع", "Enter certificate path": "أدخل مسار الشهادة", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "أدخل الChunk Overlap", "Enter Chunk Size": "أدخل Chunk الحجم", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "أدخل أزواج \"الرمز:قيمة التحيز\" مفصولة بفواصل (مثال: 5432:100، 413:-100)", @@ -595,6 +608,7 @@ "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 Github Raw URL": "أدخل عنوان URL ل Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "(e.g. 512x512) أدخل حجم الصورة ", + "Enter Jina API Base URL": "", "Enter Jina API Key": "أدخل مفتاح API لـ Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "أدخل كلمة مرور Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "أدخل مفتاح API لـ Kagi Search", "Enter Key Behavior": "أدخل سلوك المفتاح", "Enter language codes": "أدخل كود اللغة", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "أدخل معرف النموذج", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "الميزات", "Features Permissions": "أذونات الميزات", "February": "فبراير", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "سجل الملاحظات", - "Feedbacks": "الملاحظات", "Feel free to add specific details": "لا تتردد في إضافة تفاصيل محددة", "Female": "", "File": "ملف", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "تم اكتشاف انتحال بصمة الإصبع: غير قادر على استخدام الأحرف الأولى كصورة رمزية. الافتراضي لصورة الملف الشخصي الافتراضية.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "تم حذف المجلد بنجاح", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "لا يمكن أن يكون اسم المجلد فارغًا.", "Folder name updated successfully": "تم تحديث اسم المجلد بنجاح", @@ -826,7 +846,6 @@ "General": "عام", "Generate": "", "Generate an image": "توليد صورة", - "Generate Image": "توليد صورة", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "إنشاء استعلام بحث", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "ابدأ باستخدام {{WEBUI_NAME}}", "Global": "عام", "Good Response": "استجابة جيدة", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "مفتاح واجهة برمجة تطبيقات PSE من Google", "Google PSE Engine Id": "معرف محرك PSE من Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "مجموعة", "Group Channel": "", "Group created successfully": "تم إنشاء المجموعة بنجاح", @@ -895,7 +916,6 @@ "Image Prompt Generation": "توليد التوجيه للصورة", "Image Prompt Generation Prompt": "نص توجيه توليد الصورة", "Image Size": "", - "Images": "الصور", "Import": "", "Import Chats": "استيراد الدردشات", "Import Config from JSON File": "استيراد الإعدادات من ملف JSON", @@ -927,6 +947,7 @@ "Integration": "التكامل", "Integrations": "", "Interface": "واجهه المستخدم", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "تنسيق ملف غير صالح.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "يكتب...", "Italic": "", "January": "يناير", + "Jina API Base URL": "", "Jina API Key": "مفتاح API لـ Jina", "join our Discord for help.": "انضم إلى Discord للحصول على المساعدة.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "اتركه فارغًا لتضمين جميع النماذج أو اختر نماذج محددة", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "اتركه فارغًا لاستخدام التوجيه الافتراضي، أو أدخل توجيهًا مخصصًا", "Leave model field empty to use the default model.": "اترك حقل النموذج فارغًا لاستخدام النموذج الافتراضي.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "مارس", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "الحد الأقصى لعدد التحميلات", "Max Upload Size": "الحد الأقصى لحجم الملف المرفوع", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "يمكن تنزيل 3 نماذج كحد أقصى في وقت واحد. الرجاء معاودة المحاولة في وقت لاحق.", "May": "مايو", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "سيتم عرض الذكريات التي يمكن الوصول إليها بواسطة LLMs هنا.", "Memory": "الذاكرة", "Memory added successfully": "تم إضافة الذاكرة بنجاح", @@ -1051,6 +1077,7 @@ "Merge Responses": "دمج الردود", "Merged Response": "نتيجة الردود المدمجة", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "يجب تفعيل تقييم الرسائل لاستخدام هذه الميزة", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "اسم النموذج", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "لم تختار موديل", "Model Params": "معلمات النموذج", "Model Permissions": "أذونات النموذج", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "تم تحديث النموذج بنجاح", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "مفتاح API لـ Mojeek Search", "More": "المزيد", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "لا توجد مسافة متاحة", "No expiration can pose security risks.": "", - "No feedbacks found": "لم يتم العثور على ملاحظات", + "No feedback found": "", "No file selected": "لم يتم تحديد ملف", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "لم يتم اختيار نماذج", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "لا توجد نتائج", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "يمكن الوصول فقط من قبل المستخدمين والمجموعات المصرح لهم", + "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.": "عذرًا! حدث خطأ في الرد السابق.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "تستخدم واجهة WebUI أداة faster-whisper داخليًا.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "تستخدم WebUI نموذج SpeechT5 وتضمينات صوتية من CMU Arctic.", + "Open WebUI version": "", "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", @@ -1235,6 +1268,8 @@ "page": "صفحة", "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.": "", "Password": "الباسورد", "Passwords do not match.": "", "Paste Large Text as File": "الصق نصًا كبيرًا كملف", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "تم حذف خط المعالجة بنجاح", "Pipeline downloaded successfully": "تم تنزيل خط المعالجة بنجاح", - "Pipelines": "خطوط الانابيب", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines عبارة عن نظام إضافات يتيح تنفيذًا عشوائيًا للتعليمات البرمجية —", "Pipelines Not Detected": "لم يتم الكشف عن خطوط المعالجة", "Pipelines Valves": "صمامات خطوط الأنابيب", @@ -1502,6 +1536,7 @@ "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.": "يحدد تسلسلات الإيقاف. عند مواجهتها، سيتوقف النموذج عن التوليد ويُرجع النتيجة. يمكن تحديد أنماط توقف متعددة داخل ملف النموذج.", "Setting": "", "Settings": "الاعدادات", + "Settings Permissions": "", "Settings saved successfully!": "تم حفظ الاعدادات بنجاح", "Share": "كشاركة", "Share Chat": "مشاركة الدردشة", @@ -1545,6 +1580,7 @@ "Speech recognition error: {{error}}": "{{error}} خطأ في التعرف على الكلام", "Speech-to-Text": "", "Speech-to-Text Engine": "محرك تحويل الكلام إلى نص", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "بداية القناة", "Start Tag": "", @@ -1555,6 +1591,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "إيقاف", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "وقف التسلسل", "Stream Chat Response": "بث استجابة الدردشة", @@ -1575,7 +1612,14 @@ "Support": "الدعم", "Support this plugin:": "دعم هذا المكون الإضافي:", "Supported MIME Types": "", + "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.": "", "System": "النظام", "System Instructions": "تعليمات النظام", "System Prompt": "محادثة النظام", @@ -1620,6 +1664,7 @@ "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.": "", "Theme": "الثيم", + "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.": "", @@ -1734,6 +1779,7 @@ "Upload Pipeline": "رفع خط المعالجة", "Upload Progress": "جاري التحميل", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "الرابط", "URL is required": "", @@ -1751,6 +1797,7 @@ "User Groups": "", "User location successfully retrieved.": "تم استرجاع موقع المستخدم بنجاح.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "اسم المستخدم", "users": "", @@ -1800,15 +1847,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "ستقوم WebUI بإرسال الطلبات إلى \"{{url}}/chat/completions\"", "What are you trying to achieve?": "ما الذي تحاول تحقيقه؟", "What are you working on?": "على ماذا تعمل؟", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "ما هو الجديد", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (محلي)", + "Who can share to this group": "", "Why?": "لماذا؟", "Widescreen Mode": "وضع الشاشة العريضة", "Width": "", + "Wikipedia": "", "Won": "فاز", "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": "مساحة العمل", @@ -1820,6 +1871,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "أمس", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "انت", @@ -1827,6 +1880,9 @@ "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.": "يمكنك تخصيص تفاعلك مع النماذج اللغوية عن طريق إضافة الذكريات باستخدام زر \"إدارة\" أدناه، مما يجعلها أكثر فائدة وتناسبًا لك.", "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 save this prompt.": "", "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.": "", @@ -1838,6 +1894,8 @@ "Your Account": "", "Your account status is currently pending activation.": "حالة حسابك حالياً بانتظار التفعيل.", "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.": "", "YouTube": "Youtube", "Youtube Language": "لغة YouTube", "Youtube Proxy URL": "رابط بروكسي YouTube" diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index d3e35a62e3..af3acfd83c 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "При промяна на тези настройки промените се прилагат за всички потребители.", "admin": "админ", "Admin": "Администратор", + "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.": "Администраторите имат достъп до всички инструменти по всяко време; потребителите се нуждаят от инструменти, присвоени за всеки модел в работното пространство.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Разреши качване на файлове", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Разреши нелокални гласове", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "и още {{COUNT}}", "and create a new shared link.": "и създай нов общ линк.", "Android": "", + "Anyone": "", "API Base URL": "API Базов URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API Ключ", @@ -175,6 +176,7 @@ "Authenticate": "Удостоверяване", "Authentication": "Автентикация", "Auto": "Авто", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Автоматично копиране на отговор в клипборда", "Auto-playback response": "Автоматично възпроизвеждане на отговора", "Autocomplete Generation": "Генериране на автоматично довършване", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth низ", "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.)": "", "Available list": "Наличен списък", "Available Tools": "Налични инструменти", "available users": "Налични потребители", @@ -201,6 +204,7 @@ "before": "преди", "Being lazy": "Мързелив е", "Beta": "Бета", + "Bing": "", "Bing Search V7 Endpoint": "Крайна точка за Bing Search V7", "Bing Search V7 Subscription Key": "Абонаментен ключ за Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "API ключ за Bocha Search", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "API ключ за Brave Search", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Проверка за актуализации", "Checking for updates...": "Проверка за актуализации...", "Choose a model before saving...": "Изберете модел преди запазване...", + "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.": "", "Ciphers": "Шифри", "Citation": "Цитат", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Изпълнение на код", - "Code Execution": "Изпълнение на код", "Code Execution Engine": "Двигател за изпълнение на кода", "Code Execution Timeout": "", "Code formatted successfully": "Кодът е форматиран успешно", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Свържете се с администратор за достъп до WebUI", "Content": "Съдържание", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Продължи отговора", "Continue with {{provider}}": "Продължете с {{provider}}", "Continue with Email": "Продължете с имейл", @@ -393,6 +401,7 @@ "Database": "База данни", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Декември", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Документация", - "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.": "Не извличайте произволни pipelines от източници, на които не вярвате.", @@ -493,11 +502,14 @@ "Done": "Готово", "Download": "Изтегляне", "Download & Delete": "Изтегляне и изтриване", + "Download as JSON": "", "Download as SVG": "Изтегляне като SVG", "Download canceled": "Изтегляне отменено", "Download Database": "Сваляне на база данни", + "Downloading stats...": "", "Draw": "Рисуване", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "напр. '30с','10м'. Валидни единици са 'с', 'м', 'ч'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Въведете API ключ за Bocha Search", "Enter Brave Search API Key": "Въведете API ключ за Brave Search", "Enter certificate path": "Въведете път до сертификата", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Въведете припокриване на чънкове", "Enter Chunk Size": "Въведете размер на чънк", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Въведете URL адрес на Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Въведете размер на изображението (напр. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Въведете API ключ за Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Въведете парола за Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Въведете API ключ за Kagi Search", "Enter Key Behavior": "", "Enter language codes": "Въведете кодове на езика", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Въведете ID на модела", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Функции", "Features Permissions": "Разрешения за функции", "February": "Февруари", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "История на обратната връзка", - "Feedbacks": "Обратни връзки", "Feel free to add specific details": "Не се колебайте да добавите конкретни детайли", "Female": "", "File": "Файл", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Потвърждаване на отпечатък: Не може да се използва инициализационна буква като аватар. Потребителят се връща към стандартна аватарка.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Папката е изтрита успешно", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Името на папката не може да бъде празно.", "Folder name updated successfully": "Името на папката е актуализирано успешно", @@ -826,7 +846,6 @@ "General": "Основни", "Generate": "", "Generate an image": "Генериране на изображение", - "Generate Image": "Генериране на изображение", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Генериране на заявка за търсене", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Започнете с {{WEBUI_NAME}}", "Global": "Глобално", "Good Response": "Добър отговор", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API ключ", "Google PSE Engine Id": "Идентификатор на двигателя на Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Група", "Group Channel": "", "Group created successfully": "Групата е създадена успешно", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Генериране на промпт за изображения", "Image Prompt Generation Prompt": "Промпт за генериране на промпт за изображения", "Image Size": "", - "Images": "Изображения", "Import": "", "Import Chats": "Импортване на чатове", "Import Config from JSON File": "Импортиране на конфигурация от JSON файл", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Интерфейс", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Невалиден формат на файла.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "пише...", "Italic": "", "January": "Януари", + "Jina API Base URL": "", "Jina API Key": "API ключ за Jina", "join our Discord for help.": "свържете се с нашия Discord за помощ.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "Оставете празно, за да включите всички модели или изберете конкретни модели", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Оставете празно, за да използвате промпта по подразбиране, или въведете персонализиран промпт", "Leave model field empty to use the default model.": "Оставете полето за модел празно, за да използвате модела по подразбиране.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Март", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Максимален брой качвания", "Max Upload Size": "Максимален размер на качване", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 модела могат да бъдат сваляни едновременно. Моля, опитайте отново по-късно.", "May": "Май", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Мемории достъпни от LLMs ще бъдат показани тук.", "Memory": "Памет", "Memory added successfully": "Паметта е добавена успешно", @@ -1051,6 +1077,7 @@ "Merge Responses": "Обединяване на отговори", "Merged Response": "Обединен отговор", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Оценяването на съобщения трябва да бъде активирано, за да използвате тази функция", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "Име на модел", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Не е избран модел", "Model Params": "Параметри на модела", "Model Permissions": "Разрешения на модела", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Моделът е актуализиран успешно", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Споделяне на моделите публично", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "API ключ за Mojeek Search", "More": "Повече", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Няма налично разстояние", "No expiration can pose security risks.": "", - "No feedbacks found": "Не са намерени обратни връзки", + "No feedback found": "", "No file selected": "Не е избран файл", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Няма избрани модели", "No Notes": "Няма бележки", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Няма намерени резултати", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Само избрани потребители и групи с разрешение могат да имат достъп", + "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.": "Упс! Имаше грешка в предишния отговор.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI използва вътрешно по-бързо-whisper.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI използва SpeechT5 и CMU Arctic говорителни вграждания.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Версията на Open WebUI (v{{OPEN_WEBUI_VERSION}}) е по-ниска от необходимата версия (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API на OpenAI", @@ -1235,6 +1268,8 @@ "page": "страница", "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.": "", "Password": "Парола", "Passwords do not match.": "", "Paste Large Text as File": "Поставете голям текст като файл", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Пайплайнът е изтрит успешно", "Pipeline downloaded successfully": "Пайплайнът е изтеглен успешно", - "Pipelines": "Пайплайни", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines е система от приставки с възможност за произволно изпълнение на код —", "Pipelines Not Detected": "Не са открити пайплайни", "Pipelines Valves": "Клапани на пайплайни", @@ -1498,6 +1532,7 @@ "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 saved successfully!": "Настройките са запазени успешно!", "Share": "Подели", "Share Chat": "Подели Чат", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Грешка при разпознаване на речта: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Двигател за преобразуване на реч в текста", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Начало на канала", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Спри", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Стоп последователност", "Stream Chat Response": "Поточен чат отговор", @@ -1571,7 +1608,14 @@ "Support": "Поддръжка", "Support this plugin:": "Подкрепете този плъгин:", "Supported MIME Types": "", + "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.": "", "System": "Система", "System Instructions": "Системни инструкции", "System Prompt": "Системен Промпт", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Тема", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Качване на конвейер", "Upload Progress": "Прогрес на качването", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Местоположението на потребителя е успешно извлечено.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Потребителско име", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ще прави заявки към \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Какво се опитвате да постигнете?", "What are you working on?": "Върху какво работите?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Какво е ново в", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (Локално)", + "Who can share to this group": "", "Why?": "Защо?", "Widescreen Mode": "Широкоекранен режим", "Width": "", + "Wikipedia": "", "Won": "Спечелено", "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.": "", "Workspace": "Работно пространство", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "вчера", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Вие", @@ -1823,6 +1876,9 @@ "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Статусът на вашия акаунт в момента очаква активиране.", "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.": "", "YouTube": "Youtube", "Youtube Language": "Youtube език", "Youtube Proxy URL": "Youtube Прокси URL" diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index 021413a54b..6f1d41d392 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "এই সেটিংগুলো পরিবর্তন করলে তা সব ইউজারের উপরেই প্রয়োগ করা হবে", "admin": "এডমিন", "Admin": "", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "এবং একটি নতুন শেয়ারে লিংক তৈরি করুন.", "Android": "", + "Anyone": "", "API Base URL": "এপিআই বেজ ইউআরএল", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "এপিআই কোড", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "রেসপন্সগুলো স্বয়ংক্রিভাবে ক্লিপবোর্ডে কপি হবে", "Auto-playback response": "রেসপন্স অটো-প্লেব্যাক", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 বেজ ইউআরএল", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 বেজ ইউআরএল আবশ্যক", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "উপলব্ধ ব্যবহারকারী", @@ -201,6 +204,7 @@ "before": "পূর্ববর্তী", "Being lazy": "অলস হওয়া", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "সাহসী অনুসন্ধান API কী", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "নতুন আপডেট আছে কিনা চেক করুন", "Checking for updates...": "নতুন আপডেট আছে কিনা চেক করা হচ্ছে...", "Choose a model before saving...": "সেভ করার আগে একটি মডেল নির্বাচন করুন", + "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.": "", "Ciphers": "", "Citation": "উদ্ধৃতি", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "বিষয়বস্তু", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "যাচাই করুন", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "ডেটাবেজ", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "ডেসেম্বর", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "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.": "যে উৎসে আপনি ভরসা করেন না সেখান থেকে এলোমেলো পাইপলাইন আনবেন না।", @@ -493,11 +502,14 @@ "Done": "", "Download": "ডাউনলোড", "Download & Delete": "ডাউনলোড ও মুছে ফেলুন", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "ডাউনলোড বাতিল করা হয়েছে", "Download Database": "ডেটাবেজ ডাউনলোড করুন", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "যেমন '30s','10m'. সময়ের অনুমোদিত অনুমোদিত এককগুলি হচ্ছে 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "সাহসী অনুসন্ধান API কী লিখুন", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "চাঙ্ক ওভারল্যাপ লিখুন", "Enter Chunk Size": "চাংক সাইজ লিখুন", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "গিটহাব কাঁচা URL লিখুন", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "ছবির মাপ লিখুন (যেমন 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "ল্যাঙ্গুয়েজ কোড লিখুন", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "ফেব্রুয়ারি", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "নির্দিষ্ট বিবরণ যোগ করতে বিনা দ্বিধায়", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "ফিঙ্গারপ্রিন্ট স্পুফিং ধরা পড়েছে: অ্যাভাটার হিসেবে নামের আদ্যক্ষর ব্যবহার করা যাচ্ছে না। ডিফল্ট প্রোফাইল পিকচারে ফিরিয়ে নেয়া হচ্ছে।", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "সাধারণ", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "অনুসন্ধান ক্যোয়ারী তৈরি করা হচ্ছে", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "ভালো সাড়া", + "Google": "", "Google Drive": "", "Google PSE API Key": "গুগল পিএসই এপিআই কী", "Google PSE Engine Id": "গুগল পিএসই ইঞ্জিন আইডি", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "গ্রুপ", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "ছবিসমূহ", "Import": "", "Import Chats": "চ্যাটগুলি ইমপোর্ট করুন", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "ইন্টারফেস", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "জানুয়ারী", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "সাহায্যের জন্য আমাদের Discord-এ যুক্ত হোন", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "মার্চ", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "একসঙ্গে সর্বোচ্চ তিনটি মডেল ডাউনলোড করা যায়। দয়া করে পরে আবার চেষ্টা করুন।", "May": "মে", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLMs দ্বারা অ্যাক্সেসযোগ্য মেমোরিগুলি এখানে দেখানো হবে।", "Memory": "মেমোরি", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "একত্রিত প্রতিক্রিয়া ফলাফল", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "আপনার লিঙ্ক তৈরি করার পরে আপনার পাঠানো বার্তাগুলি শেয়ার করা হবে না। ইউআরএল ব্যবহারকারীরা শেয়ার করা চ্যাট দেখতে পারবেন।", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "মডেল নির্বাচন করা হয়নি", "Model Params": "মডেল প্যারাম", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "আরো", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "কোন ফলাফল পাওয়া যায়নি", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "ওহ, মনে হচ্ছে ইউআরএলটা ইনভ্যালিড। দয়া করে আর চেক করে চেষ্টা করুন।", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "OpenAI এপিআই", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "পাসওয়ার্ড", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "পাইপলাইন", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines হলো একটি প্লাগইন সিস্টেম, যেখানে যেকোনো কোড চালানো যেতে পারে —", "Pipelines Not Detected": "", "Pipelines Valves": "পাইপলাইন ভালভ", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "সেটিংসমূহ", + "Settings Permissions": "", "Settings saved successfully!": "সেটিংগুলো সফলভাবে সংরক্ষিত হয়েছে", "Share": "শেয়ার করুন", "Share Chat": "চ্যাট শেয়ার করুন", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "স্পিচ রিকগনিশনে সমস্যা: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "স্পিচ-টু-টেক্সট ইঞ্জিন", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "চ্যানেলের শুরু", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "সিকোয়েন্স থামান", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "সিস্টেম", "System Instructions": "", "System Prompt": "সিস্টেম প্রম্পট", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "থিম", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "আপলোড হচ্ছে", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "এতে নতুন কী", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "ওয়ার্কস্পেস", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "আগামী", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "আপনি", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/bo-TB/translation.json b/src/lib/i18n/locales/bo-TB/translation.json index d72b463383..207c4c70c2 100644 --- a/src/lib/i18n/locales/bo-TB/translation.json +++ b/src/lib/i18n/locales/bo-TB/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "སྒྲིག་འགོད་འདི་དག་ལེགས་སྒྲིག་བྱས་ན་བེད་སྤྱོད་མཁན་ཡོངས་ལ་འགྱུར་བ་དེ་བཀོལ་སྤྱོད་བྱེད་ངེས།", "admin": "དོ་དམ་པ།", "Admin": "དོ་དམ་པ།", + "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.": "དོ་དམ་པས་དུས་རྟག་ཏུ་ལག་ཆ་ཡོངས་ལ་འཛུལ་སྤྱོད་བྱེད་ཆོག བེད་སྤྱོད་མཁན་གྱིས་ལས་ཡུལ་ནང་དཔེ་དབྱིབས་རེ་རེར་བཀོད་པའི་ལག་ཆ་དགོས་མཁོ་ཡོད།", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "ཡིག་ཆ་སྤར་བར་གནང་བ་སྤྲོད་པ།", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "ས་གནས་མིན་པའི་སྐད་གདངས་ལ་གནང་བ་སྤྲོད་པ།", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "ད་དུང་ {{COUNT}}", "and create a new shared link.": "དང་མཉམ་སྤྱོད་སྦྲེལ་ཐག་གསར་པ་ཞིག་བཟོ་བ།", "Android": "", + "Anyone": "", "API Base URL": "API གཞི་རྩའི་ URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API ལྡེ་མིག", @@ -175,6 +176,7 @@ "Authenticate": "དངོས་ར་སྤྲོད་པ།", "Authentication": "དངོས་ར་སྤྲོད་པ།", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "ལན་རང་འགུལ་གྱིས་སྦྱར་སྡེར་དུ་འདྲ་བཤུས་བྱེད་པ།", "Auto-playback response": "ལན་རང་འགུལ་གྱིས་གཏོང་བ།", "Autocomplete Generation": "རང་འཚང་བཟོ་སྐྲུན།", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth ཡིག་ཕྲེང་།", "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.)": "", "Available list": "ཡོད་པའི་ཐོ་གཞུང་།", "Available Tools": "", "available users": "ཡོད་པའི་སྤྱོད་མཁན", @@ -201,6 +204,7 @@ "before": "སྔོན།", "Being lazy": "ལེ་ལོ་བྱེད་པ།", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 མཇུག་མཐུད།", "Bing Search V7 Subscription Key": "Bing Search V7 མངགས་ཉོ་ལྡེ་མིག", "Bio": "", @@ -209,7 +213,9 @@ "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 Search API Key": "Brave Search API ལྡེ་མིག", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "གསར་སྒྱུར་འཚོལ་ཞིབ།", "Checking for updates...": "གསར་སྒྱུར་འཚོལ་བཞིན་པ།...", "Choose a model before saving...": "ཉར་ཚགས་མ་བྱས་སྔོན་དུ་དཔེ་དབྱིབས་ཤིག་གདམ་པ།...", + "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.": "", "Ciphers": "གསང་སྦྱོར།", "Citation": "ལུང་འདྲེན།", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "ཀོཌ་ལག་བསྟར།", - "Code Execution": "ཀོཌ་ལག་བསྟར།", "Code Execution Engine": "ཀོཌ་ལག་བསྟར་འཕྲུལ་འཁོར།", "Code Execution Timeout": "ཀོཌ་ལག་བསྟར་དུས་ཚོད་བཀག་པ།", "Code formatted successfully": "ཀོཌ་བཀོད་པ་ལེགས་པར་བཟོས་ཟིན།", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "WebUI འཛུལ་སྤྱོད་ཆེད་དུ་དོ་དམ་པ་དང་འབྲེལ་གཏུག་བྱེད་པ།", "Content": "ནང་དོན།", "Content Extraction Engine": "ནང་དོན་འདོན་སྤེལ་འཕྲུལ་འཁོར།", + "Content lengths (character counts only)": "", "Continue Response": "ལན་མུ་མཐུད་པ།", "Continue with {{provider}}": "{{provider}} དང་མཉམ་དུ་མུ་མཐུད་པ།", "Continue with Email": "ཡིག་ཟམ་དང་མཉམ་དུ་མུ་མཐུད་པ།", @@ -393,6 +401,7 @@ "Database": "གནས་ཚུལ་མཛོད།", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "ཟླ་བ་བཅུ་གཉིས་པ།", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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", "Docling Parameters": "", "Docling Server URL required.": "Docling སར་བར་གྱི་ URL དགོས་ངེས།", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "ཡིག་ཆ།", - "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.": "རྟོགས་མེད་པའི་ཁུངས་ནས་ pipelines གང་འརྒྱུར་མ་འབྱོར་", @@ -493,11 +502,14 @@ "Done": "ཚར་སོང་།", "Download": "ཕབ་ལེན།", "Download & Delete": "ཕབ་ལེན་དང་བསུབ་", + "Download as JSON": "", "Download as SVG": "SVG ཐོག་ཕབ་ལེན།", "Download canceled": "ཕབ་ལེན་རྩིས་མེད་བཏང་།", "Download Database": "གནས་ཚུལ་མཛོད་ཕབ་ལེན།", + "Downloading stats...": "", "Draw": "རི་མོ་འབྲི་བ།", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "དཔེར་ན། '30s','10m'. ནུས་ལྡན་དུས་ཚོད་ཀྱི་ཚན་པ་ནི། 's', 'm', 'h' ཡིན།", "e.g. \"json\" or a JSON schema": "དཔེར་ན། \"json\" ཡང་ན་ JSON གི་ schema", "e.g. 60": "དཔེར་ན། ༦༠", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Bocha Search API ལྡེ་མིག་འཇུག་པ།", "Enter Brave Search API Key": "Brave Search API ལྡེ་མིག་འཇུག་པ།", "Enter certificate path": "ལག་ཁྱེར་གྱི་ལམ་བུ་འཇུག་པ།", + "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)", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Github Raw URL འཇུག་པ།", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "པར་གྱི་ཆེ་ཆུང་འཇུག་པ། (དཔེར་ན། 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina API ལྡེ་མིག་འཇུག་པ།", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Jupyter གསང་གྲངས་འཇུག་པ།", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search API ལྡེ་མིག་འཇུག་པ།", "Enter Key Behavior": "ལྡེ་མིག་གི་བྱེད་སྟངས་འཇུག་པ།", "Enter language codes": "སྐད་ཡིག་གི་ཨང་རྟགས་འཇུག་པ།", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "དཔེ་དབྱིབས་ཀྱི་ ID འཇུག་པ།", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "ཁྱད་ཆོས།", "Features Permissions": "ཁྱད་ཆོས་ཀྱི་དབང་ཚད།", "February": "ཟླ་བ་གཉིས་པ།", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "བསམ་འཆར་གྱི་ལོ་རྒྱུས།", - "Feedbacks": "བསམ་འཆར།", "Feel free to add specific details": "ཞིབ་ཕྲ་ངེས་ཅན་སྣོན་པར་སེམས་ཁྲལ་མེད།", "Female": "", "File": "ཡིག་ཆ།", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "མཛུབ་ཐེལ་རྫུན་བཟོ་རྙེད་སོང་།: མིང་གི་ཡིག་འབྲུ་མགོ་མ་སྐུ་ཚབ་ཏུ་བེད་སྤྱོད་གཏོང་མི་ཐུབ། སྔོན་སྒྲིག་ཕྱི་ཐག་པར་རིས་ལ་སྔོན་སྒྲིག་བྱེད་བཞིན་པ།", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "ཡིག་སྣོད་ལེགས་པར་བསུབས་ཟིན།", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "ཡིག་སྣོད་ཀྱི་མིང་སྟོང་པ་ཡིན་མི་ཆོག", "Folder name updated successfully": "ཡིག་སྣོད་ཀྱི་མིང་ལེགས་པར་གསར་སྒྱུར་བྱས་ཟིན།", @@ -826,7 +846,6 @@ "General": "སྤྱིར་བཏང་།", "Generate": "", "Generate an image": "པར་ཞིག་བཟོ་བ།", - "Generate Image": "པར་བཟོ་བ།", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "འཚོལ་བཤེར་འདྲི་བ་བཟོ་བཞིན་པ།", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}} དང་མཉམ་དུ་འགོ་འཛུགས་པ།", "Global": "འཛམ་གླིང་ཡོངས་ཀྱི་", "Good Response": "ལན་ཡག་པོ།", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API ལྡེ་མིག", "Google PSE Engine Id": "Google PSE Engine Id", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "ཚོགས་པ།", "Group Channel": "", "Group created successfully": "ཚོགས་པ་ལེགས་པར་བཟོས་ཟིན།", @@ -895,7 +916,6 @@ "Image Prompt Generation": "པར་འགུལ་སློང་བཟོ་སྐྲུན།", "Image Prompt Generation Prompt": "པར་འགུལ་སློང་བཟོ་སྐྲུན་གྱི་འགུལ་སློང་།", "Image Size": "", - "Images": "པར།", "Import": "", "Import Chats": "ཁ་བརྡ་ནང་འདྲེན།", "Import Config from JSON File": "JSON ཡིག་ཆ་ནས་སྒྲིག་འགོད་ནང་འདྲེན།", @@ -927,6 +947,7 @@ "Integration": "མཉམ་འདྲེས།", "Integrations": "", "Interface": "ངོས་འཛིན།", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "ཡིག་ཆའི་བཀོད་པ་ནུས་མེད།", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "ཡིག་འབྲུ་རྒྱག་བཞིན་པ།...", "Italic": "", "January": "ཟླ་བ་དང་པོ།", + "Jina API Base URL": "", "Jina API Key": "Jina API ལྡེ་མིག", "join our Discord for help.": "རོགས་རམ་ཆེད་དུ་ང་ཚོའི་ Discord ལ་མཉམ་ཞུགས་བྱེད་པ།", "JSON": "JSON", @@ -990,6 +1012,7 @@ "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 model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "སྔོན་སྒྲིག་འགུལ་སློང་བེད་སྤྱོད་གཏོང་བར་སྟོང་པ་བཞག་པའམ། ཡང་ན་སྲོལ་བཟོས་འགུལ་སློང་འཇུག་པ།", "Leave model field empty to use the default model.": "སྔོན་སྒྲིག་དཔེ་དབྱིབས་བེད་སྤྱོད་གཏོང་བར་དཔེ་དབྱིབས་ཀྱི་ཁོངས་སྟོང་པ་བཞག་པ།", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "ཟླ་བ་གསུམ་པ།", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "སྤར་བའི་གྲངས་མང་ཤོས།", "Max Upload Size": "སྤར་བའི་ཆེ་ཆུང་མང་ཤོས།", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "དཔེ་དབྱིབས་ ༣ ལས་མང་བ་མཉམ་དུ་ཕབ་ལེན་བྱེད་མི་ཐུབ། རྗེས་སུ་ཡང་བསྐྱར་ཚོད་ལྟ་བྱེད་རོགས།", "May": "ཟླ་བ་ལྔ་པ།", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLMs ཀྱིས་འཛུལ་སྤྱོད་ཐུབ་པའི་དྲན་ཤེས་དག་འདིར་སྟོན་ངེས།", "Memory": "དྲན་ཤེས།", "Memory added successfully": "དྲན་ཤེས་ལེགས་པར་བསྣན་ཟིན།", @@ -1051,6 +1077,7 @@ "Merge Responses": "ལན་ཟླ་སྒྲིལ།", "Merged Response": "བསྡུར་མཐུན་གྱི་ལན་གསལ་གནས་ཡོད།", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "ཁྱད་ཆོས་འདི་བེད་སྤྱོད་གཏོང་བར་འཕྲིན་ལ་སྐར་མ་སྤྲོད་པ་སྒུལ་བསྐྱོད་བྱེད་དགོས།", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "དཔེ་དབྱིབས་ཀྱི་མིང་།", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "དཔེ་དབྱིབས་གདམ་ག་མ་བྱས།", "Model Params": "དཔེ་དབྱིབས་ཀྱི་ཞུགས་གྲངས།", "Model Permissions": "དཔེ་དབྱིབས་ཀྱི་དབང་ཚད།", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "དཔེ་དབྱིབས་ལེགས་པར་གསར་སྒྱུར་བྱས།", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "དཔེ་དབྱིབས་སྤྱི་སྤྱོད་མཉམ་སྤྱོད།", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API ལྡེ་མིག", "More": "མང་བ།", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "ཐག་རིང་ཚད་མེད།", "No expiration can pose security risks.": "", - "No feedbacks found": "བསམ་འཆར་མ་རྙེད།", + "No feedback found": "", "No file selected": "ཡིག་ཆ་གདམ་ག་མ་བྱས།", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "དཔེ་དབྱིབས་གདམ་ག་མ་བྱས།", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "འབྲས་བུ་མ་རྙེད།", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "དབང་ཚད་ཡོད་པའི་བེད་སྤྱོད་མཁན་དང་ཚོགས་པ་གདམ་ག་བྱས་པ་ཁོ་ན་འཛུལ་སྤྱོད་ཐུབ།", + "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.": "ཨོའོ། ལན་སྔ་མར་ནོར་འཁྲུལ་ཞིག་བྱུང་སོང་།", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI ཡིས་ནང་ཁུལ་དུ་ faster-whisper བེད་སྤྱོད་བྱེད།", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI ཡིས་ SpeechT5 དང་ CMU Arctic གཏམ་བཤད་པའི་ཚུད་འཇུག་བེད་སྤྱོད་བྱེད།", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI པར་གཞི། (v{{OPEN_WEBUI_VERSION}}) དེ་དགོས་ངེས་ཀྱི་པར་གཞི་ (v{{REQUIRED_VERSION}}) ལས་དམའ་བ།", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "ཤོག་ངོས།", "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.": "", "Password": "གསང་གྲངས།", "Passwords do not match.": "", "Paste Large Text as File": "ཡིག་རྐྱང་ཆེན་པོ་ཡིག་ཆ་ལྟར་སྦྱོར་བ།", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "རྒྱུ་ལམ་ལེགས་པར་བསུབས་ཟིན།", "Pipeline downloaded successfully": "རྒྱུ་ལམ་ལེགས་པར་ཕབ་ལེན་བྱས་ཟིན།", - "Pipelines": "རྒྱུ་ལམ།", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines ནི་ མ་སྦྱར་མའི་མ་ལག་རིམ་པའི་མུ་མཐུད་རྣམ་གྲངས་ཞིག་ཡིན་པས་ གསང་ཡིག་གང་རུང་ལག་བསྟར་བྱེད་ཐུབ —", "Pipelines Not Detected": "རྒྱུ་ལམ་མ་རྙེད།", "Pipelines Valves": "རྒྱུ་ལམ་གྱི་ Valve", @@ -1497,6 +1531,7 @@ "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 ཡིས་ཡིག་རྐྱང་བཟོ་བ་མཚམས་འཇོག་ནས་ཕྱིར་ལོག་བྱེད་ངེས། Modelfile ནང་མཚམས་འཇོག་ཞུགས་གྲངས་ལོགས་སུ་མང་པོ་གསལ་བཀོད་བྱས་ནས་མཚམས་འཇོག་བཟོ་ལྟ་མང་པོ་འཇོག་ཐུབ།", "Setting": "", "Settings": "སྒྲིག་འགོད།", + "Settings Permissions": "", "Settings saved successfully!": "སྒྲིག་འགོད་ལེགས་པར་ཉར་ཚགས་བྱས།", "Share": "མཉམ་སྤྱོད།", "Share Chat": "ཁ་བརྡ་མཉམ་སྤྱོད།", @@ -1540,6 +1575,7 @@ "Speech recognition error: {{error}}": "གཏམ་བཤད་ངོས་འཛིན་ནོར་འཁྲུལ།: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "གཏམ་བཤད་ནས་ཡིག་རྐྱང་གི་འཕྲུལ་འཁོར།", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "རྒྱས་ལམ་འགོ་རིམ་", "Start Tag": "", @@ -1550,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "མཚམས་འཇོག", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "མཚམས་འཇོག་རིམ་པ།", "Stream Chat Response": "ཁ་བརྡའི་ལན་རྒྱུག་པ།", @@ -1570,7 +1607,14 @@ "Support": "རྒྱབ་སྐྱོར།", "Support this plugin:": "plugin འདི་ལ་རྒྱབ་སྐྱོར་བྱེད་པ།:", "Supported MIME Types": "", + "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.": "", "System": "མ་ལག", "System Instructions": "མ་ལག་གི་ལམ་སྟོན།", "System Prompt": "མ་ལག་གི་འགུལ་སློང་།", @@ -1615,6 +1659,7 @@ "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.": "", "Theme": "བརྗོད་གཞི།", + "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}} བགྲོ་གླེང་གི་ཐོག་མ་རང་ཡིན།", @@ -1729,6 +1774,7 @@ "Upload Pipeline": "རྒྱུ་ལམ་སྤར་བ།", "Upload Progress": "སྤར་བའི་འཕེལ་རིམ།", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1746,6 +1792,7 @@ "User Groups": "", "User location successfully retrieved.": "བེད་སྤྱོད་མཁན་གནས་ཡུལ་ལེགས་པར་ལེན་ཚུར་སྒྲུབ་བྱས།", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "བེད་སྤྱོད་མཁན་གྱི་ Webhooks", "Username": "བེད་སྤྱོད་མིང་།", "users": "", @@ -1795,15 +1842,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ཡིས་ \"{{url}}/chat/completions\" ལ་རེ་ཞུ་གཏོང་ངེས།", "What are you trying to achieve?": "ཁྱེད་ཀྱིས་ཅི་ཞིག་འགྲུབ་ཐབས་བྱེད་བཞིན་ཡོད།", "What are you working on?": "ཁྱེད་ཀྱིས་ཅི་ཞིག་ལས་ཀ་བྱེད་བཞིན་ཡོད།", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "གསར་པ་ཅི་ཡོད།", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (ས་གནས།)", + "Who can share to this group": "", "Why?": "ཅིའི་ཕྱིར།", "Widescreen Mode": "ཡངས་གནས་ངོས་མ་དཔེ།", "Width": "", + "Wikipedia": "", "Won": "ཐོབ།", "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": "ལས་ཡུལ།", @@ -1815,6 +1866,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "ཁ་ས།", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "ཁྱེད།", @@ -1822,6 +1875,9 @@ "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.": "ཁྱེད་ཀྱིས་གཤམ་གྱི་ 'དོ་དམ་' མཐེབ་གནོན་བརྒྱུད་དྲན་ཤེས་སྣོན་ནས་ LLMs དང་མཉམ་དུ་འབྲེལ་འདྲིས་བྱེད་པ་སྒེར་སྤྱོད་ཅན་བཟོ་ཐུབ། དེ་དག་ཁྱེད་ལ་སྔར་ལས་ཕན་ཐོགས་པ་དང་འཚམ་པོ་བཟོ་ཐུབ།", "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 save this prompt.": "", "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.": "", @@ -1833,6 +1889,8 @@ "Your Account": "", "Your account status is currently pending activation.": "ཁྱེད་ཀྱི་རྩིས་ཁྲའི་གནས་སྟངས་ད་ལྟ་སྒུལ་བསྐྱོད་སྒུག་བཞིན་པ།", "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.": "ཁྱེད་ཀྱི་ཞལ་འདེབས་ཆ་ཚང་ཐད་ཀར་ plugin གསར་སྤེལ་བ་ལ་འགྲོ་ངེས། Open WebUI ཡིས་བརྒྱ་ཆ་གང་ཡང་མི་ལེན། འོན་ཀྱང་། གདམ་ཟིན་པའི་མ་དངུལ་གཏོང་བའི་སྟེགས་བུ་ལ་དེའི་རང་གི་འགྲོ་གྲོན་ཡོད་སྲིད།", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube སྐད་ཡིག", "Youtube Proxy URL": "Youtube Proxy URL" diff --git a/src/lib/i18n/locales/bs-BA/translation.json b/src/lib/i18n/locales/bs-BA/translation.json index 6c78ed522c..726890c181 100644 --- a/src/lib/i18n/locales/bs-BA/translation.json +++ b/src/lib/i18n/locales/bs-BA/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Podešavanje će se primijeniti univerzalno na sve korisnike.", "admin": "administrator", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Admin ploča", "Admin Settings": "Admin postavke", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Admini imaju pristup svim alatima u svako doba; korisninicima je dat pristup alatima u zavisnosti od modela u radnoj povrsini", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Dozvoli vise modela u jednom chatu", "Allow non-local voices": "Dopusti nelokalne glasove", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "i stvorite novu dijeljenu vezu.", "Android": "", + "Anyone": "", "API Base URL": "Osnovni URL API-ja", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API ključ", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatsko kopiranje odgovora u međuspremnik", "Auto-playback response": "Automatska reprodukcija odgovora", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 osnovni URL", "AUTOMATIC1111 Base URL is required.": "Potreban je AUTOMATIC1111 osnovni URL.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "dostupni korisnici", @@ -201,6 +204,7 @@ "before": "prije", "Being lazy": "Biti lijen", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave tražilica - API ključ", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Provjeri za ažuriranja", "Checking for updates...": "Provjeravam ažuriranja...", "Choose a model before saving...": "Odaberite model prije spremanja...", + "Chunk Min Size Target": "", "Chunk Overlap": "Preklapanje dijelova", "Chunk Size": "Veličina dijela", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Citiranje", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Kontaktirajte admina za WebUI pristup", "Content": "Sadržaj", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Nastavi odgovor", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Baza podataka", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Decembar", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentacija", - "Documents": "Dokumenti", "does not make any external connections, and your data stays securely on your locally hosted server.": "ne uspostavlja vanjske veze, a vaši podaci ostaju sigurno na vašem lokalno hostiranom poslužitelju.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Ne preuzimajte nasumične pipelines iz izvora kojima ne vjerujete.", @@ -493,11 +502,14 @@ "Done": "", "Download": "Preuzimanje", "Download & Delete": "Preuzmi i izbriši", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Preuzimanje otkazano", "Download Database": "Preuzmi bazu podataka", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "npr. '30s','10m'. Važeće vremenske jedinice su 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Unesite Brave Search API ključ", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Unesite preklapanje dijelova", "Enter Chunk Size": "Unesite veličinu dijela", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Unesite Github sirovi URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Unesite veličinu slike (npr. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Unesite kodove jezika", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Februar", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "Slobodno dodajte specifične detalje", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Otkriveno krivotvorenje otisaka prstiju: Nemoguće je koristiti inicijale kao avatar. Postavljanje na zadanu profilnu sliku.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Općenito", "Generate": "", "Generate an image": "", - "Generate Image": "Gneriraj sliku", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Generiranje upita za pretraživanje", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "Dobar odgovor", + "Google": "", "Google Drive": "", "Google PSE API Key": "Google PSE API ključ", "Google PSE Engine Id": "ID Google PSE modula", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grupa", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Slike", "Import": "", "Import Chats": "Uvoz razgovora", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Sučelje", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Januar", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "pridružite se našem Discordu za pomoć.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Mart", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksimalno 3 modela se mogu preuzeti istovremeno. Pokušajte ponovo kasnije.", "May": "Maj", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Ovdje će biti prikazana memorija kojoj mogu pristupiti LLM-ovi.", "Memory": "Memorija", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Spojeni odgovor", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Poruke koje pošaljete nakon stvaranja veze neće se dijeliti. Korisnici s URL-om moći će vidjeti zajednički chat.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model nije odabran", "Model Params": "Model parametri", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Više", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Nema rezultata", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Izgleda da je URL nevažeći. Molimo provjerite ponovno i pokušajte ponovo.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Lozinka", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "Cjevovodi", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines je sustav dodataka s proizvoljnim izvršavanjem koda —", "Pipelines Not Detected": "", "Pipelines Valves": "Ventili za cjevovode", @@ -1499,6 +1533,7 @@ "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.": "", "Setting": "", "Settings": "Postavke", + "Settings Permissions": "", "Settings saved successfully!": "Postavke su uspješno spremljene!", "Share": "Podijeli", "Share Chat": "Podijeli razgovor", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Pogreška prepoznavanja govora: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Stroj za prepoznavanje govora", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Početak kanala", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Zaustavi sekvencu", "Stream Chat Response": "", @@ -1572,7 +1609,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "Sustav", "System Instructions": "", "System Prompt": "Sistemski prompt", @@ -1617,6 +1661,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Razmišljam", "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.": "", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Prijenos kanala", "Upload Progress": "Napredak učitavanja", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Što je novo u", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (lokalno)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "Mod širokog zaslona", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "Radna ploča", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Jučer", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Vi", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Možete personalizirati svoje interakcije s LLM-ima dodavanjem uspomena putem gumba 'Upravljanje' u nastavku, čineći ih korisnijima i prilagođenijima vama.", "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 save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Status vašeg računa trenutno čeka aktivaciju.", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index 28bd2294c7..c96dee8c51 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Si ajustes aquesta preferència, els canvis s'aplicaran de manera universal a tots els usuaris.", "admin": "administrador", "Admin": "Administrador", + "Admin Contact Email": "", "Admin Panel": "Panell d'administració", "Admin Settings": "Preferències d'administració", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Els administradors tenen accés a totes les eines en tot moment; els usuaris necessiten eines assignades per model a l'espai de treball.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Permetre continuar la resposta", "Allow Delete Messages": "Permetre eliminar missatges", "Allow File Upload": "Permetre la pujada d'arxius", - "Allow Group Sharing": "Permetre compartir en grup", "Allow Multiple Models in Chat": "Permetre múltiple models al xat", "Allow non-local voices": "Permetre veus no locals", "Allow Rate Response": "Permetre valorar les respostes", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "i {{COUNT}} més", "and create a new shared link.": "i crear un nou enllaç compartit.", "Android": "Android", + "Anyone": "", "API Base URL": "URL Base de l'API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "URL base de l'API per al servei de marcadors de Datalab. Per defecte: https://www.datalab.to/api/v1/marker", "API Key": "clau API", @@ -175,6 +176,7 @@ "Authenticate": "Autenticar", "Authentication": "Autenticació", "Auto": "Automàtic", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Copiar la resposta automàticament al porta-retalls", "Auto-playback response": "Reproduir la resposta automàticament", "Autocomplete Generation": "Generació automàtica", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Cadena d'autenticació de l'API d'AUTOMATIC1111", "AUTOMATIC1111 Base URL": "URL Base d'AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Es requereix la URL Base d'AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Llista de disponibles", "Available Tools": "Eines disponibles", "available users": "usuaris disponibles", @@ -201,6 +204,7 @@ "before": "abans", "Being lazy": "Essent mandrós", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Punt de connexió a Bing Search V7", "Bing Search V7 Subscription Key": "Clau de subscripció a Bing Search V7", "Bio": "Bio", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Clau API de Bocha Search", "Bold": "Negreta", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Potenciar o penalitzar tokens específics per a respostes limitades. Els valors de biaix es fixaran entre -100 i 100 (inclosos). (Per defecte: cap)", + "Brave": "", "Brave Search API Key": "Clau API de Brave Search", + "Builtin Tools": "", "Bullet List": "Llista indexada", "Button ID": "ID del botó", "Button Label": "Etiqueta del botó", @@ -256,8 +262,10 @@ "Check for updates": "Comprovar si hi ha actualitzacions", "Checking for updates...": "Comprovant actualitzacions...", "Choose a model before saving...": "Triar un model abans de desar...", + "Chunk Min Size Target": "", "Chunk Overlap": "Solapament de blocs", "Chunk Size": "Mida del bloc", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Xifradors", "Citation": "Cita", "Citations": "Cites", @@ -293,7 +301,6 @@ "Code Block": "Bloc de codi", "Code Editor": "Editor de codi", "Code execution": "Execució de codi", - "Code Execution": "Execució de Codi", "Code Execution Engine": "Motor d'execució de codi", "Code Execution Timeout": "Temps màxim d'execució de codi", "Code formatted successfully": "Codi formatat correctament", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Posa't en contacte amb l'administrador per accedir a WebUI", "Content": "Contingut", "Content Extraction Engine": "Motor d'extracció de contingut", + "Content lengths (character counts only)": "", "Continue Response": "Continuar la resposta", "Continue with {{provider}}": "Continuar amb {{provider}}", "Continue with Email": "Continuar amb el correu", @@ -393,6 +401,7 @@ "Database": "Base de dades", "Datalab Marker API": "API de Datalab Marker", "DD/MM/YYYY": "DD/MM/YYYY", + "DDGS Backend": "", "December": "Desembre", "Decrease UI Scale": "Disminuir la mida de la interfície gràfica", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Aprofundir en el coneixement", "Do not install functions from sources you do not fully trust.": "No instal·lis funcions de fonts en què no confiïs plenament.", "Do not install tools from sources you do not fully trust.": "No instal·lis eines de fonts en què no confiïs plenament.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "Paràmetres de Docling", "Docling Server URL required.": "La URL del servidor Docling és necessària", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Es necessita un punt de connexió de Document Intelligence", "Document Intelligence Model": "Model de Document Intelligence", "Documentation": "Documentació", - "Documents": "Documents", "does not make any external connections, and your data stays securely on your locally hosted server.": "no realitza connexions externes, i les teves dades romanen segures al teu servidor allotjat localment.", "Domain Filter List": "Llista de filtre de dominis", "don't fetch random pipelines from sources you don't trust.": "No obtinguis pipelines aleatòries de fonts no fiables.", @@ -493,11 +502,14 @@ "Done": "Fet", "Download": "Descarregar", "Download & Delete": "Descarregar i suprimir", + "Download as JSON": "", "Download as SVG": "Descarrega com a SVG", "Download canceled": "Descàrrega cancel·lada", "Download Database": "Descarregar la base de dades", + "Downloading stats...": "", "Draw": "Dibuixar", "Drop any files here to upload": "Arrossega aquí qualsevol fitxer per pujar-lo", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "p. ex. '30s','10m'. Les unitats de temps vàlides són 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "p. ex. \"json\" o un esquema JSON", "e.g. 60": "p. ex. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Introdueix la clau API de Bocha Search", "Enter Brave Search API Key": "Introdueix la clau API de Brave Search", "Enter certificate path": "Introdueix el camí del certificat", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Introdueix la mida de solapament de blocs", "Enter Chunk Size": "Introdueix la mida del bloc", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Introdueix parelles de \"token:valor de biaix\" separats per comes (exemple: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Introdueix la URL d'External Web Search", "Enter Firecrawl API Base URL": "Introdueix la URL base de Firecrawl API", "Enter Firecrawl API Key": "Introdueix la clau API de Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Introdueix el nom de la carpeta", "Enter function name filter list (e.g. func1, !func2)": "Introdueix la llista de filtres de noms de funció (per exemple, func1, !func2)", "Enter Github Raw URL": "Introdueix la URL en brut de Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Introdueix el codi hexadecimal del color (p. ex. #FF0000)", "Enter ID": "Introdueix l'ID", "Enter Image Size (e.g. 512x512)": "Introdueix la mida de la imatge (p. ex. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Introdueix la clau API de Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Introdueix la configuració JSON (per exemple, {\"disable_links\": true})", "Enter Jupyter Password": "Introdueix la contrasenya de Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Introdueix la clau API de Kagi Search", "Enter Key Behavior": "Introdueix el comportament de clau", "Enter language codes": "Introdueix els codis de llenguatge", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Entra la URL Base de l'API de Mistral", "Enter Mistral API Key": "Entra la clau API de Mistral", "Enter Model ID": "Introdueix l'identificador del model", @@ -736,6 +753,7 @@ "Failed to generate title": "No s'ha pogut generar el títol", "Failed to import models": "No s'han pogut importar el models", "Failed to load chat preview": "No s'ha pogut carregar la previsualització del xat", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "No s'ha pogut carregar el contingut del fitxer", "Failed to move chat": "No s'ha pogut moure el xat", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Característiques", "Features Permissions": "Permisos de les característiques", "February": "Febrer", + "Feedback": "", "Feedback deleted successfully": "Retorn eliminat correctament", "Feedback Details": "Detalls del retorn", "Feedback History": "Històric de comentaris", - "Feedbacks": "Comentaris", "Feel free to add specific details": "Sent-te lliure d'afegir detalls específics", "Female": "Dona", "File": "Arxiu", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "S'ha detectat la suplantació d'identitat de l'empremta digital: no es poden utilitzar les inicials com a avatar. S'estableix la imatge de perfil predeterminada.", "Firecrawl API Base URL": "URL de l'API de base de Firecrawl", "Firecrawl API Key": "Clau API de Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Accions ràpides flotants", "Focus Chat Input": "Posa el focus en l'entrada del xat", "Folder": "Carpeta", "Folder Background Image": "Imatge del fons de la carpeta", "Folder deleted successfully": "Carpeta eliminada correctament", + "Folder Max File Count": "", "Folder Name": "Nom de la carpeta", "Folder name cannot be empty.": "El nom de la carpeta no pot ser buit.", "Folder name updated successfully": "Nom de la carpeta actualitzat correctament", @@ -826,7 +846,6 @@ "General": "General", "Generate": "Generar", "Generate an image": "Generar una imatge", - "Generate Image": "Generar imatge", "Generate Message Pair": "Generar parella de missatges", "Generated Image": "Imatge generada", "Generating search query": "Generant consulta", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Comença amb {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Bona resposta", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Clau API PSE de Google", "Google PSE Engine Id": "Identificador del motor PSE de Google", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Grup", "Group Channel": "Canal de grup", "Group created successfully": "El grup s'ha creat correctament", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Generació d'indicacions d'imatge", "Image Prompt Generation Prompt": "Indicació per a la generació d'indicacions d'imatge", "Image Size": "Mida de la imatge", - "Images": "Imatges", "Import": "Importar", "Import Chats": "Importar xats", "Import Config from JSON File": "Importar la configuració des d'un arxiu JSON", @@ -927,6 +947,7 @@ "Integration": "Integració", "Integrations": "Integracions", "Interface": "Interfície", + "Interface Settings Access": "", "Invalid file content": "Continguts del fitxer no vàlids", "Invalid file format.": "Format d'arxiu no vàlid.", "Invalid JSON file": "Arxiu JSON no vàlid", @@ -940,6 +961,7 @@ "is typing...": "està escrivint...", "Italic": "Cursiva", "January": "Gener", + "Jina API Base URL": "", "Jina API Key": "Clau API de Jina", "join our Discord for help.": "uneix-te al nostre Discord per obtenir ajuda.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Deixar-ho buit per incloure tots els models del punt de connexió \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Deixar-ho buit per incloure tots els models del punt de connexió \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Deixa-ho en blanc per incloure tots els models o selecciona models específics", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Deixau-ho en blanc per utilitzar el model per defecte (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Deixa-ho en blanc per utilitzar la indicació predeterminada o introdueix una indicació personalitzada", "Leave model field empty to use the default model.": "Deixa el camp de model buit per utilitzar el model per defecte.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Gestionar la informació del teu compte.", "March": "Març", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (encapçalament)", + "Markdown Header Text Splitter": "", "Max Speakers": "Nombre màxim d'altaveus", "Max Upload Count": "Nombre màxim de càrregues", "Max Upload Size": "Mida màxima de càrrega", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es poden descarregar un màxim de 3 models simultàniament. Si us plau, prova-ho més tard.", "May": "Maig", "MBR": "MBR", @@ -1042,6 +1067,7 @@ "Member removed successfully": "El membre s'ha eliminat satisfactòriament", "Members": "Membres", "Members added successfully": "Els membres s'han afegit satisfactòriament", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Les memòries accessibles pels models de llenguatge es mostraran aquí.", "Memory": "Memòria", "Memory added successfully": "Memòria afegida correctament", @@ -1051,6 +1077,7 @@ "Merge Responses": "Fusionar les respostes", "Merged Response": "Resposta combinada", "Message": "Missatge", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "La classificació dels missatges s'hauria d'activar per utilitzar aquesta funció", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Els missatges enviats després de crear el teu enllaç no es compartiran. Els usuaris amb la URL podran veure el xat compartit.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Nom del model", "Model name already exists, please choose a different one": "Aquest nom de model ja existeix, si us plau, tria'n un altre", "Model Name is required.": "El nom del model és necessari", + "Model names and usage frequency": "", "Model not selected": "Model no seleccionat", "Model Params": "Paràmetres del model", "Model Permissions": "Permisos dels models", + "Model responses or outputs": "", "Model unloaded successfully": "El model s'ha descarregat correctament", "Model updated successfully": "Model actualitzat correctament", "Model(s) do not support file upload": "El model no permet la pujada d'arxius", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Els models s'han importat correctament", "Models Public Sharing": "Compartició pública de models", "Models Sharing": "Compartir els models", + "Mojeek": "", "Mojeek Search API Key": "Clau API de Mojeek Search", "More": "Més", "More Concise": "Més precís", @@ -1129,7 +1159,7 @@ "No conversation to save": "No hi ha cap conversa a desar", "No distance available": "No hi ha distància disponible", "No expiration can pose security risks.": "No posar expiració pot suposar problemes de seguretat.", - "No feedbacks found": "No s'han trobat comentaris", + "No feedback found": "", "No file selected": "No s'ha escollit cap fitxer", "No files in this knowledge base.": "", "No functions found": "No s'han trobat funcions", @@ -1144,6 +1174,7 @@ "No models selected": "No s'ha seleccionat cap model", "No Notes": "No hi ha notes", "No notes found": "No s'han trobat notes", + "No one": "", "No pinned messages": "No hi ha missatges fixats", "No prompts found": "No s'han trobat indicacions", "No results": "No s'han trobat resultats", @@ -1195,6 +1226,7 @@ "Only invited users can access": "Només hi poden accedir els usuaris convidats", "Only markdown files are allowed": "Només es permeten arxius markdown", "Only select users and groups with permission can access": "Només hi poden accedir usuaris i grups seleccionats amb permís", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ui! Sembla que la URL no és vàlida. Si us plau, revisa-la i torna-ho a provar.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ui! Encara hi ha fitxers pujant-se. Si us plau, espera que finalitzi la càrrega.", "Oops! There was an error in the previous response.": "Ui! Hi ha hagut un error a la resposta anterior.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI pot utilitzar eines de servidors OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI utilitza faster-whisper internament.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI utilitza incrustacions de SpeechT5 i CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "La versió d'Open WebUI (v{{OPEN_WEBUI_VERSION}}) és inferior a la versió requerida (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API d'OpenAI", @@ -1235,6 +1268,8 @@ "page": "pàgina", "Paginate": "Paginar", "Parameters": "Paràmetres", + "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.": "", "Password": "Contrasenya", "Passwords do not match.": "Les contrasenyes no coincideixen", "Paste Large Text as File": "Enganxa un text llarg com a fitxer", @@ -1260,7 +1295,6 @@ "Pipe": "Canonada", "Pipeline deleted successfully": "Pipeline eliminada correctament", "Pipeline downloaded successfully": "Pipeline descarregada correctament", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines és un sistema de connectors amb execució arbitrària de codi —", "Pipelines Not Detected": "No s'ha detectat Pipelines", "Pipelines Valves": "Vàlvules de les Pipelines", @@ -1499,6 +1533,7 @@ "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.": "Establir les seqüències d'aturada a utilitzar. Quan es trobi aquest patró, el LLM deixarà de generar text. Es poden establir diversos patrons de parada especificant diversos paràmetres de parada separats en un fitxer model.", "Setting": "Preferència", "Settings": "Preferències", + "Settings Permissions": "", "Settings saved successfully!": "Les preferències s'han desat correctament", "Share": "Compartir", "Share Chat": "Compartir el xat", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Error de reconeixement de veu: {{error}}", "Speech-to-Text": "Àudio-a-Text", "Speech-to-Text Engine": "Motor de veu a text", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Iniciar una nova conversa", "Start of the channel": "Inici del canal", "Start Tag": "Etiqueta d'inici", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Passos", "Stop": "Atura", + "Stop Download": "", "Stop Generating": "Aturar la generació", "Stop Sequence": "Atura la seqüència", "Stream Chat Response": "Fer streaming de la resposta del xat", @@ -1572,7 +1609,14 @@ "Support": "Dona suport", "Support this plugin:": "Dona suport a aquest complement:", "Supported MIME Types": "Tipus MIME admesos", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sincronitzar directori", + "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": "Sistema", "System Instructions": "Instruccions de sistema", "System Prompt": "Indicació del Sistema", @@ -1617,6 +1661,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "El pes de la cerca híbrida BM25. 0 més semàntic, 1 més lèxic. Per defecte 0,5", "The width in pixels to compress images to. Leave empty for no compression.": "L'amplada en píxels per comprimir imatges. Deixar-ho buit per a cap compressió.", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Pensant...", "This action cannot be undone. Do you wish to continue?": "Aquesta acció no es pot desfer. Vols continuar?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Aquest canal es va crear el dia {{createdAt}}. Aquest és el començament del canal {{channelName}}.", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Pujar una Pipeline", "Upload Progress": "Progrés de càrrega", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Progrés de la pujada: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "Pujant l'arxiu...", "URL": "URL", "URL is required": "La URL és necessaria", @@ -1748,6 +1794,7 @@ "User Groups": "Grups d'usuari", "User location successfully retrieved.": "Ubicació de l'usuari obtinguda correctament", "User menu": "Menú d'usuari", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooks d'usuari", "Username": "Nom d'usuari", "users": "usuaris", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI farà peticions a \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Què intentes aconseguir?", "What are you working on?": "En què estàs treballant?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Què hi ha de nou a", "What's on your mind?": "Què tens en ment?", "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.": "Quan està activat, el model respondrà a cada missatge de xat en temps real, generant una resposta tan bon punt l'usuari envia un missatge. Aquest mode és útil per a aplicacions de xat en directe, però pot afectar el rendiment en maquinari més lent.", "wherever you are": "allà on estiguis", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Si es pagina la sortida. Cada pàgina estarà separada per una regla horitzontal i un número de pàgina. Per defecte és Fals.", "Whisper (Local)": "Whisper (local)", + "Who can share to this group": "", "Why?": "Per què?", "Widescreen Mode": "Mode de pantalla ampla", "Width": "amplada", + "Wikipedia": "", "Won": "Ha guanyat", "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.": "Funciona juntament amb top-k. Un valor més alt (p. ex., 0,95) donarà lloc a un text més divers, mentre que un valor més baix (p. ex., 0,5) generarà un text més concentrat i conservador.", "Workspace": "Espai de treball", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "URL de la instància de Yacy", "Yacy Password": "Contrasenya de Yacy", "Yacy Username": "Nom d'usuari de Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Ahir", "Yesterday at {{LOCALIZED_TIME}}": "Ahir a les {{LOCALIZED_TIME}}", "You": "Tu", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Només pots xatejar amb un màxim de {{maxCount}} fitxers alhora.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Pots personalitzar les teves interaccions amb els models de llenguatge afegint memòries mitjançant el botó 'Gestiona' que hi ha a continuació, fent-les més útils i adaptades a tu.", "You cannot upload an empty file.": "No es pot pujar un arxiu buit.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "No tens permís per enviar missatges en aquest canal.", "You do not have permission to send messages in this thread.": "No tens permís per enviar missatges en aquest fil.", "You do not have permission to upload files to this knowledge base.": "", @@ -1835,6 +1891,8 @@ "Your Account": "El teu compte", "Your account status is currently pending activation.": "El compte està actualment pendent d'activació", "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.": "Tota la teva contribució anirà directament al desenvolupador del complement; Open WebUI no se'n queda cap percentatge. Tanmateix, la plataforma de finançament escollida pot tenir les seves pròpies comissions.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Idioma de YouTube", "Youtube Proxy URL": "URL de Proxy de Youtube" diff --git a/src/lib/i18n/locales/ceb-PH/translation.json b/src/lib/i18n/locales/ceb-PH/translation.json index cc900436b7..fed29d79f1 100644 --- a/src/lib/i18n/locales/ceb-PH/translation.json +++ b/src/lib/i18n/locales/ceb-PH/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ang pag-adjust niini nga mga setting magamit ang mga pagbag-o sa tanan nga tiggamit.", "admin": "Administrator", "Admin": "", + "Admin Contact Email": "", "Admin Panel": "Admin Panel", "Admin Settings": "Mga setting sa administratibo", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "", "Android": "", + "Anyone": "", "API Base URL": "API Base URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "yawe sa API", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Awtomatikong kopya sa tubag sa clipboard", "Auto-playback response": "Autoplay nga tubag", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "Base URL AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Ang AUTOMATIC1111 base URL gikinahanglan.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "magamit nga mga tiggamit", @@ -201,6 +204,7 @@ "before": "", "Being lazy": "", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Susiha ang mga update", "Checking for updates...": "Pagsusi alang sa mga update...", "Choose a model before saving...": "Pagpili og template sa dili pa i-save...", + "Chunk Min Size Target": "", "Chunk Overlap": "Block overlap", "Chunk Size": "Gidak-on sa block", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Mga kinutlo", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "Kontento", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Database", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "Documents": "Mga dokumento", "does not make any external connections, and your data stays securely on your locally hosted server.": "wala maghimo ug eksternal nga koneksyon, ug ang imong data nagpabiling luwas sa imong lokal nga host server.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Ayaw kuhaa og random nga pipelines gikan sa dili kasaligan nga mga tinubdan.", @@ -493,11 +502,14 @@ "Done": "", "Download": "", "Download & Delete": "I-download ug papas", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "", "Download Database": "I-download ang database", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "p. ", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Pagsulod sa block overlap", "Enter Chunk Size": "Isulod ang block size", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Pagsulod sa gidak-on sa hulagway (pananglitan 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Heneral", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "", + "Google": "", "Google Drive": "", "Google PSE API Key": "", "Google PSE Engine Id": "", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grupo", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Mga hulagway", "Import": "", "Import Chats": "Import nga mga chat", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Interface", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "Apil sa among Discord alang sa tabang.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Ang labing taas nga 3 nga mga disenyo mahimong ma-download nga dungan. ", "May": "", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "", "Memory": "", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Gihiusa nga Resulta sa Tubag", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Wala gipili ang modelo", "Model Params": "", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Walay resulta", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! ", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Password", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "", "Pipelines are a plugin system with arbitrary code execution —": "Ang Pipelines usa ka plugin system nga makapadagan og bisan unsang kodigo —", "Pipelines Not Detected": "", "Pipelines Valves": "", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "Mga setting", + "Settings Permissions": "", "Settings saved successfully!": "Malampuson nga na-save ang mga setting!", "Share": "", "Share Chat": "", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Sayop sa pag-ila sa tingog: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Engine sa pag-ila sa tingog", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Sinugdan sa channel", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Pagkasunod-sunod sa pagsira", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "Sistema", "System Instructions": "", "System Prompt": "Madasig nga Sistema", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Tema", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "Pag-uswag sa Pag-upload", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Unsay bag-o sa", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/cs-CZ/translation.json b/src/lib/i18n/locales/cs-CZ/translation.json index 1e0b837b2b..f08c54f6a6 100644 --- a/src/lib/i18n/locales/cs-CZ/translation.json +++ b/src/lib/i18n/locales/cs-CZ/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Úprava těchto nastavení se projeví u všech uživatelů.", "admin": "administrátor", "Admin": "Administrátor", + "Admin Contact Email": "", "Admin Panel": "Administrace", "Admin Settings": "Nastavení administrátora", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administrátoři mají kdykoli přístup ke všem nástrojům; uživatelé potřebují mít nástroje přiřazené k jednotlivým modelům v pracovním prostoru.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Povolit nahrávání souborů", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Povolit více modelů v chatu", "Allow non-local voices": "Povolit nelokální hlasy", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "a {{COUNT}} dalších", "and create a new shared link.": "a vytvořit nový sdílený odkaz.", "Android": "Android", + "Anyone": "", "API Base URL": "Základní URL adresa API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "Základní URL adresa API pro službu Datalab Marker. Výchozí hodnota: https://www.datalab.to/api/v1/marker", "API Key": "Klíč API", @@ -175,6 +176,7 @@ "Authenticate": "Ověřit", "Authentication": "Ověřování", "Auto": "Auto", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automaticky kopírovat odpověď do schránky", "Auto-playback response": "Automatické přehrávání odpovědi", "Autocomplete Generation": "Generování automatického dokončování", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Ověřovací řetězec API pro AUTOMATIC1111", "AUTOMATIC1111 Base URL": "Základní URL pro AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Je vyžadována základní URL pro AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Seznam dostupných", "Available Tools": "Dostupné nástroje", "available users": "dostupní uživatelé", @@ -201,6 +204,7 @@ "before": "před", "Being lazy": "Být líný", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Koncový bod Bing Search V7", "Bing Search V7 Subscription Key": "Klíč předplatného Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "API klíč pro Bocha Search", "Bold": "Tučně", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Zvýhodňování nebo penalizace specifických tokenů pro omezené odpovědi. Hodnoty odchylky budou omezeny v rozmezí -100 až 100 (včetně). (Výchozí: žádné)", + "Brave": "", "Brave Search API Key": "Klíč API pro Brave Search", + "Builtin Tools": "", "Bullet List": "Seznam s odrážkami", "Button ID": "ID tlačítka", "Button Label": "Popisek tlačítka", @@ -256,8 +262,10 @@ "Check for updates": "Zkontrolovat aktualizace", "Checking for updates...": "Kontrola aktualizací...", "Choose a model before saving...": "Před uložením vyberte model...", + "Chunk Min Size Target": "", "Chunk Overlap": "Překryv bloků", "Chunk Size": "Velikost bloku", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Šifry", "Citation": "Citace", "Citations": "Citace", @@ -293,7 +301,6 @@ "Code Block": "Blok kódu", "Code Editor": "", "Code execution": "Spouštění kódu", - "Code Execution": "Spouštění kódu", "Code Execution Engine": "Jádro pro spouštění kódu", "Code Execution Timeout": "Časový limit pro spuštění kódu", "Code formatted successfully": "Kód byl úspěšně naformátován.", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Pro přístup k webovému rozhraní kontaktujte administrátora.", "Content": "Obsah", "Content Extraction Engine": "Jádro pro extrakci obsahu", + "Content lengths (character counts only)": "", "Continue Response": "Pokračovat v odpovědi", "Continue with {{provider}}": "Pokračovat s {{provider}}", "Continue with Email": "Pokračovat s e-mailem", @@ -393,6 +401,7 @@ "Database": "Databáze", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "DD.MM.RRRR", + "DDGS Backend": "", "December": "Prosinec", "Decrease UI Scale": "", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Ponořte se do znalostí", "Do not install functions from sources you do not fully trust.": "Neinstalujte funkce ze zdrojů, kterým plně nedůvěřujete.", "Do not install tools from sources you do not fully trust.": "Neinstalujte nástroje ze zdrojů, kterým plně nedůvěřujete.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "Je vyžadována URL adresa serveru Docling.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentace", - "Documents": "Dokumenty", "does not make any external connections, and your data stays securely on your locally hosted server.": "nevytváří žádná externí připojení a vaše data zůstávají bezpečně na vašem lokálně hostovaném serveru.", "Domain Filter List": "Seznam pro filtrování domén", "don't fetch random pipelines from sources you don't trust.": "Nestahujte náhodné pipelines ze zdrojů, kterým nedůvěřujete.", @@ -493,11 +502,14 @@ "Done": "Hotovo", "Download": "Stáhnout", "Download & Delete": "Stáhnout a smazat", + "Download as JSON": "", "Download as SVG": "Stáhnout jako SVG", "Download canceled": "Stahování zrušeno", "Download Database": "Stáhnout databázi", + "Downloading stats...": "", "Draw": "Kreslit", "Drop any files here to upload": "Přetáhněte sem soubory pro nahrání", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "např. '30s','10m'. Platné časové jednotky jsou 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "např. \"json\" nebo JSON schéma", "e.g. 60": "např. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Zadejte API klíč pro Bocha Search", "Enter Brave Search API Key": "Zadejte API klíč pro Brave Search", "Enter certificate path": "Zadejte cestu k certifikátu", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Zadejte překryv bloků", "Enter Chunk Size": "Zadejte velikost bloku", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Zadejte páry \"token:hodnota_odchylky\" oddělené čárkou (příklad: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Zadejte URL pro externí webové vyhledávání", "Enter Firecrawl API Base URL": "Zadejte základní URL API pro Firecrawl", "Enter Firecrawl API Key": "Zadejte API klíč pro Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Zadejte název složky", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Zadejte URL pro Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Zadejte barvu v hex formátu (např. #FF0000)", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Zadejte velikost obrázku (např. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Zadejte API klíč pro Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Zadejte JSON konfiguraci (např. {\"disable_links\": true})", "Enter Jupyter Password": "Zadejte heslo pro Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Zadejte API klíč pro Kagi Search", "Enter Key Behavior": "Zadejte chování klávesy", "Enter language codes": "Zadejte kódy jazyků", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Zadejte API klíč pro Mistral", "Enter Model ID": "Zadejte ID modelu", @@ -736,6 +753,7 @@ "Failed to generate title": "Nepodařilo se vygenerovat název", "Failed to import models": "", "Failed to load chat preview": "Nepodařilo se načíst náhled konverzace", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Nepodařilo se načíst obsah souboru.", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Funkce", "Features Permissions": "Oprávnění funkcí", "February": "Únor", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Podrobnosti zpětné vazby", "Feedback History": "Historie zpětné vazby", - "Feedbacks": "Zpětné vazby", "Feel free to add specific details": "Neváhejte přidat konkrétní detaily.", "Female": "Žena", "File": "Soubor", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Detekován spoofing otisku prstu: Nelze použít iniciály jako avatar. Používá se výchozí profilový obrázek.", "Firecrawl API Base URL": "Základní URL API pro Firecrawl", "Firecrawl API Key": "API klíč pro Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Plovoucí rychlé akce", "Focus Chat Input": "", "Folder": "Složka", "Folder Background Image": "Obrázek na pozadí složky", "Folder deleted successfully": "Složka byla úspěšně smazána", + "Folder Max File Count": "", "Folder Name": "Název složky", "Folder name cannot be empty.": "Název složky nesmí být prázdný.", "Folder name updated successfully": "Název složky byl úspěšně aktualizován.", @@ -826,7 +846,6 @@ "General": "Obecné", "Generate": "Generovat", "Generate an image": "Generovat obrázek", - "Generate Image": "Generovat obrázek", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Generuji vyhledávací dotaz", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Začněte s {{WEBUI_NAME}}", "Global": "Globální", "Good Response": "Dobrá odpověď", + "Google": "", "Google Drive": "Disk Google", "Google PSE API Key": "API klíč pro Google PSE", "Google PSE Engine Id": "ID jádra Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Skupina", "Group Channel": "", "Group created successfully": "Skupina byla úspěšně vytvořena", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Generování instrukcí pro obrázek", "Image Prompt Generation Prompt": "Instrukce pro generování instrukcí pro obrázek", "Image Size": "", - "Images": "Obrázky", "Import": "Importovat", "Import Chats": "Importovat konverzace", "Import Config from JSON File": "Importovat konfiguraci ze souboru JSON", @@ -927,6 +947,7 @@ "Integration": "Integrace", "Integrations": "Integrace", "Interface": "Rozhraní", + "Interface Settings Access": "", "Invalid file content": "Neplatný obsah souboru", "Invalid file format.": "Neplatný formát souboru.", "Invalid JSON file": "Neplatný soubor JSON", @@ -940,6 +961,7 @@ "is typing...": "píše...", "Italic": "Kurzíva", "January": "Leden", + "Jina API Base URL": "", "Jina API Key": "API klíč pro Jina", "join our Discord for help.": "připojte se na náš Discord pro pomoc.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Ponechte prázdné pro zahrnutí všech modelů z koncového bodu \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Ponechte prázdné pro zahrnutí všech modelů z koncového bodu \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Ponechte prázdné pro zahrnutí všech modelů nebo vyberte konkrétní modely.", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Ponechte prázdné pro použití výchozích instrukcí, nebo zadejte vlastní instrukce.", "Leave model field empty to use the default model.": "Ponechte pole modelu prázdné pro použití výchozího modelu.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Spravujte informace o svém účtu.", "March": "Březen", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (nadpis)", + "Markdown Header Text Splitter": "", "Max Speakers": "Max. mluvčích", "Max Upload Count": "Maximální počet nahrání", "Max Upload Size": "Maximální velikost nahrávaných souborů", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Současně lze stahovat maximálně 3 modely. Zkuste to prosím později.", "May": "Květen", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Zde se zobrazí vzpomínky přístupné pro LLM.", "Memory": "Paměť", "Memory added successfully": "Vzpomínka byla úspěšně přidána.", @@ -1051,6 +1077,7 @@ "Merge Responses": "Sloučit odpovědi", "Merged Response": "Sloučená odpověď", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Pro použití této funkce musí být povoleno hodnocení zpráv.", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Zprávy, které odešlete po vytvoření odkazu, nebudou sdíleny. Uživatelé s URL adresou budou moci zobrazit sdílenou konverzaci.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Název modelu", "Model name already exists, please choose a different one": "Název modelu již existuje, zvolte prosím jiný", "Model Name is required.": "Název modelu je vyžadován.", + "Model names and usage frequency": "", "Model not selected": "Není vybrán žádný model", "Model Params": "Parametry modelu", "Model Permissions": "Oprávnění modelu", + "Model responses or outputs": "", "Model unloaded successfully": "Model byl úspěšně uvolněn", "Model updated successfully": "Model byl úspěšně aktualizován", "Model(s) do not support file upload": "Vybraný model (modely) nepodporuje nahrávání souborů", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Veřejné sdílení modelů", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "API klíč pro Mojeek Search", "More": "Více", "More Concise": "Stručnější", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Vzdálenost není k dispozici", "No expiration can pose security risks.": "", - "No feedbacks found": "Nebyla nalezena žádná zpětná vazba", + "No feedback found": "", "No file selected": "Nebyl vybrán žádný soubor", "No files in this knowledge base.": "", "No functions found": "Žádné funkce nenalezeny", @@ -1144,6 +1174,7 @@ "No models selected": "Nebyly vybrány žádné modely", "No Notes": "Žádné poznámky", "No notes found": "Nebyly nalezeny žádné poznámky", + "No one": "", "No pinned messages": "", "No prompts found": "Nebyly nalezeny žádné instrukce", "No results": "Nebyly nalezeny žádné výsledky", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Jsou povoleny pouze soubory markdown", "Only select users and groups with permission can access": "Přístup mají pouze vybraní uživatelé a skupiny s oprávněním", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Jejda! Zdá se, že URL adresa je neplatná. Zkontrolujte ji prosím a zkuste to znovu.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Jejda! Některé soubory se stále nahrávají. Počkejte prosím na dokončení nahrávání.", "Oops! There was an error in the previous response.": "Jejda! V předchozí odpovědi došlo k chybě.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI může používat nástroje poskytované jakýmkoli serverem OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI interně používá faster-whisper.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI používá SpeechT5 a vektorizaci mluvčích CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Verze Open WebUI (v{{OPEN_WEBUI_VERSION}}) je nižší než požadovaná verze (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "stránka", "Paginate": "Stránkovat", "Parameters": "Parametry", + "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.": "", "Password": "Heslo", "Passwords do not match.": "Hesla se neshodují.", "Paste Large Text as File": "Vložit velký text jako soubor", @@ -1260,7 +1295,6 @@ "Pipe": "Pipe", "Pipeline deleted successfully": "Pipeline byla úspěšně smazána", "Pipeline downloaded successfully": "Pipeline byla úspěšně stažena", - "Pipelines": "Pipeline", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines je zásuvný systém s možností libovolného spouštění kódu —", "Pipelines Not Detected": "Nebyla nalezena žádná pipeline", "Pipelines Valves": "Řízení toků pipeline", @@ -1500,6 +1534,7 @@ "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.": "Nastavuje ukončovací sekvence. Když je tento vzor nalezen, LLM přestane generovat text a vrátí výsledek. Lze nastavit více ukončovacích vzorů zadáním více samostatných parametrů stop v souboru modelfile.", "Setting": "", "Settings": "Nastavení", + "Settings Permissions": "", "Settings saved successfully!": "Nastavení byla úspěšně uložena!", "Share": "Sdílet", "Share Chat": "Sdílet konverzaci", @@ -1543,6 +1578,7 @@ "Speech recognition error: {{error}}": "Chyba rozpoznávání řeči: {{error}}", "Speech-to-Text": "Převod řeči na text", "Speech-to-Text Engine": "Jádro pro převod řeči na text", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Začátek kanálu", "Start Tag": "", @@ -1553,6 +1589,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Zastavit", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "stop sequence", "Stream Chat Response": "stream chat response", @@ -1573,7 +1610,14 @@ "Support": "Podpora", "Support this plugin:": "Podpořte tento plugin:", "Supported MIME Types": "Podporované typy MIME", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synchronizovat adresář", + "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": "Systém", "System Instructions": "Systémové instrukce", "System Prompt": "Systémové instrukce", @@ -1618,6 +1662,7 @@ "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.": "Šířka v pixelech, na kterou se mají obrázky komprimovat. Pro žádnou kompresi ponechte prázdné.", "Theme": "Motiv", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Přemýšlím...", "This action cannot be undone. Do you wish to continue?": "Tuto akci nelze vrátit zpět. Přejete si pokračovat?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Tento kanál byl vytvořen {{createdAt}}. Toto je úplný začátek kanálu {{channelName}}.", @@ -1732,6 +1777,7 @@ "Upload Pipeline": "Nahrát pipeline", "Upload Progress": "Průběh nahrávání", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Průběh nahrávání: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "URL je vyžadována", @@ -1749,6 +1795,7 @@ "User Groups": "Skupiny uživatelů", "User location successfully retrieved.": "Poloha uživatele byla úspěšně získána.", "User menu": "Uživatelská nabídka", + "User ratings (thumbs up/down)": "", "User Webhooks": "Uživatelské webhooky", "Username": "Uživatelské jméno", "users": "", @@ -1798,15 +1845,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI bude odesílat požadavky na \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Čeho se snažíte dosáhnout?", "What are you working on?": "Na čem pracujete?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Co je nového v", "What's on your mind?": "", "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.": "Když je povoleno, model bude odpovídat na každou zprávu v konverzaci v reálném čase a generovat odpověď, jakmile uživatel odešle zprávu. Tento režim je užitečný pro aplikace s živou konverzací, ale může ovlivnit výkon na pomalejším hardwaru.", "wherever you are": "ať jste kdekoli", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Zda stránkovat výstup. Každá stránka bude oddělena vodorovnou čarou a číslem stránky. Výchozí hodnota je False.", "Whisper (Local)": "Whisper (lokální)", + "Who can share to this group": "", "Why?": "Proč?", "Widescreen Mode": "Širokoúhlý režim", "Width": "Šířka", + "Wikipedia": "", "Won": "Vyhrál", "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.": "Funguje společně s top-k. Vyšší hodnota (např. 0,95) povede k rozmanitějšímu textu, zatímco nižší hodnota (např. 0,5) vygeneruje soustředěnější a konzervativnější text.", "Workspace": "Pracovní prostor", @@ -1818,6 +1869,8 @@ "Yacy Instance URL": "URL instance Yacy", "Yacy Password": "Heslo pro Yacy", "Yacy Username": "Uživatelské jméno pro Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Včera", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Vy", @@ -1825,6 +1878,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Můžete konverzovat s maximálně {{maxCount}} souborem (soubory) najednou.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Své interakce s LLM si můžete přizpůsobit přidáním vzpomínek pomocí tlačítka 'Spravovat' níže, čímž se stanou užitečnějšími a přizpůsobenými vám.", "You cannot upload an empty file.": "Nemůžete nahrát prázdný soubor.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1836,6 +1892,8 @@ "Your Account": "Váš účet", "Your account status is currently pending activation.": "Stav vašeho účtu aktuálně čeká na aktivaci.", "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.": "Celý váš příspěvek půjde přímo vývojáři pluginu; Open WebUI si nebere žádné procento. Zvolená platforma pro financování však může mít vlastní poplatky.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "Jazyk YouTube", "Youtube Proxy URL": "Proxy URL pro YouTube" diff --git a/src/lib/i18n/locales/da-DK/translation.json b/src/lib/i18n/locales/da-DK/translation.json index 3c9dbf29be..3fc64726ab 100644 --- a/src/lib/i18n/locales/da-DK/translation.json +++ b/src/lib/i18n/locales/da-DK/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ændringer af disse indstillinger har konsekvenser for alle brugere.", "admin": "administrator", "Admin": "Administrator", + "Admin Contact Email": "", "Admin Panel": "Administrationspanel", "Admin Settings": "Administrationsindstillinger", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratorer har adgang til alle værktøjer altid; brugere skal tilføjes værktøjer pr. model i hvert workspace.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Tillad fortsættelse af svar", "Allow Delete Messages": "Tillad sletning af beskeder", "Allow File Upload": "Tillad upload af fil", - "Allow Group Sharing": "Tillad gruppedeling", "Allow Multiple Models in Chat": "Tillad flere modeller i chats", "Allow non-local voices": "Tillad ikke-lokale stemmer", "Allow Rate Response": "Tillad vurdering af svar", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "og {{COUNT}} mere", "and create a new shared link.": "og lav et nyt link til deling", "Android": "Android", + "Anyone": "", "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. Standard: https://www.datalab.to/api/v1/marker", "API Key": "API nøgle", @@ -175,6 +176,7 @@ "Authenticate": "Autentificer", "Authentication": "Autentikation", "Auto": "Auto", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatisk kopiering af svar til udklipsholder", "Auto-playback response": "Automatisk afspil svar", "Autocomplete Generation": "Genere automatisk fuldførsel", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 base URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 base URL er påkrævet.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Tilgængelige lister", "Available Tools": "Tilgængelige værktøj", "available users": "tilgængelige brugere", @@ -201,6 +204,7 @@ "before": "før", "Being lazy": "At være doven", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 Endpoint", "Bing Search V7 Subscription Key": "Bing Search V7 Subscription Key", "Bio": "Biografi", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search API Key", "Bold": "Fed", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Forøg eller reducer specifikke tokens for begrænsede svar. Bias-værdier vil blive begrænset til mellem -100 og 100 (inklusiv). (Standard: ingen)", + "Brave": "", "Brave Search API Key": "Brave Search API nøgle", + "Builtin Tools": "", "Bullet List": "Punktliste", "Button ID": "Knap ID", "Button Label": "Knap label", @@ -256,8 +262,10 @@ "Check for updates": "Søg efter opdateringer", "Checking for updates...": "Søger efter opdateringer", "Choose a model before saving...": "Vælg en model før du gemmer", + "Chunk Min Size Target": "", "Chunk Overlap": "Chunk overlap", "Chunk Size": "Chunk størrelse", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Ciphers", "Citation": "Citat", "Citations": "Citater", @@ -293,7 +301,6 @@ "Code Block": "Kodeblok", "Code Editor": "Kodeeditor", "Code execution": "Kode kørsel", - "Code Execution": "Kode kørsel", "Code Execution Engine": "Kode kørsel engine", "Code Execution Timeout": "Kode kørsel timeout", "Code formatted successfully": "Kode formateret korrekt", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Kontakt din administrator for adgang til WebUI", "Content": "Indhold", "Content Extraction Engine": "Content Extraction Motor", + "Content lengths (character counts only)": "", "Continue Response": "Fortsæt svar", "Continue with {{provider}}": "Fortsæt med {{provider}}", "Continue with Email": "Fortsæt med Email", @@ -393,6 +401,7 @@ "Database": "Database", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "DD/MM/ÅÅÅÅ", + "DDGS Backend": "", "December": "december", "Decrease UI Scale": "Nedjuster UI-skalering", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Undersøg viden", "Do not install functions from sources you do not fully trust.": "Lad være med at installere funktioner fra kilder, som du ikke stoler på.", "Do not install tools from sources you do not fully trust.": "Lad være med at installere værktøjer fra kilder, som du ikke stoler på.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "Docling parametre", "Docling Server URL required.": "Docling Server URL påkrævet.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Document Intelligence endpoint påkrævet", "Document Intelligence Model": "Document Intelligence model", "Documentation": "Dokumentation", - "Documents": "Dokumenter", "does not make any external connections, and your data stays securely on your locally hosted server.": "laver ikke eksterne kald, og din data bliver sikkert på din egen lokalt hostede server.", "Domain Filter List": "Domæne filterliste", "don't fetch random pipelines from sources you don't trust.": "Hent ikke tilfældige pipelines fra kilder, du ikke stoler på.", @@ -493,11 +502,14 @@ "Done": "Færdig", "Download": "Download", "Download & Delete": "Download og slet", + "Download as JSON": "", "Download as SVG": "Download som SVG", "Download canceled": "Download afbrudt", "Download Database": "Download database", + "Downloading stats...": "", "Draw": "Tegn", "Drop any files here to upload": "Drop nogen filer her for at uploade", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "f.eks. '30s', '10m'. Tilladte værdier er 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "f.eks. \"json\" eller en JSON schema", "e.g. 60": "f.eks. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Indtast Bocha Search API nøgle", "Enter Brave Search API Key": "Indtast Brave Search API-nøgle", "Enter certificate path": "Indtast certifikatsti", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Indtast overlapning af tekststykker", "Enter Chunk Size": "Indtast størrelse af tekststykker", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Indtast kommaseparerede \"token:bias_værdi\" par (eksempel: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Indtast External Web Search URL", "Enter Firecrawl API Base URL": "Indtast Firecrawl API base URL", "Enter Firecrawl API Key": "Indtast Firecrawl API nøgle", + "Enter Firecrawl Timeout": "", "Enter folder name": "Indtast mappenavn", "Enter function name filter list (e.g. func1, !func2)": "Indtast funktionsnavn filterliste (f.eks. func1, !func2)", "Enter Github Raw URL": "Indtast Github Raw URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Indtast hex farve (f.eks. #FF0000)", "Enter ID": "Indtast ID", "Enter Image Size (e.g. 512x512)": "Indtast billedstørrelse (f.eks. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Indtast Jina API nøgle", "Enter JSON config (e.g., {\"disable_links\": true})": "Indtast JSON konfiguration (f.eks., {\"disable_links\": true})", "Enter Jupyter Password": "Indtast Jupyter password", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Indtast Kagi Search API nøgle", "Enter Key Behavior": "Indtast taste opførsel", "Enter language codes": "Indtast sprogkoder", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Indtast Mistral API base URL", "Enter Mistral API Key": "Indtast Mistral API nøgle", "Enter Model ID": "Indtast model-ID", @@ -736,6 +753,7 @@ "Failed to generate title": "Kunne ikke generere titel", "Failed to import models": "Kunne ikke importere modeller", "Failed to load chat preview": "Kunne ikke indlæse chat forhåndsvisning", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Kunne ikke indlæse filindhold.", "Failed to move chat": "Kunne ikke flytte chat", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Features", "Features Permissions": "Features tilladelser", "February": "Februar", + "Feedback": "", "Feedback deleted successfully": "Feedback slettet", "Feedback Details": "Feedback detaljer", "Feedback History": "Feedback historik", - "Feedbacks": "Feedback", "Feel free to add specific details": "Du er velkommen til at tilføje specifikke detaljer", "Female": "Kvinde", "File": "Fil", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingeraftryksspoofing registreret: Kan ikke bruge initialer som avatar. Bruger standard profilbillede.", "Firecrawl API Base URL": "Firecrawl API base URL", "Firecrawl API Key": "Firecrawl API nøgle", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Flydende hurtig-handlinger", "Focus Chat Input": "Fokus chat-input", "Folder": "Mappe", "Folder Background Image": "Mappe baggrundsbillede", "Folder deleted successfully": "Mappe fjernet.", + "Folder Max File Count": "", "Folder Name": "Mappenavn", "Folder name cannot be empty.": "Mappenavn kan ikke være tom.", "Folder name updated successfully": "Mappenavn opdateret.", @@ -826,7 +846,6 @@ "General": "Generelt", "Generate": "Generer", "Generate an image": "Generer et billede", - "Generate Image": "Generer billede", "Generate Message Pair": "Generer besked par", "Generated Image": "Genereret billede", "Generating search query": "Genererer søgeforespørgsel", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Kom i gang med {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Godt svar", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API-nøgle", "Google PSE Engine Id": "Google PSE Engine-ID", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Gruppe", "Group Channel": "Gruppekanal", "Group created successfully": "Gruppe oprettet.", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Billedpromptgenerering", "Image Prompt Generation Prompt": "Billedpromptgenerering prompt", "Image Size": "Billedstørrelse", - "Images": "Billeder", "Import": "Importer", "Import Chats": "Importer chats", "Import Config from JSON File": "Importer konfiguration fra JSON-fil", @@ -927,6 +947,7 @@ "Integration": "Integration", "Integrations": "Integrationer", "Interface": "Grænseflade", + "Interface Settings Access": "", "Invalid file content": "Ugyldigt filindhold", "Invalid file format.": "Ugyldigt filformat.", "Invalid JSON file": "Ugyldig JSON fil", @@ -940,6 +961,7 @@ "is typing...": "er i gang med at skrive...", "Italic": "Kursiv", "January": "Januar", + "Jina API Base URL": "", "Jina API Key": "Jina API-nøgle", "join our Discord for help.": "tilslut dig vores Discord for at få hjælp.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Lad stå tomt for at inkludere alle modeller fra \"{{url}}/api/tags\" endpoint", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Lad stå tomt for at inkludere alle modeller fra \"{{url}}/models\" endpoint", "Leave empty to include all models or select specific models": "Lad stå tomt for at inkludere alle modeller eller vælg specifikke modeller", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Lad stå tomt for at bruge standardmodel (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Lad stå tomt for at bruge standardprompten, eller indtast en brugerdefineret prompt", "Leave model field empty to use the default model.": "Lad modelfeltet stå tomt for at bruge standardmodellen.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Administrer dine brugerinformationer.", "March": "Marts", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (Overskrift)", + "Markdown Header Text Splitter": "", "Max Speakers": "Max talere", "Max Upload Count": "Maks. uploadantal", "Max Upload Size": "Maks. uploadstørrelse", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Højst 3 modeller kan downloades samtidigt. Prøv igen senere.", "May": "Maj", "MBR": "MBR", @@ -1042,6 +1067,7 @@ "Member removed successfully": "Medlem fjernet", "Members": "Medlemmer", "Members added successfully": "Medlemmer tilføjet", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Minder, der er tilgængelige for LLM'er, vises her.", "Memory": "Hukommelse", "Memory added successfully": "Hukommelse tilføjet.", @@ -1051,6 +1077,7 @@ "Merge Responses": "Flet svar", "Merged Response": "Sammensat svar", "Message": "Besked", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Besked rating skal være aktiveret for at bruge denne funktion", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Beskeder, du sender efter at have oprettet dit link, deles ikke. Brugere med URL'en vil kunne se den delte chat.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Modelnavn", "Model name already exists, please choose a different one": "Modelnavn findes allerede, vælg venligst et andet", "Model Name is required.": "Modelnavn er påkrævet.", + "Model names and usage frequency": "", "Model not selected": "Model ikke valgt", "Model Params": "Modelparametre", "Model Permissions": "Model tilladelser", + "Model responses or outputs": "", "Model unloaded successfully": "Model aflæst", "Model updated successfully": "Model opdateret.", "Model(s) do not support file upload": "Model(ler) understøtter ikke fil upload", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Modeller importeret", "Models Public Sharing": "Modeller offentlig deling", "Models Sharing": "Modeldeling", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API nøgle", "More": "Mere", "More Concise": "Mere kortfattet", @@ -1129,7 +1159,7 @@ "No conversation to save": "Ingen samtale at gemme", "No distance available": "Ingen afstand tilgængelig", "No expiration can pose security risks.": "Ingen udløbsdato kan udgøre en sikkerhedsrisiko.", - "No feedbacks found": "Ingen feedback fundet", + "No feedback found": "", "No file selected": "Ingen fil valgt", "No files in this knowledge base.": "", "No functions found": "Ingen funktioner fundet", @@ -1144,6 +1174,7 @@ "No models selected": "Ingen modeller valgt", "No Notes": "Ingen noter", "No notes found": "Ingen noter fundet", + "No one": "", "No pinned messages": "Ingen fastgjorte beskeder", "No prompts found": "Ingen prompts fundet", "No results": "Ingen resultater fundet", @@ -1195,6 +1226,7 @@ "Only invited users can access": "Kun inviterede brugere kan få adgang", "Only markdown files are allowed": "Kun markdown-filer er tilladt", "Only select users and groups with permission can access": "Kun valgte brugere og grupper med tilladelse kan tilgå", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! URL'en ser ud til at være ugyldig. Tjek den igen, og prøv igen.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ups! Der er filer, der stadig uploades. Vent, til uploaden er færdig.", "Oops! There was an error in the previous response.": "Ups! Der var en fejl i det tidligere svar.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI kan bruge værktøjer leveret af enhver OpenAPI server.", "Open WebUI uses faster-whisper internally.": "Open WebUI bruger faster-whisper internt.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI bruger SpeechT5 og CMU Arctic taler embeddings.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI-version (v{{OPEN_WEBUI_VERSION}}) er lavere end den krævede version (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "side", "Paginate": "Paginering", "Parameters": "Parametre", + "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.": "", "Password": "Adgangskode", "Passwords do not match.": "Passwords stemmer ikke overens.", "Paste Large Text as File": "Indsæt store tekster som fil", @@ -1260,7 +1295,6 @@ "Pipe": "Pipe", "Pipeline deleted successfully": "Pipeline slettet.", "Pipeline downloaded successfully": "Pipeline downloadet.", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines er et plugin-system med vilkårlig kodekørsel —", "Pipelines Not Detected": "Pipelines ikke registreret", "Pipelines Valves": "Pipelines-ventiler", @@ -1498,6 +1532,7 @@ "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.": "Indstiller stop-sekvenserne til brug. Når dette mønster stødes på, vil LLM'en stoppe med at generere tekst og returnere. Flere stop-mønstre kan indstilles ved at specificere flere separate stop-parametre i en modelfil.", "Setting": "Indstilling", "Settings": "Indstillinger", + "Settings Permissions": "", "Settings saved successfully!": "Indstillinger gemt!", "Share": "Del", "Share Chat": "Del chat", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Talegenkendelsesfejl: {{error}}", "Speech-to-Text": "Tale-til-tekst", "Speech-to-Text Engine": "Tale-til-tekst-engine", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Start en ny samtale", "Start of the channel": "Kanalens start", "Start Tag": "Start tag", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Trin", "Stop": "Stop", + "Stop Download": "", "Stop Generating": "Stop generering", "Stop Sequence": "Stopsekvens", "Stream Chat Response": "Stream chatsvar", @@ -1571,7 +1608,14 @@ "Support": "Support", "Support this plugin:": "Støt dette plugin:", "Supported MIME Types": "Understøttede MIME-typer", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synkroniser mappe", + "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", "System Instructions": "Systeminstruktioner", "System Prompt": "Systemprompt", @@ -1616,6 +1660,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "Vægten af BM25 Hybrid Search. 0 er mere semantisk, 1 mere leksikalt. Standard er 0.5", "The width in pixels to compress images to. Leave empty for no compression.": "Bredden i pixels at komprimere billeder til. Lad være tom for ingen komprimering.", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Tænker...", "This action cannot be undone. Do you wish to continue?": "Denne handling kan ikke fortrydes. Vil du fortsætte?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Denne kanal blev oprettet den {{createdAt}}. Dette er det helt første i kanalen {{channelName}}.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Upload pipeline", "Upload Progress": "Uploadfremdrift", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Uploadfremdrift: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "Uploader fil...", "URL": "URL", "URL is required": "URL er påkrævet", @@ -1747,6 +1793,7 @@ "User Groups": "Brugergrupper", "User location successfully retrieved.": "Brugerplacering hentet.", "User menu": "Brugermenu", + "User ratings (thumbs up/down)": "", "User Webhooks": "Bruger Webhooks", "Username": "Brugernavn", "users": "brugere", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI vil lave forespørgsler til \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Hvad prøver du at opnå?", "What are you working on?": "Hvad arbejder du på?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Nyheder i", "What's on your mind?": "Hvad har du på hjertet?", "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.": "Når aktiveret, vil modellen reagere på hver chatbesked i realtid og generere et svar, så snart brugeren sender en besked. Denne tilstand er nyttig til live chat-applikationer, men kan påvirke ydeevnen på langsommere hardware.", "wherever you are": "hvad end du er", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Om outputtet skal pagineres. Hver side vil være adskilt af en vandret streg og sidetal. Standard er False.", "Whisper (Local)": "Whisper (lokal)", + "Who can share to this group": "", "Why?": "Hvorfor?", "Widescreen Mode": "Widescreen-tilstand", "Width": "Bredde", + "Wikipedia": "", "Won": "Vandt", "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.": "Fungerer sammen med top-k. En højere værdi (f.eks. 0,95) vil føre til mere forskelligartet tekst, mens en lavere værdi (f.eks. 0,5) vil generere mere fokuseret og konservativ tekst.", "Workspace": "Arbejdsområde", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy instans URL", "Yacy Password": "Yacy adgangskode", "Yacy Username": "Yacy brugernavn", + "Yahoo": "", + "Yandex": "", "Yesterday": "I går", "Yesterday at {{LOCALIZED_TIME}}": "I går klokken {{LOCALIZED_TIME}}", "You": "Du", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Du kan kun chatte med maksimalt {{maxCount}} fil(er) ad gangen.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Du kan personliggøre dine interaktioner med LLM'er ved at tilføje minder via knappen 'Administrer' nedenfor, hvilket gør dem mere nyttige og skræddersyet til dig.", "You cannot upload an empty file.": "Du kan ikke uploade en tom fil", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "Du har ikke tilladelse til at sende beskeder i denne kanal.", "You do not have permission to send messages in this thread.": "Du har ikke tilladelse til at sende beskeder i denne tråd.", "You do not have permission to upload files to this knowledge base.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Din bruger", "Your account status is currently pending activation.": "Din kontostatus afventer i øjeblikket aktivering.", "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.": "Hele dit bidrag går direkte til plugin-udvikleren; Open WebUI tager ikke nogen procentdel. Den valgte finansieringsplatform kan dog have sine egne gebyrer.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube sprog", "Youtube Proxy URL": "Youtube Proxy URL" diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index a7eed9e741..146c1ebcba 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Das Anpassen dieser Einstellungen wendet Änderungen universell auf alle Benutzer an.", "admin": "Administrator", "Admin": "Administrator", + "Admin Contact Email": "", "Admin Panel": "Admin-Bereich", "Admin Settings": "Admin-Einstellungen", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratoren haben jederzeit Zugriff auf alle Werkzeuge; Benutzern müssen Werkzeuge pro Modell im Arbeitsbereich zugewiesen werden.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Fortsetzung der Antwort erlauben", "Allow Delete Messages": "Löschen von Nachrichten erlauben", "Allow File Upload": "Dateiupload erlauben", - "Allow Group Sharing": "Teilen in Gruppe erlauben", "Allow Multiple Models in Chat": "Mehrere Modelle im Chat erlauben", "Allow non-local voices": "Nicht-lokale Stimmen erlauben", "Allow Rate Response": "Antwortbewertung erlauben", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "und {{COUNT}} weitere", "and create a new shared link.": "und erstellen Sie einen neuen Freigabe-Link.", "Android": "Android", + "Anyone": "", "API Base URL": "API-Basis-URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "API-Basis-URL für den Datalab Marker-Dienst. Standardwert: https://www.datalab.to/api/v1/marker", "API Key": "API-Schlüssel", @@ -175,6 +176,7 @@ "Authenticate": "Authentifizieren", "Authentication": "Authentifizierung", "Auto": "Automatisch", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Antwort autom. in Zwischenablage kopieren", "Auto-playback response": "Antwort automatisch abspielen", "Autocomplete Generation": "Autovervollständigung", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 API-Auth-String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Basis-URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Basis-URL ist erforderlich.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Verfügbare Liste", "Available Tools": "Verfügbare Werkzeuge", "available users": "verfügbare Benutzer", @@ -201,6 +204,7 @@ "before": "zuvor", "Being lazy": "Faulheit", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 Endpunkt", "Bing Search V7 Subscription Key": "Bing Search V7 Abonnement-Schlüssel", "Bio": "Biografie", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search API-Schlüssel", "Bold": "Fett", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Bevorzugung oder Benachteiligung spezifischer Token für die Antwortsteuerung. Bias-Werte werden zwischen -100 und 100 (inklusive) begrenzt. (Standard: keine)", + "Brave": "", "Brave Search API Key": "Brave Search API-Schlüssel", + "Builtin Tools": "", "Bullet List": "Aufzählungsliste", "Button ID": "Schaltflächen-ID", "Button Label": "Schaltflächenbeschriftung", @@ -256,8 +262,10 @@ "Check for updates": "Nach Updates suchen", "Checking for updates...": "Suche nach Updates...", "Choose a model before saving...": "Wählen Sie vor dem Speichern ein Modell...", + "Chunk Min Size Target": "", "Chunk Overlap": "Chunk-Überlappung", "Chunk Size": "Chunk-Größe", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Chiffren", "Citation": "Zitat", "Citations": "Zitate", @@ -293,7 +301,6 @@ "Code Block": "Code-Block", "Code Editor": "Code-Editor", "Code execution": "Codeausführung", - "Code Execution": "Codeausführung", "Code Execution Engine": "Engine zur Codeausführung", "Code Execution Timeout": "Zeitlimit für Codeausführung", "Code formatted successfully": "Code erfolgreich formatiert", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Kontaktieren Sie den Administrator für WebUI-Zugriff", "Content": "Inhalt", "Content Extraction Engine": "Engine zur Inhaltsextraktion", + "Content lengths (character counts only)": "", "Continue Response": "Antwort fortsetzen", "Continue with {{provider}}": "Mit {{provider}} fortfahren", "Continue with Email": "Mit E-Mail fortfahren", @@ -393,6 +401,7 @@ "Database": "Datenbank", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "TT.MM.JJJJ", + "DDGS Backend": "", "December": "Dezember", "Decrease UI Scale": "UI-Skalierung verringern", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "In Wissen eintauchen", "Do not install functions from sources you do not fully trust.": "Installieren Sie keine Funktionen aus nicht vertrauenswürdigen Quellen.", "Do not install tools from sources you do not fully trust.": "Installieren Sie keine Werkzeuge aus nicht vertrauenswürdigen Quellen.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "Docling-Parameter", "Docling Server URL required.": "Docling Server-URL erforderlich.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Dokumentenintelligenz-Endpunkt erforderlich.", "Document Intelligence Model": "Dokumentenintelligenz-Modell", "Documentation": "Dokumentation", - "Documents": "Dokumente", "does not make any external connections, and your data stays securely on your locally hosted server.": "stellt keine externen Verbindungen her; Ihre Daten bleiben sicher auf Ihrem lokalen Server.", "Domain Filter List": "Domain-Filterliste", "don't fetch random pipelines from sources you don't trust.": "Laden Sie keine Pipelines aus Quellen, denen Sie nicht vertrauen.", @@ -493,11 +502,14 @@ "Done": "Fertig", "Download": "Herunterladen", "Download & Delete": "Herunterladen & Löschen", + "Download as JSON": "", "Download as SVG": "Als SVG herunterladen", "Download canceled": "Download abgebrochen", "Download Database": "Datenbank herunterladen", + "Downloading stats...": "", "Draw": "Zeichnen", "Drop any files here to upload": "Dateien zum Hochladen hier ablegen", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "z. B. '30s', '10m'. Gültig: 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "z. B. \"json\" oder ein JSON-Schema", "e.g. 60": "z. B. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Bocha Search API-Schlüssel eingeben", "Enter Brave Search API Key": "Brave Search API-Schlüssel eingeben", "Enter certificate path": "Zertifikatpfad eingeben", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Chunk-Überlappung eingeben", "Enter Chunk Size": "Chunk-Größe eingeben", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Kommagetrennte \"token:bias_value\"-Paare eingeben (Bsp: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "URL für ext. Websuche", "Enter Firecrawl API Base URL": "Firecrawl API Basis-URL eingeben", "Enter Firecrawl API Key": "Firecrawl API-Schlüssel eingeben", + "Enter Firecrawl Timeout": "", "Enter folder name": "Ordnername eingeben", "Enter function name filter list (e.g. func1, !func2)": "Funktionsnamen-Filterliste eingeben (z. B. func1, !func2)", "Enter Github Raw URL": "Github Raw URL eingeben", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Hex-Farbe eingeben (z. B. #FF0000)", "Enter ID": "ID eingeben", "Enter Image Size (e.g. 512x512)": "Bildgröße eingeben (z. B. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina API-Schlüssel eingeben", "Enter JSON config (e.g., {\"disable_links\": true})": "JSON-Konfig eingeben (z. B. {\"disable_links\": true})", "Enter Jupyter Password": "Jupyter-Passwort eingeben", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search API-Schlüssel eingeben", "Enter Key Behavior": "Eingabetasten-Verhalten", "Enter language codes": "Sprachcodes eingeben", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Mistral API Basis-URL eingeben", "Enter Mistral API Key": "Mistral API-Schlüssel eingeben", "Enter Model ID": "Modell-ID eingeben", @@ -736,6 +753,7 @@ "Failed to generate title": "Titel konnte nicht generiert werden", "Failed to import models": "Modelle konnten nicht importiert werden", "Failed to load chat preview": "Chat-Vorschau konnte nicht geladen werden", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Dateiinhalt konnte nicht geladen werden.", "Failed to move chat": "Chat konnte nicht verschoben werden", "Failed to process URL: {{url}}": "{{url}} konnte nicht verarbeitet werden", @@ -752,10 +770,10 @@ "Features": "Funktionen", "Features Permissions": "Funktionsberechtigungen", "February": "Februar", + "Feedback": "", "Feedback deleted successfully": "Feedback erfolgreich gelöscht", "Feedback Details": "Feedback-Details", "Feedback History": "Feedback-Verlauf", - "Feedbacks": "Feedbacks", "Feel free to add specific details": "Fügen Sie gerne Details hinzu", "Female": "Weiblich", "File": "Datei", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingerabdruck-Spoofing erkannt: Initialen können nicht verwendet werden. Nutze Standard-Profilbild.", "Firecrawl API Base URL": "Firecrawl API Basis-URL", "Firecrawl API Key": "Firecrawl API-Schlüssel", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Schwebende Schnellaktionen", "Focus Chat Input": "Chat-Eingabe fokussieren", "Folder": "Ordner", "Folder Background Image": "Ordner-Hintergrundbild", "Folder deleted successfully": "Ordner erfolgreich gelöscht", + "Folder Max File Count": "", "Folder Name": "Ordnername", "Folder name cannot be empty.": "Ordnername darf nicht leer sein.", "Folder name updated successfully": "Ordnername erfolgreich aktualisiert", @@ -826,7 +846,6 @@ "General": "Allgemein", "Generate": "Generieren", "Generate an image": "Ein Bild generieren", - "Generate Image": "Bild generieren", "Generate Message Pair": "Nachrichtenpaar generieren", "Generated Image": "Generiertes Bild", "Generating search query": "Generiere Suchanfrage", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Loslegen mit {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Gute Antwort", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API-Schlüssel", "Google PSE Engine Id": "Google PSE Engine-ID", "Gravatar": "Gravatar", "Grid": "Raster", + "Grokipedia": "", "Group": "Gruppe", "Group Channel": "Gruppenkanal", "Group created successfully": "Gruppe erfolgreich erstellt", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Bild-Prompt-Generierung", "Image Prompt Generation Prompt": "Prompt für Bild-Prompt-Generierung", "Image Size": "Bildgröße", - "Images": "Bilder", "Import": "Importieren", "Import Chats": "Chats importieren", "Import Config from JSON File": "Konfiguration aus JSON importieren", @@ -927,6 +947,7 @@ "Integration": "Integration", "Integrations": "Integrationen", "Interface": "Benutzeroberfläche", + "Interface Settings Access": "", "Invalid file content": "Ungültiger Dateiinhalt", "Invalid file format.": "Ungültiges Dateiformat.", "Invalid JSON file": "Ungültige JSON-Datei", @@ -940,6 +961,7 @@ "is typing...": "schreibt ...", "Italic": "Kursiv", "January": "Januar", + "Jina API Base URL": "", "Jina API Key": "Jina-API-Schlüssel", "join our Discord for help.": "Treten Sie unserem Discord bei, um Hilfe zu erhalten.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Leer lassen, um alle Modelle vom Endpunkt \"{{url}}/api/tags\" einzuschließen", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Leer lassen, um alle Modelle vom Endpunkt \"{{url}}/models\" einzuschließen", "Leave empty to include all models or select specific models": "Leer lassen, um alle Modelle einzuschließen oder spezifische Modelle auszuwählen", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Leer lassen, um das Standardmodell zu nutzen (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Leer lassen, um den Standard-Prompt zu verwenden, oder geben Sie einen eigenen Prompt ein", "Leave model field empty to use the default model.": "Leer lassen, um das Standardmodell zu verwenden.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Verwalten Sie Ihre Kontoinformationen.", "March": "März", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (Überschrift)", + "Markdown Header Text Splitter": "", "Max Speakers": "Max. Sprecher", "Max Upload Count": "Max. Anzahl Uploads", "Max Upload Size": "Max. Uploadgröße", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es können maximal 3 Modelle gleichzeitig heruntergeladen werden. Bitte versuchen Sie es später erneut.", "May": "Mai", "MBR": "MBR", @@ -1042,6 +1067,7 @@ "Member removed successfully": "Mitglied erfolgreich entfernt", "Members": "Mitglieder", "Members added successfully": "Mitglieder erfolgreich hinzugefügt", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Erinnerungen, auf die LLMs zugreifen können, werden hier angezeigt.", "Memory": "Erinnerungen", "Memory added successfully": "Erinnerung erfolgreich hinzugefügt", @@ -1051,6 +1077,7 @@ "Merge Responses": "Antworten zusammenführen", "Merged Response": "Zusammengeführte Antwort", "Message": "Nachricht", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Nachrichtenbewertung muss aktiviert sein, um diese Funktion zu nutzen", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Nachrichten, die Sie nach dem Erstellen des Links senden, werden nicht geteilt. Benutzer mit der URL können nur den bis dahin geteilten Chat sehen.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Modellname", "Model name already exists, please choose a different one": "Modellname existiert bereits, bitte wählen Sie einen anderen", "Model Name is required.": "Modellname ist erforderlich.", + "Model names and usage frequency": "", "Model not selected": "Kein Modell ausgewählt", "Model Params": "Modell-Parameter", "Model Permissions": "Modellberechtigungen", + "Model responses or outputs": "", "Model unloaded successfully": "Modell erfolgreich entladen", "Model updated successfully": "Modell erfolgreich aktualisiert", "Model(s) do not support file upload": "Modell(e) unterstützen keinen Dateiupload", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Modelle erfolgreich importiert", "Models Public Sharing": "Öffentliche Freigabe von Modellen", "Models Sharing": "Modelle teilen", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API-Schlüssel", "More": "Mehr", "More Concise": "Kürzer", @@ -1129,7 +1159,7 @@ "No conversation to save": "Keine Unterhaltung zum Speichern vorhanden", "No distance available": "Keine Distanz verfügbar", "No expiration can pose security risks.": "Ein fehlendes Ablaufdatum kann Sicherheitsrisiken bergen.", - "No feedbacks found": "Kein Feedback gefunden", + "No feedback found": "", "No file selected": "Keine Datei ausgewählt", "No files in this knowledge base.": "Keine Dateien in diesem Wissensspeicher", "No functions found": "Keine Funktionen gefunden", @@ -1144,6 +1174,7 @@ "No models selected": "Keine Modelle ausgewählt", "No Notes": "Keine Notizen", "No notes found": "Keine Notizen gefunden", + "No one": "", "No pinned messages": "Keine angehefteten Nachrichten", "No prompts found": "Keine Prompts gefunden", "No results": "Keine Ergebnisse", @@ -1195,6 +1226,7 @@ "Only invited users can access": "Nur eingeladene Benutzer haben Zugriff", "Only markdown files are allowed": "Nur Markdown-Dateien sind erlaubt", "Only select users and groups with permission can access": "Nur ausgewählte Benutzer und Gruppen mit Berechtigung haben Zugriff", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Die URL scheint ungültig zu sein. Bitte überprüfen Sie diese und versuchen Sie es erneut.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ups! Es werden noch Dateien hochgeladen. Bitte warten Sie, bis der Upload abgeschlossen ist.", "Oops! There was an error in the previous response.": "Ups! Es gab einen Fehler in der vorherigen Antwort.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI kann Werkzeuge verwenden, die von jedem OpenAPI-Server bereitgestellt werden.", "Open WebUI uses faster-whisper internally.": "Open WebUI verwendet intern faster-whisper.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI verwendet SpeechT5 und CMU Arctic Speaker-Embeddings.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Die installierte Open-WebUI-Version (v{{OPEN_WEBUI_VERSION}}) ist niedriger als die erforderliche Version (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI-API", @@ -1235,6 +1268,8 @@ "page": "Seite", "Paginate": "Paginieren", "Parameters": "Parameter", + "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.": "", "Password": "Passwort", "Passwords do not match.": "Die Passwörter stimmen nicht überein.", "Paste Large Text as File": "Großen Text als Datei einfügen", @@ -1260,7 +1295,6 @@ "Pipe": "Pipe", "Pipeline deleted successfully": "Pipeline erfolgreich gelöscht", "Pipeline downloaded successfully": "Pipeline erfolgreich heruntergeladen", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines sind ein Plugin-System mit beliebiger Codeausführung —", "Pipelines Not Detected": "Keine Pipelines erkannt", "Pipelines Valves": "Pipeline-Valves", @@ -1498,6 +1532,7 @@ "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.": "Legt die zu verwendenden Stoppsequenzen fest. Wenn dieses Muster erkannt wird, stoppt das LLM die Textgenerierung. Mehrere Stoppmuster können durch separate Stopp-Parameter in einer Modelldatei angegeben werden.", "Setting": "Einstellung", "Settings": "Einstellungen", + "Settings Permissions": "", "Settings saved successfully!": "Einstellungen erfolgreich gespeichert!", "Share": "Teilen", "Share Chat": "Chat teilen", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Spracherkennungsfehler: {{error}}", "Speech-to-Text": "Sprache-zu-Text", "Speech-to-Text Engine": "Sprache-zu-Text-Engine", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Neue Unterhaltung beginnen", "Start of the channel": "Beginn des Kanals", "Start Tag": "Start-Tag", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Schritte", "Stop": "Stopp", + "Stop Download": "", "Stop Generating": "Generierung stoppen", "Stop Sequence": "Stoppsequenz", "Stream Chat Response": "Chat-Antwort streamen", @@ -1571,7 +1608,14 @@ "Support": "Unterstützung", "Support this plugin:": "Unterstützen Sie dieses Plugin:", "Supported MIME Types": "Unterstützte MIME-Typen", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Verzeichnis synchronisieren", + "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", "System Instructions": "Systemanweisungen", "System Prompt": "System-Prompt", @@ -1616,6 +1660,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "Die Gewichtung der BM25-Hybridsuche. 0 ist semantischer, 1 ist lexikalischer. Standard ist 0.5.", "The width in pixels to compress images to. Leave empty for no compression.": "Die Breite in Pixeln, auf die Bilder komprimiert werden sollen. Leer lassen für keine Kompression.", "Theme": "Design", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Denke nach...", "This action cannot be undone. Do you wish to continue?": "Diese Aktion kann nicht rückgängig gemacht werden. Möchten Sie fortfahren?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Dieser Kanal wurde am {{createdAt}} erstellt. Dies ist der Anfang des Kanals {{channelName}}.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Pipeline hochladen", "Upload Progress": "Upload-Fortschritt", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Fortschritt: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "Datei wird hochgeladen...", "URL": "URL", "URL is required": "URL ist erforderlich", @@ -1747,6 +1793,7 @@ "User Groups": "Benutzergruppen", "User location successfully retrieved.": "Benutzerstandort erfolgreich abgerufen.", "User menu": "Benutzermenü", + "User ratings (thumbs up/down)": "", "User Webhooks": "Benutzer-Webhooks", "Username": "Benutzername", "users": "Benutzer", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI wird Anfragen an \"{{url}}/chat/completions\" senden", "What are you trying to achieve?": "Was möchten Sie erreichen?", "What are you working on?": "Woran arbeiten Sie?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Neuigkeiten in", "What's on your mind?": "Was beschäftigt Sie?", "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.": "Wenn aktiviert, antwortet das Modell in Echtzeit auf jede Chat-Nachricht. Dieser Modus ist nützlich für Live-Chats, kann jedoch die Leistung auf langsamerer Hardware beeinträchtigen.", "wherever you are": "wo immer Sie sind", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Ob die Ausgabe paginiert werden soll. Jede Seite wird durch eine horizontale Linie und Seitennummer getrennt. Standard ist False.", "Whisper (Local)": "Whisper (Lokal)", + "Who can share to this group": "", "Why?": "Warum?", "Widescreen Mode": "Breitbildmodus", "Width": "Breite", + "Wikipedia": "", "Won": "Gewonnen", "Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text.": "Funktioniert zusammen mit Top-K. Ein höherer Wert (z. B. 0.95) führt zu vielfältigerem Text, während ein niedrigerer Wert (z. B. 0.5) fokussierteren und konservativeren Text erzeugt.", "Workspace": "Arbeitsbereich", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy-Instanz-URL", "Yacy Password": "Yacy-Passwort", "Yacy Username": "Yacy-Benutzername", + "Yahoo": "", + "Yandex": "", "Yesterday": "Gestern", "Yesterday at {{LOCALIZED_TIME}}": "Gestern um {{LOCALIZED_TIME}}", "You": "Du", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Sie können mit maximal {{maxCount}} Datei(en) gleichzeitig chatten.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Sie können Interaktionen mit LLMs personalisieren, indem Sie über die Schaltfläche \"Verwalten\" Erinnerungen hinzufügen.", "You cannot upload an empty file.": "Sie können keine leere Datei hochladen.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "Sie haben keine Berechtigung, Nachrichten in diesem Kanal zu senden.", "You do not have permission to send messages in this thread.": "Sie haben keine Berechtigung, Nachrichten in diesem Thread zu senden.", "You do not have permission to upload files to this knowledge base.": "Sie haben keine Berechtigung, Dateien in diese Wissensspeicher hochzuladen.", @@ -1834,6 +1890,8 @@ "Your Account": "Ihr Konto", "Your account status is currently pending activation.": "Ihr Kontostatus wartet derzeit auf Aktivierung.", "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.": "Ihr gesamter Beitrag geht direkt an den Plugin-Entwickler; Open WebUI behält keinen Anteil ein. Die gewählte Plattform kann jedoch eigene Gebühren erheben.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "YouTube-Sprache", "Youtube Proxy URL": "YouTube-Proxy-URL" diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index 35979c1b0f..b937b2dac6 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Adjusting these settings will apply changes to all users. Such universal, very wow.", "admin": "admin", "Admin": "", + "Admin Contact Email": "", "Admin Panel": "Admin Panel", "Admin Settings": "Admin Settings", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "", "Android": "", + "Anyone": "", "API Base URL": "API Base URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API Key", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Copy Bark Auto Bark", "Auto-playback response": "Auto-playback response", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Base URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Base URL is required.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "such available users", @@ -201,6 +204,7 @@ "before": "", "Being lazy": "", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Check for updates", "Checking for updates...": "Checking for updates... Such anticipation...", "Choose a model before saving...": "Choose model before saving... Wow choose first.", + "Chunk Min Size Target": "", "Chunk Overlap": "Chunk Overlap", "Chunk Size": "Chunk Size", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "Content", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Database", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "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.": "does not connect external, data stays safe locally.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "don't fetch random pipelines from sources you don't trust, much wow.", @@ -493,11 +502,14 @@ "Done": "", "Download": "", "Download & Delete": "Download & delete wow", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "", "Download Database": "Download Database", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "e.g. '30s','10m'. Much time units are 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Enter Overlap of Chunks", "Enter Chunk Size": "Enter Size of Chunk", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Enter Size of Wow (e.g. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingerprint dogeing: Unable to use initials as avatar. Defaulting to default doge image.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Woweral", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "", + "Google": "", "Google Drive": "", "Google PSE API Key": "", "Google PSE Engine Id": "", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Much group", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Wowmages", "Import": "", "Import Chats": "Import Barks", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Interface", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "join our Discord for help.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximum of 3 models can be downloaded simultaneously. Please try again later.", "May": "", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "", "Memory": "", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model not selected", "Model Params": "", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "No results, very empty", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Looks like the URL is invalid. Please double-check and try again.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Barkword", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines be plugin system, run code arbitrary — much wow", "Pipelines Not Detected": "", "Pipelines Valves": "", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "Settings much settings", + "Settings Permissions": "", "Settings saved successfully!": "Settings saved successfully! Very success!", "Share": "", "Share Chat": "", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Speech recognition error: {{error}} so error", "Speech-to-Text": "", "Speech-to-Text Engine": "Speech-to-Text Engine much speak", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Start of channel", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Stop Sequence much stop", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "System very system", "System Instructions": "", "System Prompt": "System Prompt much prompt", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Theme much theme", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "Upload Progress much progress", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "What's New in much new", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/el-GR/translation.json b/src/lib/i18n/locales/el-GR/translation.json index 1265bed194..daa4a219b3 100644 --- a/src/lib/i18n/locales/el-GR/translation.json +++ b/src/lib/i18n/locales/el-GR/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Η ρύθμιση αυτών των παραμέτρων θα εφαρμόσει τις αλλαγές καθολικά σε όλους τους χρήστες.", "admin": "διαχειριστής", "Admin": "Διαχειριστής", + "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.": "Οι διαχειριστές έχουν πρόσβαση σε όλα τα εργαλεία ανά πάσα στιγμή· οι χρήστες χρειάζονται εργαλεία ανά μοντέλο στον χώρο εργασίας.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Επιτρέπεται η Συνέχιση Απάντησης", "Allow Delete Messages": "Επιτρέπεται η διαγραφή μηνυμάτων", "Allow File Upload": "Επιτρέπεται το Ανέβασμα Αρχείων", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Επιτρέπεται η χρήση πολλαπλών μοντέλων στη συνομιλία", "Allow non-local voices": "Επιτρέπονται μη τοπικές φωνές", "Allow Rate Response": "Επιτρέπεται η Αξιολόγηση Απάντησης", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "και {{COUNT}} ακόμα", "and create a new shared link.": "και δημιουργήστε έναν νέο κοινόχρηστο σύνδεσμο.", "Android": "", + "Anyone": "", "API Base URL": "Βασικό URL API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Κλειδί API", @@ -175,6 +176,7 @@ "Authenticate": "Επαλήθευση", "Authentication": "Ταυτοποίηση", "Auto": "Αυτόματο", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Αυτόματη Αντιγραφή Απάντησης στο Πρόχειρο", "Auto-playback response": "Αυτόματη αναπαραγωγή της απάντησης", "Autocomplete Generation": "Δημιουργία Αυτόματης Συμπλήρωσης", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Σειρά Επαλήθευσης API AUTOMATIC1111", "AUTOMATIC1111 Base URL": "Βασικό URL AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Απαιτείται το Βασικό URL AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Διαθέσιμη λίστα", "Available Tools": "Διαθέσιμα Εργαλεία", "available users": "διαθέσιμοι χρήστες", @@ -201,6 +204,7 @@ "before": "πριν", "Being lazy": "Τρώλακας", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "Τέλος Bing Search V7", "Bing Search V7 Subscription Key": "Κλειδί Συνδρομής Bing Search V7", "Bio": "Βιογραφικό", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Κλειδί API Brave Search", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Έλεγχος για ενημερώσεις", "Checking for updates...": "Ελέγχεται για ενημερώσεις...", "Choose a model before saving...": "Επιλέξτε ένα μοντέλο πριν αποθηκεύσετε...", + "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.": "", "Ciphers": "Κρυπτογραφήσεις", "Citation": "Παραπομπή", "Citations": "Παραπομπές", @@ -293,7 +301,6 @@ "Code Block": "Μπλοκ Κώδικα", "Code Editor": "", "Code execution": "Εκτέλεση κώδικα", - "Code Execution": "Εκτέλεση Κώδικα", "Code Execution Engine": "Μηχανή Εκτέλεσης Κώδικα", "Code Execution Timeout": "Χρονικό Όριο Εκτέλεσης Κώδικα", "Code formatted successfully": "Ο κώδικας μορφοποιήθηκε επιτυχώς", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Επικοινωνήστε με τον Διαχειριστή για Πρόσβαση στο WebUI", "Content": "Περιεχόμενο", "Content Extraction Engine": "Μηχανή Εξαγωγής Περιεχομένου", + "Content lengths (character counts only)": "", "Continue Response": "Συνέχεια Απάντησης", "Continue with {{provider}}": "Συνέχεια με {{provider}}", "Continue with Email": "Συνέχεια με Email", @@ -393,6 +401,7 @@ "Database": "Βάση Δεδομένων", "Datalab Marker API": "", "DD/MM/YYYY": "ΗΗ/ΜΜ/ΕΕΕΕ", + "DDGS Backend": "", "December": "Δεκέμβριος", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "Απαιτείται το URL του διακομιστή Docling.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Απαιτείται το endpoint του Document Intelligence.", "Document Intelligence Model": "", "Documentation": "Τεκμηρίωση", - "Documents": "Έγγραφα", "does not make any external connections, and your data stays securely on your locally hosted server.": "δεν κάνει καμία εξωτερική σύνδεση, και τα δεδομένα σας παραμένουν ασφαλή στον τοπικά φιλοξενούμενο διακομιστή σας.", "Domain Filter List": "Λίστα Φίλτρων Domain", "don't fetch random pipelines from sources you don't trust.": "Μην ανακτάτε τυχαία pipelines από μη αξιόπιστες πηγές.", @@ -493,11 +502,14 @@ "Done": "Έτοιμο", "Download": "Λήψη", "Download & Delete": "Λήψη & Διαγραφή", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Η λήψη ακυρώθηκε", "Download Database": "Λήψη Βάσης Δεδομένων", + "Downloading stats...": "", "Draw": "Σχεδίαση", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "π.χ. '30s','10m'. Οι έγκυρες μονάδες χρόνου είναι 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "π.χ. \"json\" ή ένα JSON σχήμα", "e.g. 60": "π.χ. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Εισάγετε το Κλειδί API Brave Search", "Enter certificate path": "Εισάγετε τη διαδρομή πιστοποιητικού", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Εισάγετε την Επικάλυψη Τμημάτων", "Enter Chunk Size": "Εισάγετε το Μέγεθος Τμημάτων", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Εισάγετε το Github Raw URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "Εισάγετε ID", "Enter Image Size (e.g. 512x512)": "Εισάγετε το Μέγεθος Εικόνας (π.χ. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Εισάγετε το Κλειδί API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Εισάγετε Κωδικό Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Εισάγετε κωδικούς γλώσσας", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Εισάγετε το ID Μοντέλου", @@ -736,6 +753,7 @@ "Failed to generate title": "Αποτυχία δημιουργίας τίτλου", "Failed to import models": "Αποτυχία εισαγωγής μοντέλων", "Failed to load chat preview": "Αποτυχία φόρτωσης προεπισκόπησης συνομιλίας", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Αποτυχία φόρτωσης περιεχομένου αρχείου", "Failed to move chat": "Αποτυχία μετακίνησης συνομιλίας", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Λειτουργίες", "Features Permissions": "", "February": "Φεβρουάριος", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Ιστορικό Ανατροφοδότησης", - "Feedbacks": "Ανατροφοδοτήσεις", "Feel free to add specific details": "Νιώστε ελεύθεροι να προσθέσετε συγκεκριμένες λεπτομέρειες", "Female": "Γυναίκα", "File": "Αρχείο", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Εντοπίστηκε spoofing δακτυλικού αποτυπώματος: Αδυναμία χρήσης αρχικών ως avatar. Χρήση της προεπιλεγμένης εικόνας προφίλ.", "Firecrawl API Base URL": "URL του API του Firecrawl", "Firecrawl API Key": "API κλειδί του Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "Φάκελος", "Folder Background Image": "Εικόνα Φόντου Φακέλου", "Folder deleted successfully": "Ο φάκελος διαγράφηκε με επιτυχία", + "Folder Max File Count": "", "Folder Name": "Όνομα Φακέλου", "Folder name cannot be empty.": "Το όνομα του φακέλου δεν μπορεί να είναι κενό.", "Folder name updated successfully": "Το όνομα του φακέλου ενημερώθηκε με επιτυχία", @@ -826,7 +846,6 @@ "General": "Γενικά", "Generate": "Δημιουργία", "Generate an image": "Δημιουργία εικόνας", - "Generate Image": "Δημιουργία Εικόνας", "Generate Message Pair": "", "Generated Image": "Δημιουργημένη Εικόνα", "Generating search query": "Γενιά αναζήτησης ερώτησης", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Ξεκινήστε με {{WEBUI_NAME}}", "Global": "Καθολικό", "Good Response": "Καλή Απάντηση", + "Google": "", "Google Drive": "", "Google PSE API Key": "Κλειδί API Google PSE", "Google PSE Engine Id": "Αναγνωριστικό Μηχανής Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Ομάδα", "Group Channel": "", "Group created successfully": "Η ομάδα δημιουργήθηκε με επιτυχία", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Προτροπή Δημιουργίας Εικόνας", "Image Prompt Generation Prompt": "Προτροπή Δημιουργίας Εικόνας", "Image Size": "", - "Images": "Εικόνες", "Import": "Εισαγωγή", "Import Chats": "Εισαγωγή Συνομιλιών", "Import Config from JSON File": "Εισαγωγή Διαμόρφωσης από Αρχείο JSON", @@ -927,6 +947,7 @@ "Integration": "Ενσωμάτωση", "Integrations": "Ενσωματώσεις", "Interface": "Διεπαφή Χρήστη", + "Interface Settings Access": "", "Invalid file content": "Μη έγκυρο περιεχόμενο αρχείου", "Invalid file format.": "Μη έγκυρη μορφή αρχείου.", "Invalid JSON file": "Μη έγκυρο αρχείο JSON", @@ -940,6 +961,7 @@ "is typing...": "πληκτρολογεί...", "Italic": "", "January": "Ιανουάριος", + "Jina API Base URL": "", "Jina API Key": "Κλειδί API Jina", "join our Discord for help.": "συμμετέχετε στο Discord μας για βοήθεια.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Αφήστε κενό για να χρησιμοποιήσετε όλα τα μοντέλα από το endpoint \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Αφήστε κενό για να χρησιμοποιήσετε όλα τα μοντέλα από το 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 model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Αφήστε κενό για να χρησιμοποιήσετε την προεπιλεγμένη προτροπή, ή εισάγετε μια προσαρμοσμένη προτροπή", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Διαχειριστείτε τις πληροφορίες του λογαριασμού σας.", "March": "Μάρτιος", "Markdown": "", - "Markdown (Header)": "Markdown (Επικεφαλίδα)", + "Markdown Header Text Splitter": "", "Max Speakers": "Μέγιστο Πλήθος Ομιλητών", "Max Upload Count": "Μέγιστος Αριθμός Ανεβάσματος", "Max Upload Size": "Μέγιστο Μέγεθος Αρχείου", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Μέγιστο των 3 μοντέλων μπορούν να κατεβούν ταυτόχρονα. Παρακαλώ δοκιμάστε ξανά αργότερα.", "May": "Μάιος", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Οι αναμνήσεις προσβάσιμες από τα LLMs θα εμφανιστούν εδώ.", "Memory": "Μνήμη", "Memory added successfully": "Η μνήμη προστέθηκε με επιτυχία", @@ -1051,6 +1077,7 @@ "Merge Responses": "Συγχώνευση Απαντήσεων", "Merged Response": "Συγχωνευμένη απάντηση", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Η αξιολόγηση μηνυμάτων πρέπει να είναι ενεργοποιημένη για να χρησιμοποιήσετε αυτή τη λειτουργία", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "Όνομα Μοντέλου", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Το μοντέλο δεν έχει επιλεγεί", "Model Params": "Παράμετροι Μοντέλου", "Model Permissions": "Δικαιώματα Μοντέλου", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Το μοντέλο ενημερώθηκε με επιτυχία", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Κλειδί API Mojeek Search", "More": "Περισσότερα", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Δεν υπάρχει διαθέσιμη απόσταση", "No expiration can pose security risks.": "", - "No feedbacks found": "Δεν βρέθηκαν ανατροφοδοτήσεις", + "No feedback found": "", "No file selected": "Δεν έχει επιλεγεί αρχείο", "No files in this knowledge base.": "", "No functions found": "Δεν βρέθηκαν λειτουργίες", @@ -1144,6 +1174,7 @@ "No models selected": "Δεν έχουν επιλεγεί μοντέλα", "No Notes": "", "No notes found": "Δεν βρέθηκαν σημειώσεις", + "No one": "", "No pinned messages": "", "No prompts found": "Δεν βρέθηκαν προτροπές", "No results": "Δεν βρέθηκαν αποτελέσματα", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Μόνο επιλεγμένοι χρήστες και ομάδες με άδεια μπορούν να έχουν πρόσβαση", + "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.": "Ωχ! Υπήρξε σφάλμα στην προηγούμενη απάντηση.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Το Open WebUI χρησιμοποιεί το faster-whisper εσωτερικά.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Το Open WebUI χρησιμοποιεί τα SpeechT5 και CMU Arctic ενσωματώσεων ομιλητών.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Η έκδοση Open WebUI (v{{OPEN_WEBUI_VERSION}}) είναι χαμηλότερη από την απαιτούμενη έκδοση (v{{REQUIRED_VERSION}})", "OpenAI": "", "OpenAI API": "", @@ -1235,6 +1268,8 @@ "page": "σελίδα", "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.": "", "Password": "Κωδικός", "Passwords do not match.": "Οι κωδικοί δεν ταιριάζουν", "Paste Large Text as File": "Επικόλληση Μεγάλου Κειμένου ως Αρχείο", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Η συνάρτηση διαγράφηκε με επιτυχία", "Pipeline downloaded successfully": "Η συνάρτηση κατεβλήθηκε με επιτυχία", - "Pipelines": "Αγωγοί", "Pipelines are a plugin system with arbitrary code execution —": "Το Pipelines είναι ένα σύστημα προσθέτων με αυθαίρετη εκτέλεση κώδικα —", "Pipelines Not Detected": "Δεν Εντοπίστηκαν Αγωγοί", "Pipelines Valves": "Βαλβίδες Αγωγών", @@ -1498,6 +1532,7 @@ "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 saved successfully!": "Οι Ρυθμίσεις αποθηκεύτηκαν με επιτυχία!", "Share": "Κοινή Χρήση", "Share Chat": "Κοινή Χρήση Συνομιλίας", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Σφάλμα αναγνώρισης ομιλίας: {{error}}", "Speech-to-Text": "Ομιλία σε Κείμενο", "Speech-to-Text Engine": "Μηχανή Ομιλίας σε Κείμενο", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Αρχή του καναλιού", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Σταμάτημα", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Σειρά Παύσης", "Stream Chat Response": "Ροή Δεδομένων Απαντήσεων", @@ -1571,7 +1608,14 @@ "Support": "Υποστήριξη", "Support this plugin:": "Υποστήριξη αυτού του plugin:", "Supported MIME Types": "Υποστηριζόμενοι τύποι MIME", + "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.": "", "System": "Σύστημα", "System Instructions": "Οδηγίες Συστήματος", "System Prompt": "Προτροπή Συστήματος", @@ -1616,6 +1660,7 @@ "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.": "Το πλάτος σε πίξελ για συμπίεση εικόνων. Αφήστε κενό για να μην υπάρχει συμπίεση.", "Theme": "Θέμα", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Ανέβασμα Pipeline", "Upload Progress": "Πρόοδος Ανεβάσματος", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "Το URL είναι απαραίτητο", @@ -1747,6 +1793,7 @@ "User Groups": "Ομάδες Χρηστών", "User location successfully retrieved.": "Η τοποθεσία του χρήστη ανακτήθηκε με επιτυχία.", "User menu": "Μενού Χρήστη", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooks Χρήστη", "Username": "Όνομα Χρήστη", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "Το WebUI θα κάνει αιτήματα στο \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Τι προσπαθείτε να πετύχετε?", "What are you working on?": "Τι εργάζεστε;", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Τι νέο υπάρχει στο", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (Τοπικό)", + "Who can share to this group": "", "Why?": "Γιατί?", "Widescreen Mode": "Λειτουργία Οθόνης Ευρείας", "Width": "Πλάτος", + "Wikipedia": "", "Won": "Κέρδισε", "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.": "", "Workspace": "Χώρος Εργασίας", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "Κωδικός Yacy", "Yacy Username": "Όνομα χρήστη Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Εχθές", "Yesterday at {{LOCALIZED_TIME}}": "Εχθές στις {{LOCALIZED_TIME}}", "You": "Εσείς", @@ -1823,6 +1876,9 @@ "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.": "Μπορείτε να προσωποποιήσετε τις αλληλεπιδράσεις σας με τα LLMs προσθέτοντας αναμνήσεις μέσω του κουμπιού 'Διαχείριση' παρακάτω, κάνοντάς τα πιο χρήσιμα και προσαρμοσμένα σε εσάς.", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Ο λογαριασμός σας", "Your account status is currently pending activation.": "Η κατάσταση του λογαριασμού σας είναι αυτή τη στιγμή σε εκκρεμότητα ενεργοποίησης.", "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.": "Η ολόκληρη η συνεισφορά σας θα πάει απευθείας στον προγραμματιστή του plugin· το Open WebUI δεν παίρνει κανένα ποσοστό. Ωστόσο, η επιλεγμένη πλατφόρμα χρηματοδότησης μπορεί να έχει τα δικά της τέλη.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Γλώσσα YouTube", "Youtube Proxy URL": "URL Διακομιστή Μεσολάβησης YouTube" diff --git a/src/lib/i18n/locales/en-GB/translation.json b/src/lib/i18n/locales/en-GB/translation.json index be4667dfd1..582945bf0d 100644 --- a/src/lib/i18n/locales/en-GB/translation.json +++ b/src/lib/i18n/locales/en-GB/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "", "admin": "", "Admin": "", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "", "Android": "", + "Anyone": "", "API Base URL": "", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "", "Auto-playback response": "", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "", "AUTOMATIC1111 Base URL is required.": "", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "", @@ -201,6 +204,7 @@ "before": "", "Being lazy": "", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Boosting or penalising specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)", + "Brave": "", "Brave Search API Key": "", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "", "Checking for updates...": "", "Choose a model before saving...": "", + "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.": "", "Ciphers": "", "Citation": "", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "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.": "", @@ -493,11 +502,14 @@ "Done": "", "Download": "", "Download & Delete": "", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "", "Download Database": "", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "", "Enter Chunk Size": "", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "Enter Key Behaviour", "Enter language codes": "", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "", + "Google": "", "Google Drive": "", "Google PSE API Key": "", "Google PSE Engine Id": "", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "", "Import": "", "Import Chats": "", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "", "JSON": "", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "", "May": "", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "", "Memory": "", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "", "Model Params": "", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "", "OpenAI API": "", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "", "Pipelines are a plugin system with arbitrary code execution —": "", "Pipelines Not Detected": "", "Pipelines Valves": "", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "", + "Settings Permissions": "", "Settings saved successfully!": "", "Share": "", "Share Chat": "", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "", "Speech-to-Text": "", "Speech-to-Text Engine": "", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "", "System Instructions": "", "System Prompt": "", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "You can personalise your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index 98f3bbf79f..10a3b6d965 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "", "admin": "", "Admin": "", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "", "Android": "", + "Anyone": "", "API Base URL": "", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "", "Auto-playback response": "", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "", "AUTOMATIC1111 Base URL is required.": "", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "", @@ -201,6 +204,7 @@ "before": "", "Being lazy": "", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "", "Checking for updates...": "", "Choose a model before saving...": "", + "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.": "", "Ciphers": "", "Citation": "", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "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.": "", @@ -493,11 +502,14 @@ "Done": "", "Download": "", "Download & Delete": "", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "", "Download Database": "", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "", "Enter Chunk Size": "", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -756,7 +774,6 @@ "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "", "Female": "", "File": "", @@ -777,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -827,7 +846,6 @@ "General": "", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "Generated Image", "Generating search query": "", @@ -837,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "", + "Google": "", "Google Drive": "", "Google PSE API Key": "", "Google PSE Engine Id": "", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "", "Group Channel": "", "Group created successfully": "", @@ -896,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "", "Import": "", "Import Chats": "", "Import Config from JSON File": "", @@ -928,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -941,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "", "JSON": "", @@ -991,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1030,10 +1052,12 @@ "Manage your account information.": "", "March": "", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "", "May": "", "MBR": "", @@ -1043,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "", "Memory": "", "Memory added successfully": "", @@ -1052,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "", "Microsoft OneDrive": "", @@ -1084,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "", "Model Params": "", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1097,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "", "More Concise": "", @@ -1130,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1145,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "", @@ -1196,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1212,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "", "OpenAI API": "", @@ -1236,6 +1268,8 @@ "page": "", "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.": "", "Password": "", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1261,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "", "Pipelines are a plugin system with arbitrary code execution —": "", "Pipelines Not Detected": "", "Pipelines Valves": "", @@ -1499,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "", + "Settings Permissions": "", "Settings saved successfully!": "", "Share": "", "Share Chat": "", @@ -1542,6 +1576,7 @@ "Speech recognition error: {{error}}": "", "Speech-to-Text": "", "Speech-to-Text Engine": "", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "", "Start Tag": "", @@ -1552,6 +1587,7 @@ "STDOUT/STDERR": "", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "", "Stream Chat Response": "", @@ -1572,7 +1608,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "", "System Instructions": "", "System Prompt": "", @@ -1617,6 +1660,7 @@ "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.": "", "Theme": "", + "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.": "", @@ -1731,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1748,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1797,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "", @@ -1817,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "", @@ -1824,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1835,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index b8c18ee124..3e42ac9e50 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "El ajuste de estas opciones se aplicará globalmente a todos los usuarios.", "admin": "admin", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Administración", "Admin Settings": "Ajustes de Admin", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Los administradores tienen acceso a todas las herramientas en todo momento; los usuarios necesitan que los modelos tengan asignadas las herramientas en el area de trabajo.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Permitir Continuar Respuesta", "Allow Delete Messages": "Permitir Borrar Mensajes", "Allow File Upload": "Permitir Subida de Archivos", - "Allow Group Sharing": "Permitir Compartir en Grupo", "Allow Multiple Models in Chat": "Permitir Chat con Múltiples Modelos", "Allow non-local voices": "Permitir voces no locales", "Allow Rate Response": "Permitir Calificar Respuesta", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "y {{COUNT}} más", "and create a new shared link.": "y crear un nuevo enlace compartido.", "Android": "Android", + "Anyone": "", "API Base URL": "URL Base API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "URL Base API para Datalab Marker service. La Predeterminada es: https://www.datalab.to/api/v1/marker", "API Key": "Clave API ", @@ -175,6 +176,7 @@ "Authenticate": "Autentificar", "Authentication": "Autenticación", "Auto": "Auto", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "AutoCopiado de respuesta al Portapapeles", "Auto-playback response": "Reproducir Respuesta automáticamente", "Autocomplete Generation": "Generación de Autocompletado", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Auth API para AUTOMATIC1111", "AUTOMATIC1111 Base URL": "URL Base de AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "la URL Base de AUTOMATIC1111 es necesaria.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Lista disponible", "Available Tools": "Herramientas Disponibles", "available users": "usuarios disponibles", @@ -201,6 +204,7 @@ "before": "antes", "Being lazy": "Ser perezoso", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Endpoint de Bing Search V7", "Bing Search V7 Subscription Key": "Clave de Suscripción de Bing Search V7", "Bio": "Bio", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Clave API de Bocha Search", "Bold": "Negrita", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Impulsando o penalizando tokens específicos para respuestas restringidas. Los valores de sesgo se limitarán entre -100 y 100 (inclusive). (Por defecto: ninguno)", + "Brave": "", "Brave Search API Key": "Clave API de Brave Search", + "Builtin Tools": "", "Bullet List": "Lista de Viñetas", "Button ID": "ID del Botón", "Button Label": "Etiqueta del Botón", @@ -256,8 +262,10 @@ "Check for updates": "Buscar actualizaciones", "Checking for updates...": "Buscando actualizaciones...", "Choose a model before saving...": "Escoge un modelo antes de guardar...", + "Chunk Min Size Target": "", "Chunk Overlap": "Superposición de Fragmentos", "Chunk Size": "Tamaño de los Fragmentos", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Cifrado", "Citation": "Cita", "Citations": "Citas", @@ -293,7 +301,6 @@ "Code Block": "Bloque de Código", "Code Editor": "Editor de Código", "Code execution": "Ejecución de Código", - "Code Execution": "Ejecución de Código", "Code Execution Engine": "Motor de Ejecución de Código", "Code Execution Timeout": "Tiempo límite de espera para Ejecución de Código", "Code formatted successfully": "El codigo se ha formateado correctamente.", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contacta con Admin para obtener acceso a WebUI", "Content": "Contenido", "Content Extraction Engine": "Motor para la Extracción de Contenido", + "Content lengths (character counts only)": "", "Continue Response": "Continuar Respuesta", "Continue with {{provider}}": "Continuar con {{provider}}", "Continue with Email": "Continuar con Email", @@ -393,6 +401,7 @@ "Database": "Base de datos", "Datalab Marker API": "API de Datalab Marker", "DD/MM/YYYY": "DD/MM/YYYY", + "DDGS Backend": "", "December": "Diciembre", "Decrease UI Scale": "Reducir la Escala de la IU", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Sumérgete en el conocimiento", "Do not install functions from sources you do not fully trust.": "¡No instalar funciones de fuentes en las que que no se confíe totalmente!", "Do not install tools from sources you do not fully trust.": "¡No instalar herramientas de fuentes en las que no se confíe totalmente!", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "Parámetros de Docling", "Docling Server URL required.": "Docling URL del servidor necesaria.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Endpoint Azure Doc Intelligence requerido", "Document Intelligence Model": "Modelo para Doc Intelligence", "Documentation": "Documentación", - "Documents": "Documentos", "does not make any external connections, and your data stays securely on your locally hosted server.": "no se realiza ninguna conexión externa y tus datos permanecen seguros alojados localmente en tu servidor.", "Domain Filter List": "Lista de Filtrado de Dominio", "don't fetch random pipelines from sources you don't trust.": "No obtengas pipelines aleatorias de fuentes no confiables.", @@ -493,11 +502,14 @@ "Done": "Hecho", "Download": "Descargar", "Download & Delete": "Descargar y eliminar", + "Download as JSON": "", "Download as SVG": "Descargar como SVG", "Download canceled": "Descarga cancelada", "Download Database": "Descargar Base de Datos", + "Downloading stats...": "", "Draw": "Dibujar", "Drop any files here to upload": "Arrastra aquí los archivos a subir.", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "p.ej. '30s','10m'. Unidades de tiempo válidas son 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "p.ej. \"json\" o un esquema JSON", "e.g. 60": "p.ej. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Ingresar la Clave API de Bocha Search", "Enter Brave Search API Key": "Ingresar la Clave API de Brave Search", "Enter certificate path": "Ingresar la ruta del certificado", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Ingresar Superposición de los Fragmentos", "Enter Chunk Size": "Ingresar el Tamaño del Fragmento", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Ingresar pares \"token:valor_sesgo\" separados por comas (ejemplo: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Ingresar URL del Buscador Web Externo", "Enter Firecrawl API Base URL": "Ingresar URL Base del API de Firecrawl", "Enter Firecrawl API Key": "Ingresar Clave del API de Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Ingresar nombre de la carpeta", "Enter function name filter list (e.g. func1, !func2)": "Ingresar lista para el filtro de nombres de función (p.ej.: func1, !func2)", "Enter Github Raw URL": "Ingresar URL Github en Bruto(raw)", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Ingresa color hex (ej. #FF0000)", "Enter ID": "Ingresar ID", "Enter Image Size (e.g. 512x512)": "Ingresar Tamaño de Imagen (p.ej. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Ingresar Clave API de Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Ingresar config JSON (ej., {\"disable_links\": true})", "Enter Jupyter Password": "Ingresar Contraseña de Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Ingresar Clave API de Kagi Search", "Enter Key Behavior": "Comportamiento de la Tecla de Envío", "Enter language codes": "Ingresar Códigos de Idioma", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Ingresar la URL Base de la API de Mistral", "Enter Mistral API Key": "Ingresar Clave API de Mistral", "Enter Model ID": "Ingresar ID del Modelo", @@ -736,6 +753,7 @@ "Failed to generate title": "Fallo al generar el título", "Failed to import models": "Fallo al importar modelos", "Failed to load chat preview": "Fallo al cargar la previsualización del chat", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Fallo al cargar el contenido del archivo", "Failed to move chat": "Fallo al mover el chat", "Failed to process URL: {{url}}": "Fallo al procesar la URL", @@ -752,10 +770,10 @@ "Features": "Características", "Features Permissions": "Permisos de las Características", "February": "Febrero", + "Feedback": "", "Feedback deleted successfully": "Opinión eliminada correctamente", "Feedback Details": "Detalle de la Opinión", "Feedback History": "Historia de la Opiniones", - "Feedbacks": "Opiniones", "Feel free to add specific details": "Añade libremente detalles específicos", "Female": "Mujer", "File": "Archivo", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Se detectó suplantación de huellas: No se pueden usar las iniciales como avatar. Se establece la imagen de perfil predeterminada.", "Firecrawl API Base URL": "URL Base de API de Firecrawl", "Firecrawl API Key": "Clave de API de Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Acciones Rápidas Flotantes", "Focus Chat Input": "Enfocar a la Entrada del Chat", "Folder": "Carpeta", "Folder Background Image": "Imagen de Fondo de la Carpeta", "Folder deleted successfully": "Carpeta eliminada correctamente", + "Folder Max File Count": "", "Folder Name": "Nombre de la Carpeta", "Folder name cannot be empty.": "El nombre de la carpeta no puede estar vacío", "Folder name updated successfully": "Nombre de la carpeta actualizado correctamente", @@ -826,7 +846,6 @@ "General": "General", "Generate": "Generar", "Generate an image": "Generar una imagen", - "Generate Image": "Generar imagen", "Generate Message Pair": "Generar Par de Mensajes", "Generated Image": "Imagen Generada", "Generating search query": "Generando consulta de búsqueda", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Empezar con {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Buena Respuesta", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Clave API de Google PSE", "Google PSE Engine Id": "ID del Motor PSE de Google", "Gravatar": "Gravatar", "Grid": "Cuadrícula", + "Grokipedia": "", "Group": "Grupo", "Group Channel": "Canal de Grupo", "Group created successfully": "Grupo creado correctamente", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Indicador para Generación de Imagen", "Image Prompt Generation Prompt": "Indicador para la Generación del Indicador de Imagen", "Image Size": "Tamaño de la Imagen", - "Images": "Imágenes", "Import": "Importar", "Import Chats": "Importar Chats", "Import Config from JSON File": "Importar Config desde Archivo JSON", @@ -927,6 +947,7 @@ "Integration": "Integración", "Integrations": "Integraciones", "Interface": "Interfaz", + "Interface Settings Access": "", "Invalid file content": "Contenido de archivo inválido", "Invalid file format.": "Formato de archivo inválido.", "Invalid JSON file": "Archivo JSON inválido", @@ -940,6 +961,7 @@ "is typing...": "está escribiendo...", "Italic": "Cursiva", "January": "Enero", + "Jina API Base URL": "", "Jina API Key": "Clave API de Jina", "join our Discord for help.": "unete a nuestro Discord para ayuda.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Dejar vacío para incluir todos los modelos desde el endpoint \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Dejar vacío para incluir todos los modelos desde el endpoint \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Dejar vacío para incluir todos los modelos o Seleccionar modelos específicos", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Dejar vacío para usar el modo predeterminado (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Dejar vacío para usar el indicador predeterminado, o Ingresar un indicador personalizado", "Leave model field empty to use the default model.": "Dejar vacío el campo modelo para usar el modelo predeterminado.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Gestionar la información de tu cuenta", "March": "Marzo", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (Encabezado)", + "Markdown Header Text Splitter": "", "Max Speakers": "Max Interlocutores", "Max Upload Count": "Número Max de Subidas", "Max Upload Size": "Tamaño Max de Subidas", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Se puede descargar un máximo de 3 modelos simultáneamente. Por favor, reinténtelo más tarde.", "May": "Mayo", "MBR": "MBR", @@ -1042,6 +1067,7 @@ "Member removed successfully": "Miembro removido correctamente", "Members": "Miembros", "Members added successfully": "Miembros añadidos correctamente", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Las memorias accesibles por los LLMs se mostrarán aquí.", "Memory": "Memoria", "Memory added successfully": "Memoria añadida correctamente", @@ -1051,6 +1077,7 @@ "Merge Responses": "Fusionar Respuestas", "Merged Response": "Respuesta combinada", "Message": "Mensaje", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Para usar esta función debe estar habilitada la calificación de mensajes", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Los mensajes que envíe después de la creación del enlace no se compartirán. Los usuarios con la URL del enlace podrán ver el chat compartido.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Nombre Modelo", "Model name already exists, please choose a different one": "Ese nombre de modelo ya existe, por favor elige otro diferente", "Model Name is required.": "El Nombre de Modelo es requerido", + "Model names and usage frequency": "", "Model not selected": "Modelo no seleccionado", "Model Params": "Paráms Modelo", "Model Permissions": "Permisos Modelo", + "Model responses or outputs": "", "Model unloaded successfully": "Modelo descargado correctamente", "Model updated successfully": "Modelo actualizado correctamente", "Model(s) do not support file upload": "Modelo/s no soportan subida de archivos", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Modelos importados correctamente", "Models Public Sharing": "Compartir Modelos Públicamente", "Models Sharing": "Compartir Modelos", + "Mojeek": "", "Mojeek Search API Key": "Clave API de Mojeek Search", "More": "Más", "More Concise": "Más Conciso", @@ -1129,7 +1159,7 @@ "No conversation to save": "No hay conversación para guardar", "No distance available": "No hay distancia disponible", "No expiration can pose security risks.": "No expiración puede poner la seguridad en riesgo.", - "No feedbacks found": "No se encontraron comentarios", + "No feedback found": "", "No file selected": "No se seleccionó archivo", "No files in this knowledge base.": "Ningún archivo en esta base de conocimiento.", "No functions found": "No se encontraron funciones", @@ -1144,6 +1174,7 @@ "No models selected": "No se seleccionaron modelos", "No Notes": "Sin Notas", "No notes found": "No se encontraron notas", + "No one": "", "No pinned messages": "No hay mensajes fijados", "No prompts found": "No se encontraron indicadores", "No results": "No se encontraron resultados", @@ -1195,6 +1226,7 @@ "Only invited users can access": "Solo pueden acceder usuarios invitados", "Only markdown files are allowed": "Solo están permitidos archivos markdown", "Only select users and groups with permission can access": "Solo pueden acceder los usuarios y grupos con permiso", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "¡vaya! Parece que la URL es inválida. Por favor, revisala y reintenta de nuevo.", "Oops! There are files still uploading. Please wait for the upload to complete.": "¡vaya! Todavía hay archivos subiendose. Por favor, espera a que se complete la subida.", "Oops! There was an error in the previous response.": "¡vaya! Hubo un error en la respuesta previa.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open-WebUI puede usar herramientas proporcionadas por cualquier servidor OpenAPI", "Open WebUI uses faster-whisper internally.": "Open-WebUI usa faster-whisper internamente.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open-WebUI usa SpeechT5 y la incrustración de locutores de CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "La versión de Open-WebUI (v{{OPEN_WEBUI_VERSION}}) es inferior a la versión (v{{REQUIRED_VERSION}}) requerida", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "página", "Paginate": "Paginar", "Parameters": "Parámetros", + "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.": "", "Password": "Contraseña", "Passwords do not match.": "Las contraseñas no coinciden", "Paste Large Text as File": "Pegar el Texto Largo como Archivo", @@ -1260,7 +1295,6 @@ "Pipe": "Tubo", "Pipeline deleted successfully": "Tubería borrada correctamente", "Pipeline downloaded successfully": "Tubería descargada correctamente", - "Pipelines": "Tuberías", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines es un sistema de complementos con ejecución arbitraria de código —", "Pipelines Not Detected": "Servicio de Tuberías (Pipelines) No Detectado", "Pipelines Valves": "Válvulas de Tuberías", @@ -1499,6 +1533,7 @@ "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.": "Establece las secuencias de parada a usar. Cuando se encuentre este patrón, el LLM dejará de generar texto y retornará. Se pueden establecer varios patrones de parada especificando separadamente múltiples parámetros de parada en un archivo de modelo.", "Setting": "Ajuste", "Settings": "Ajustes", + "Settings Permissions": "", "Settings saved successfully!": "¡Ajustes guardados correctamente!", "Share": "Compartir", "Share Chat": "Compartir Chat", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Error en reconocimiento de voz: {{error}}", "Speech-to-Text": "Voz a Texto", "Speech-to-Text Engine": "Motor Voz a Texto(STT)", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Comenzar una conversación nueva", "Start of the channel": "Inicio del canal", "Start Tag": "Etiqueta de Inicio", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Pasos", "Stop": "Detener", + "Stop Download": "", "Stop Generating": "Parar la Generación", "Stop Sequence": "Secuencia de Parada", "Stream Chat Response": "Transmisión Directa de la Respuesta del Chat", @@ -1572,7 +1609,14 @@ "Support": "Soportar", "Support this plugin:": "Apoya este plugin:", "Supported MIME Types": "Tipos MIME Soportados", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sincroniza Directorio", + "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": "Sistema", "System Instructions": "Instrucciones del sistema", "System Prompt": "Indicador del sistema", @@ -1617,6 +1661,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "La Ponderación de BM25 en la Búsqueda Híbrida. 0 más semántica, 1 más léxica. Por defecto, 0.5", "The width in pixels to compress images to. Leave empty for no compression.": "El ancho en pixeles al comprimir imágenes. Dejar vacío para no compresión", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Pensando...", "This action cannot be undone. Do you wish to continue?": "Esta acción no se puede deshacer. ¿Desea continuar?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Este canal fue creado el {{createdAt}}. Este es el comienzo del canal {{channelName}}.", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Subir Tubería", "Upload Progress": "Progreso de la Subida", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Progreso de la Subida: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "Subiendo archivo...", "URL": "URL", "URL is required": "La URL es requerida", @@ -1748,6 +1794,7 @@ "User Groups": "Grupos de Usuarios", "User location successfully retrieved.": "Ubicación de usuario obtenida correctamente.", "User menu": "Menu de Usuario", + "User ratings (thumbs up/down)": "", "User Webhooks": "Usuario Webhooks", "Username": "Nombre de Usuario", "users": "usuarios", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI hará solicitudes a \"{{url}}/chat/completions\"", "What are you trying to achieve?": "¿Qué estás tratando de conseguir?", "What are you working on?": "¿En qué estás trabajando?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Que hay de Nuevo en", "What's on your mind?": "¿En que estás pensando?", "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.": "Cuando está habilitado, el modelo responderá a cada mensaje de chat en tiempo real, generando una respuesta tan pronto como se envíe un mensaje. Este modo es útil para aplicaciones de chat en vivo, pero puede afectar al rendimiento en equipos más lentos.", "wherever you are": "dondequiera que estés", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Al paginar la salida. Cada página será separada por una línea horizontal y número de página. Por defecto: Falso", "Whisper (Local)": "Whisper (Local)", + "Who can share to this group": "", "Why?": "¿Por qué?", "Widescreen Mode": "Modo Pantalla Ancha", "Width": "Ancho", + "Wikipedia": "", "Won": "Ganó", "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.": "Trabaja conjuntamente con top-k. Un valor más alto (p.ej. 0.95) dará lugar a un texto más diverso, mientras que un valor más bajo (p.ej. 0.5) generará un texto más centrado y conservador.", "Workspace": "Espacio de Trabajo", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "URL de la instancia Yacy", "Yacy Password": "Contraseña de Yacy", "Yacy Username": "Usuario de Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Ayer", "Yesterday at {{LOCALIZED_TIME}}": "Ayer a las {{LOCALIZED_TIME}}", "You": "Tu", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Solo puedes chatear con un máximo de {{maxCount}} archivo(s) a la vez.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Puedes personalizar tus interacciones con los LLMs añadiendo memorias a través del botón 'Gestionar' debajo, haciendo que te sean más útiles y personalizados.", "You cannot upload an empty file.": "No puedes subir un archivo vacío.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "No tienes permiso para enviar mensajes en este canal", "You do not have permission to send messages in this thread.": "No tienes permiso para enviar mensajes en este hilo", "You do not have permission to upload files to this knowledge base.": "No tienes permiso para subir archivos a esta base de conocimiento.", @@ -1835,6 +1891,8 @@ "Your Account": "Tu Cuenta", "Your account status is currently pending activation.": "Tu cuenta está pendiente de activación.", "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.": "Tu entera contribución irá directamente al desarrollador del complemento; Open-WebUI no recibe ningún porcentaje. Sin embargo, la plataforma de financiación elegida podría tener sus propias tarifas.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube Idioma", "Youtube Proxy URL": "Youtube URL Proxy" diff --git a/src/lib/i18n/locales/et-EE/translation.json b/src/lib/i18n/locales/et-EE/translation.json index 7cdf4d3f77..fccfe0d05e 100644 --- a/src/lib/i18n/locales/et-EE/translation.json +++ b/src/lib/i18n/locales/et-EE/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Nende seadete kohandamine rakendab muudatused universaalselt kõigile kasutajatele.", "admin": "admin", "Admin": "Administraator", + "Admin Contact Email": "", "Admin Panel": "Administraatori paneel", "Admin Settings": "Administraatori seaded", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administraatoritel on alati juurdepääs kõigile tööriistadele; kasutajatele tuleb tööriistad määrata mudeli põhiselt tööruumis.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Luba vastuse jätkamine", "Allow Delete Messages": "Luba sõnumite kustutamine", "Allow File Upload": "Luba failide üleslaadimine", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Luba mitu mudelit vestluses", "Allow non-local voices": "Luba mitte-lokaalsed hääled", "Allow Rate Response": "Luba vastuse hindamine", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "ja veel {{COUNT}}", "and create a new shared link.": "ja looge uus jagatud link.", "Android": "Android", + "Anyone": "", "API Base URL": "API baas-URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "Datalab Marker teenuse API baas-URL. Vaikimisi: https://www.datalab.to/api/v1/marker", "API Key": "API võti", @@ -175,6 +176,7 @@ "Authenticate": "Autendi", "Authentication": "Autentimine", "Auto": "Auto", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Kopeeri vastus automaatselt lõikelauale", "Auto-playback response": "Mängi vastus automaatselt", "Autocomplete Generation": "Automaattäitmise genereerimine", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 API autentimise string", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 baas-URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 baas-URL on nõutav.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Saadaolevate nimekiri", "Available Tools": "Saadaolevad tööriistad", "available users": "saadaolevad kasutajad", @@ -201,6 +204,7 @@ "before": "enne", "Being lazy": "Laisklemine", "Beta": "Beeta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 lõpp-punkt", "Bing Search V7 Subscription Key": "Bing Search V7 tellimuse võti", "Bio": "Bio", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha otsingu API võti", "Bold": "Paks", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Konkreetsete tokenite võimendamine või karistamine piiratud vastuste jaoks. Kallutatuse väärtused piiratakse vahemikku -100 kuni 100 (kaasa arvatud). (Vaikimisi: puudub)", + "Brave": "", "Brave Search API Key": "Brave Search API võti", + "Builtin Tools": "", "Bullet List": "Täpiline loend", "Button ID": "Nupu ID", "Button Label": "Nupu silt", @@ -256,8 +262,10 @@ "Check for updates": "Kontrolli uuendusi", "Checking for updates...": "Uuenduste kontrollimine...", "Choose a model before saving...": "Valige mudel enne salvestamist...", + "Chunk Min Size Target": "", "Chunk Overlap": "Tükkide ülekate", "Chunk Size": "Tüki suurus", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Šifrid", "Citation": "Viide", "Citations": "Citations", @@ -293,7 +301,6 @@ "Code Block": "Koodiplokk", "Code Editor": "", "Code execution": "Koodi täitmine", - "Code Execution": "Koodi täitmine", "Code Execution Engine": "Koodi täitmise mootor", "Code Execution Timeout": "Koodi täitmise aegumine", "Code formatted successfully": "Kood vormindatud edukalt", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Võtke WebUI juurdepääsu saamiseks ühendust administraatoriga", "Content": "Sisu", "Content Extraction Engine": "Sisu ekstraheerimise mootor", + "Content lengths (character counts only)": "", "Continue Response": "Jätka vastust", "Continue with {{provider}}": "Jätka {{provider}}-ga", "Continue with Email": "Jätka e-postiga", @@ -393,6 +401,7 @@ "Database": "Andmebaas", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "PP/KK/AAAA", + "DDGS Backend": "", "December": "Detsember", "Decrease UI Scale": "", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Sukeldu teadmistesse", "Do not install functions from sources you do not fully trust.": "Ärge installige funktsioone allikatest, mida te täielikult ei usalda.", "Do not install tools from sources you do not fully trust.": "Ärge installige tööriistu allikatest, mida te täielikult ei usalda.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "Docling serveri URL on nõutav.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Document Intelligence lõpp-punkt on nõutav.", "Document Intelligence Model": "", "Documentation": "Dokumentatsioon", - "Documents": "Dokumendid", "does not make any external connections, and your data stays securely on your locally hosted server.": "ei loo väliseid ühendusi ja teie andmed jäävad turvaliselt teie kohalikult majutatud serverisse.", "Domain Filter List": "Domeeni filtri nimekiri", "don't fetch random pipelines from sources you don't trust.": "Ära tõmba juhuslikke pipelines allikatest, mida sa ei usalda.", @@ -493,11 +502,14 @@ "Done": "Valmis", "Download": "Laadi alla", "Download & Delete": "Laadi alla ja kustuta", + "Download as JSON": "", "Download as SVG": "Laadi alla SVG-na", "Download canceled": "Allalaadimine tühistatud", "Download Database": "Laadi alla andmebaas", + "Downloading stats...": "", "Draw": "Joonista", "Drop any files here to upload": "Lohistage siia failid üleslaadimiseks", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "nt '30s', '10m'. Kehtivad ajaühikud on 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "nt \"json\" või JSON skeem", "e.g. 60": "nt 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Sisestage Bocha Search API võti", "Enter Brave Search API Key": "Sisestage Brave Search API võti", "Enter certificate path": "Sisestage sertifikaadi tee", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Sisestage tükkide ülekate", "Enter Chunk Size": "Sisestage tüki suurus", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Sisestage komadega eraldatud \"token:kallutuse_väärtus\" paarid (näide: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Enter Väline Veeb Otsi URL", "Enter Firecrawl API Base URL": "Enter Firecrawl API Base URL", "Enter Firecrawl API Key": "Enter Firecrawl API Võti", + "Enter Firecrawl Timeout": "", "Enter folder name": "Enter kaust nimi", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Sisestage Github toorURL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Enter hex värv (e.g. #FF0000)", "Enter ID": "Enter ID", "Enter Image Size (e.g. 512x512)": "Sisestage pildi suurus (nt 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Sisestage Jina API võti", "Enter JSON config (e.g., {\"disable_links\": true})": "Enter JSON config (e.g., {\"disable_links\": true})", "Enter Jupyter Password": "Sisestage Jupyter parool", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Sisestage Kagi Search API võti", "Enter Key Behavior": "Sisestage võtme käitumine", "Enter language codes": "Sisestage keelekoodid", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Enter Mistral API Võti", "Enter Model ID": "Sisestage mudeli ID", @@ -736,6 +753,7 @@ "Failed to generate title": "Ebaõnnestus kuni generate title", "Failed to import models": "Ebaõnnestus kuni impordi mudelid", "Failed to load chat preview": "Ebaõnnestus kuni load vestlus preview", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Ebaõnnestus kuni load fail content.", "Failed to move chat": "Ebaõnnestus kuni teisalda vestlus", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Funktsioonid", "Features Permissions": "Funktsioonide õigused", "February": "Veebruar", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Tagasiside Details", "Feedback History": "Tagasiside ajalugu", - "Feedbacks": "Tagasisided", "Feel free to add specific details": "Võite lisada konkreetseid üksikasju", "Female": "Female", "File": "Fail", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Tuvastati sõrmejälje võltsimine: initsiaalide kasutamine avatarina pole võimalik. Kasutatakse vaikimisi profiilikujutist.", "Firecrawl API Base URL": "Firecrawl API Base URL", "Firecrawl API Key": "Firecrawl API Võti", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Floating Quick Actions", "Focus Chat Input": "", "Folder": "Kaust", "Folder Background Image": "Kausta taustpilt", "Folder deleted successfully": "Kaust edukalt kustutatud", + "Folder Max File Count": "", "Folder Name": "Kausta nimi", "Folder name cannot be empty.": "Kausta nimi ei saa olla tühi.", "Folder name updated successfully": "Kausta nimi edukalt uuendatud", @@ -826,7 +846,6 @@ "General": "Üldine", "Generate": "Generate", "Generate an image": "Genereeri pilt", - "Generate Image": "Genereeri pilt", "Generate Message Pair": "", "Generated Image": "Genereeritud pilt", "Generating search query": "Otsinguküsimuse genereerimine", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Alusta {{WEBUI_NAME}} kasutamist", "Global": "Globaalne", "Good Response": "Hea vastus", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API võti", "Google PSE Engine Id": "Google PSE mootori ID", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Rühm", "Group Channel": "", "Group created successfully": "Grupp edukalt loodud", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Pildi vihje genereerimine", "Image Prompt Generation Prompt": "Pildi vihje genereerimise vihje", "Image Size": "", - "Images": "Pildid", "Import": "Impordi", "Import Chats": "Impordi vestlused", "Import Config from JSON File": "Impordi seadistus JSON-failist", @@ -927,6 +947,7 @@ "Integration": "Integratsioon", "Integrations": "Integratsioonid", "Interface": "Kasutajaliides", + "Interface Settings Access": "", "Invalid file content": "Vigane faili sisu", "Invalid file format.": "Vigane failiformaat.", "Invalid JSON file": "Vigane JSON-fail", @@ -940,6 +961,7 @@ "is typing...": "kirjutab...", "Italic": "Kaldkiri", "January": "Jaanuar", + "Jina API Base URL": "", "Jina API Key": "Jina API võti", "join our Discord for help.": "liituge abi saamiseks meie Discordiga.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Leave empty kuni include all mudelid alates \"{{url}}/api/sildid\" lõpp-punkt", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Leave empty kuni include all mudelid alates \"{{url}}/mudelid\" lõpp-punkt", "Leave empty to include all models or select specific models": "Jäta tühjaks, et kaasata kõik mudelid või vali konkreetsed mudelid", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Jäta tühjaks, et kasutada vaikimisi vihjet, või sisesta kohandatud vihje", "Leave model field empty to use the default model.": "Jäta mudeli väli tühjaks, et kasutada vaikimisi mudelit.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Halda oma konto teavet.", "March": "Märts", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (päis)", + "Markdown Header Text Splitter": "", "Max Speakers": "Maksimaalne kõnelejate arv", "Max Upload Count": "Maksimaalne üleslaadimiste arv", "Max Upload Size": "Maksimaalne üleslaadimise suurus", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Korraga saab alla laadida maksimaalselt 3 mudelit. Palun proovige hiljem uuesti.", "May": "Mai", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLM-idele ligipääsetavad mälestused kuvatakse siin.", "Memory": "Mälu", "Memory added successfully": "Mälu edukalt lisatud", @@ -1051,6 +1077,7 @@ "Merge Responses": "Ühenda vastused", "Merged Response": "Kombineeritud vastus", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Selle funktsiooni kasutamiseks peaks sõnumite hindamine olema lubatud", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Teie saadetud sõnumeid pärast lingi loomist ei jagata. Kasutajad, kellel on URL, saavad vaadata jagatud vestlust.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Mudeli nimi", "Model name already exists, please choose a different one": "Mudel nimi already exists, please choose a different one", "Model Name is required.": "Mudel Nimi is required.", + "Model names and usage frequency": "", "Model not selected": "Mudel pole valitud", "Model Params": "Mudeli parameetrid", "Model Permissions": "Mudeli õigused", + "Model responses or outputs": "", "Model unloaded successfully": "Mudel unloaded successfully", "Model updated successfully": "Mudel edukalt uuendatud", "Model(s) do not support file upload": "Mudel(id) ei toeta faili üleslaadimist", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Mudelid edukalt imporditud", "Models Public Sharing": "Mudelite avalik jagamine", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API võti", "More": "Rohkem", "More Concise": "Kokkuvõtlikum", @@ -1129,7 +1159,7 @@ "No conversation to save": "No conversation kuni salvesta", "No distance available": "Kaugus pole saadaval", "No expiration can pose security risks.": "No expiration can pose security risks.", - "No feedbacks found": "Tagasisidet ei leitud", + "No feedback found": "", "No file selected": "Faili pole valitud", "No files in this knowledge base.": "", "No functions found": "No functions found", @@ -1144,6 +1174,7 @@ "No models selected": "Mudeleid pole valitud", "No Notes": "No Märkmed", "No notes found": "No märkmed found", + "No one": "", "No pinned messages": "", "No prompts found": "No prompts found", "No results": "Tulemusi ei leitud", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Only markdown failid are allowed", "Only select users and groups with permission can access": "Juurdepääs on ainult valitud õigustega kasutajatel ja gruppidel", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oih! URL tundub olevat vigane. Palun kontrollige ja proovige uuesti.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Oih! Failide üleslaadimine on veel pooleli. Palun oodake, kuni üleslaadimine lõpeb.", "Oops! There was an error in the previous response.": "Oih! Eelmises vastuses oli viga.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Ava WebUI can use tööriista provided autor any OpenAPI server.", "Open WebUI uses faster-whisper internally.": "Open WebUI kasutab sisemiselt faster-whisper'it.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI kasutab SpeechT5 ja CMU Arctic kõneleja manustamisi.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI versioon (v{{OPEN_WEBUI_VERSION}}) on madalam kui nõutav versioon (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "leht", "Paginate": "Paginate", "Parameters": "Parameetrid", + "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.": "", "Password": "Parool", "Passwords do not match.": "Passwords do not match.", "Paste Large Text as File": "Kleebi suur tekst failina", @@ -1260,7 +1295,6 @@ "Pipe": "Pipe", "Pipeline deleted successfully": "Torustik edukalt kustutatud", "Pipeline downloaded successfully": "Torustik edukalt alla laaditud", - "Pipelines": "Torustikud", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines on pluginate süsteem, mis võimaldab suvalise koodi käivitamist —", "Pipelines Not Detected": "Torustikke ei tuvastatud", "Pipelines Valves": "Torustike klapid", @@ -1498,6 +1532,7 @@ "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.": "Määrab kasutatavad lõpetamise järjestused. Kui see muster kohatakse, lõpetab LLM teksti genereerimise ja tagastab. Mitme lõpetamise mustri saab määrata, täpsustades modelfile'is mitu eraldi lõpetamise parameetrit.", "Setting": "", "Settings": "Seaded", + "Settings Permissions": "", "Settings saved successfully!": "Seaded edukalt salvestatud!", "Share": "Jaga", "Share Chat": "Jaga vestlust", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Kõnetuvastuse viga: {{error}}", "Speech-to-Text": "Speech-to-Text", "Speech-to-Text Engine": "Kõne-tekstiks mootor", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Käivita a new conversation", "Start of the channel": "Kanali algus", "Start Tag": "Käivita Silt", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Peata", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Lõpetamise järjestus", "Stream Chat Response": "Voogedasta vestluse vastust", @@ -1571,7 +1608,14 @@ "Support": "Tugi", "Support this plugin:": "Toeta seda pistikprogrammi:", "Supported MIME Types": "Supported MIME Types", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sünkroniseeri kataloog", + "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": "Süsteem", "System Instructions": "Süsteemi juhised", "System Prompt": "Süsteemi vihje", @@ -1616,6 +1660,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "The Weight - BM25 Hybrid Otsi. 0 more semantic, 1 more lexical. Vaikimisi 0.5", "The width in pixels to compress images to. Leave empty for no compression.": "The laius in pixels kuni compress pildid kuni. Leave empty for no compression.", "Theme": "Teema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Mõtleb...", "This action cannot be undone. Do you wish to continue?": "Seda toimingut ei saa tagasi võtta. Kas soovite jätkata?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "This channel was created peal {{createdAt}}. This is the very beginning - the {{channelName}} channel.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Laadi torustik üles", "Upload Progress": "Üleslaadimise progress", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Laadi Edenemine: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "URL is required", @@ -1747,6 +1793,7 @@ "User Groups": "Kasutaja Groups", "User location successfully retrieved.": "Kasutaja asukoht edukalt hangitud.", "User menu": "Kasutaja menu", + "User ratings (thumbs up/down)": "", "User Webhooks": "Kasutaja Webhooks", "Username": "Kasutajanimi", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI teeb päringuid aadressile \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Mida te püüate saavutada?", "What are you working on?": "Millega te tegelete?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Mis on uut", "What's on your mind?": "", "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.": "Kui see on lubatud, vastab mudel igale vestlussõnumile reaalajas, genereerides vastuse niipea, kui kasutaja sõnumi saadab. See režiim on kasulik reaalajas vestlusrakendustes, kuid võib mõjutada jõudlust aeglasema riistvara puhul.", "wherever you are": "kus iganes te olete", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Whether kuni paginate the output. Each leht will be separated autor a horizontal rule ja leht number. Defaults kuni False.", "Whisper (Local)": "Whisper (lokaalne)", + "Who can share to this group": "", "Why?": "Miks?", "Widescreen Mode": "Laiekraani režiim", "Width": "Laius", + "Wikipedia": "", "Won": "Võitis", "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.": "Töötab koos top-k-ga. Kõrgem väärtus (nt 0,95) annab tulemuseks mitmekesisema teksti, samas kui madalam väärtus (nt 0,5) genereerib keskendunuma ja konservatiivsema teksti.", "Workspace": "Tööala", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy Instance URL", "Yacy Password": "Yacy Parool", "Yacy Username": "Yacy Username", + "Yahoo": "", + "Yandex": "", "Yesterday": "Eile", "Yesterday at {{LOCALIZED_TIME}}": "Eile kell {{LOCALIZED_TIME}}", "You": "Sina", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Saate korraga vestelda maksimaalselt {{maxCount}} faili(ga).", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Saate isikupärastada oma suhtlust LLM-idega, lisades mälestusi alumise 'Halda' nupu kaudu, muutes need kasulikumaks ja teile kohandatumaks.", "You cannot upload an empty file.": "Te ei saa üles laadida tühja faili.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "You do not have õigus kuni send sõnumid in this channel.", "You do not have permission to send messages in this thread.": "You do not have õigus kuni send sõnumid in this thread.", "You do not have permission to upload files to this knowledge base.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Your Konto", "Your account status is currently pending activation.": "Teie konto staatus on praegu ootel aktiveerimist.", "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.": "Kogu teie toetus läheb otse pistikprogrammi arendajale; Open WebUI ei võta mingit protsenti. Kuid valitud rahastamisplatvormil võivad olla oma tasud.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube keel", "Youtube Proxy URL": "Youtube puhverserveri URL" diff --git a/src/lib/i18n/locales/eu-ES/translation.json b/src/lib/i18n/locales/eu-ES/translation.json index b755775459..15be123f92 100644 --- a/src/lib/i18n/locales/eu-ES/translation.json +++ b/src/lib/i18n/locales/eu-ES/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ezarpen hauek aldatzeak aldaketak erabiltzaile guztiei aplikatuko dizkie.", "admin": "administratzailea", "Admin": "Administratzailea", + "Admin Contact Email": "", "Admin Panel": "Administrazio Panela", "Admin Settings": "Administrazio Ezarpenak", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratzaileek tresna guztietarako sarbidea dute beti; erabiltzaileek lan-eremuan eredu bakoitzeko esleituak behar dituzte tresnak.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Baimendu Fitxategiak Igotzea", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Baimendu urruneko ahotsak", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "eta {{COUNT}} gehiago", "and create a new shared link.": "eta sortu partekatutako esteka berri bat.", "Android": "", + "Anyone": "", "API Base URL": "API Oinarri URLa", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API Gakoa", @@ -175,6 +176,7 @@ "Authenticate": "Autentifikatu", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatikoki Kopiatu Erantzuna Arbelera", "Auto-playback response": "Automatikoki erreproduzitu erantzuna", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Autentifikazio Katea", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Oinarri URLa", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Oinarri URLa beharrezkoa da.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Zerrenda erabilgarria", "Available Tools": "", "available users": "erabilgarri dauden erabiltzaileak", @@ -201,6 +204,7 @@ "before": "aurretik", "Being lazy": "Alferra izatea", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "Bing Bilaketa V7 Endpointua", "Bing Search V7 Subscription Key": "Bing Bilaketa V7 Harpidetza Gakoa", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave Bilaketa API Gakoa", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Bilatu eguneraketak", "Checking for updates...": "Eguneraketak bilatzen...", "Choose a model before saving...": "Aukeratu eredu bat gorde aurretik...", + "Chunk Min Size Target": "", "Chunk Overlap": "Zatien Gainjartzea", "Chunk Size": "Zati Tamaina", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Zifratuak", "Citation": "Aipamena", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Kodearen exekuzioa", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "Kodea ongi formateatu da", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Jarri harremanetan Administratzailearekin WebUI Sarbiderako", "Content": "Edukia", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Jarraitu Erantzuna", "Continue with {{provider}}": "Jarraitu {{provider}}-rekin", "Continue with Email": "Jarraitu Posta Elektronikoarekin", @@ -393,6 +401,7 @@ "Database": "Datu-basea", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Abendua", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Murgildu ezagutzan", "Do not install functions from sources you do not fully trust.": "Ez instalatu guztiz fidagarriak ez diren iturrietatik datozen funtzioak.", "Do not install tools from sources you do not fully trust.": "Ez instalatu guztiz fidagarriak ez diren iturrietatik datozen tresnak.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentazioa", - "Documents": "Dokumentuak", "does not make any external connections, and your data stays securely on your locally hosted server.": "ez du kanpo konexiorik egiten, eta zure datuak modu seguruan mantentzen dira zure zerbitzari lokalean.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Ez eskuratu pipelines aleatorioak iturri ez fidagarrietatik.", @@ -493,11 +502,14 @@ "Done": "Eginda", "Download": "Deskargatu", "Download & Delete": "Deskargatu eta ezabatu", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Deskarga bertan behera utzi da", "Download Database": "Deskargatu Datu-basea", + "Downloading stats...": "", "Draw": "Marraztu", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "adib. '30s','10m'. Denbora unitate baliodunak dira 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Sartu Brave Bilaketa API Gakoa", "Enter certificate path": "Sartu ziurtagiriaren bidea", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Sartu Zatien Gainjartzea (chunk overlap)", "Enter Chunk Size": "Sartu Zati Tamaina", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Sartu Github Raw URLa", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Sartu Irudi Tamaina (adib. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Sartu Jina API Gakoa", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Sartu hizkuntza kodeak", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Sartu Eredu IDa", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Otsaila", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Feedbacken Historia", - "Feedbacks": "Feedbackak", "Feel free to add specific details": "Gehitu xehetasun zehatzak nahi izanez gero", "Female": "", "File": "Fitxategia", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Hatz-marka faltsutzea detektatu da: Ezin dira inizialak avatar gisa erabili. Profil irudi lehenetsia erabiliko da.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Karpeta ongi ezabatu da", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Karpetaren izena ezin da hutsik egon.", "Folder name updated successfully": "Karpetaren izena ongi eguneratu da", @@ -826,7 +846,6 @@ "General": "Orokorra", "Generate": "", "Generate an image": "", - "Generate Image": "Sortu Irudia", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Bilaketa kontsulta sortzen", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Hasi {{WEBUI_NAME}}-rekin", "Global": "Globala", "Good Response": "Erantzun Ona", + "Google": "", "Google Drive": "", "Google PSE API Key": "Google PSE API Gakoa", "Google PSE Engine Id": "Google PSE Motor IDa", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Taldea", "Group Channel": "", "Group created successfully": "Taldea ongi sortu da", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Irudiak", "Import": "", "Import Chats": "Inportatu Txatak", "Import Config from JSON File": "Inportatu Konfigurazioa JSON Fitxategitik", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Interfazea", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Fitxategi formatu baliogabea.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Urtarrila", + "Jina API Base URL": "", "Jina API Key": "Jina API Gakoa", "join our Discord for help.": "batu gure Discord-era laguntzarako.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "Utzi hutsik eredu guztiak sartzeko edo hautatu eredu zehatzak", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Utzi hutsik prompt lehenetsia erabiltzeko, edo sartu prompt pertsonalizatu bat", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Martxoa", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Karga kopuru maximoa", "Max Upload Size": "Karga tamaina maximoa", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Gehienez 3 modelo deskarga daitezke aldi berean. Saiatu berriro geroago.", "May": "Maiatza", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLMek atzitu ditzaketen memoriak hemen erakutsiko dira.", "Memory": "Memoria", "Memory added successfully": "Memoria ongi gehitu da", @@ -1051,6 +1077,7 @@ "Merge Responses": "Batu erantzunak", "Merged Response": "Erantzun bateratua", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Mezuen balorazioa gaitu behar da funtzionalitate hau erabiltzeko", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Esteka sortu ondoren bidaltzen dituzun mezuak ez dira partekatuko. URLa duten erabiltzaileek partekatutako txata ikusi ahal izango dute.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Modeloaren izena", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Ez da modelorik hautatu", "Model Params": "Modelo parametroak", "Model Permissions": "Modelo baimenak", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Modeloa ongi eguneratu da", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek bilaketa API gakoa", "More": "Gehiago", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Ez dago distantziarik eskuragarri", "No expiration can pose security risks.": "", - "No feedbacks found": "Ez da iritzirik aurkitu", + "No feedback found": "", "No file selected": "Ez da fitxategirik hautatu", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Ez da modelorik hautatu", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Ez da emaitzarik aurkitu", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Baimena duten erabiltzaile eta talde hautatuek soilik sar daitezke", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ui! URLa ez da baliozkoa. Mesedez, egiaztatu eta saiatu berriro.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ui! Oraindik fitxategiak kargatzen ari dira. Mesedez, itxaron karga amaitu arte.", "Oops! There was an error in the previous response.": "Ui! Errore bat egon da aurreko erantzunean.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI-k faster-whisper erabiltzen du barnean.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI-k SpeechT5 eta CMU Arctic hiztun txertaketak erabiltzen ditu.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI bertsioa (v{{OPEN_WEBUI_VERSION}}) beharrezko bertsioa (v{{REQUIRED_VERSION}}) baino baxuagoa da", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "orria", "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.": "", "Password": "Pasahitza", "Passwords do not match.": "", "Paste Large Text as File": "Itsatsi testu luzea fitxategi gisa", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline-a ongi ezabatu da", "Pipeline downloaded successfully": "Pipeline-a ongi deskargatu da", - "Pipelines": "Pipeline-ak", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines pluginen sistema bat da, ausazko kode‑exekuzioarekin —", "Pipelines Not Detected": "Ez da Pipeline-rik detektatu", "Pipelines Valves": "Pipeline balbulak", @@ -1498,6 +1532,7 @@ "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.": "Ezartzen ditu erabiliko diren gelditzeko sekuentziak. Patroi hau aurkitzen denean, LLMak testua sortzeari utziko dio eta itzuli egingo da. Gelditzeko patroi anitz ezar daitezke modelfile batean gelditzeko parametro anitz zehaztuz.", "Setting": "", "Settings": "Ezarpenak", + "Settings Permissions": "", "Settings saved successfully!": "Ezarpenak ongi gorde dira!", "Share": "Partekatu", "Share Chat": "Partekatu txata", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Ahots ezagutze errorea: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Ahotsetik-testura motorra", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Kanalaren hasiera", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Gelditu", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Gelditzeko sekuentzia", "Stream Chat Response": "Transmititu txat erantzuna", @@ -1571,7 +1608,14 @@ "Support": "Laguntza", "Support this plugin:": "Lagundu plugin hau:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sinkronizatu direktorioa", + "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": "Sistema", "System Instructions": "Sistema jarraibideak", "System Prompt": "Sistema prompta", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Gaia", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Pentsatzen...", "This action cannot be undone. Do you wish to continue?": "Ekintza hau ezin da desegin. Jarraitu nahi duzu?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Kargatu Pipeline-a", "Upload Progress": "Kargaren aurrerapena", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URLa", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Erabiltzailearen kokapena ongi berreskuratu da.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Erabiltzaile-izena", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI-k eskaerak egingo ditu \"{{url}}/chat/completions\"-era", "What are you trying to achieve?": "Zer lortu nahi duzu?", "What are you working on?": "Zertan ari zara lanean?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Zer berri honetan:", "What's on your mind?": "", "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.": "Gaituta dagoenean, modeloak txat mezu bakoitzari denbora errealean erantzungo dio, erantzun bat sortuz erabiltzaileak mezua bidaltzen duen bezain laster. Modu hau erabilgarria da zuzeneko txat aplikazioetarako, baina errendimenduan eragina izan dezake hardware motelagoan.", "wherever you are": "zauden tokian zaudela", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", "Whisper (Local)": "Whisper (Lokala)", + "Who can share to this group": "", "Why?": "Zergatik?", "Widescreen Mode": "Pantaila zabaleko modua", "Width": "", + "Wikipedia": "", "Won": "Irabazi du", "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.": "", "Workspace": "Lan-eremua", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Atzo", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Zu", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Gehienez {{maxCount}} fitxategirekin txateatu dezakezu aldi berean.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "LLMekin dituzun interakzioak pertsonalizatu ditzakezu memoriak gehituz beheko 'Kudeatu' botoiaren bidez, lagungarriagoak eta zuretzat egokituagoak eginez.", "You cannot upload an empty file.": "Ezin duzu fitxategi huts bat kargatu.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Zure kontuaren egoera aktibazio zain dago.", "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.": "Zure ekarpen osoa zuzenean plugin garatzaileari joango zaio; Open WebUI-k ez du ehunekorik hartzen. Hala ere, aukeratutako finantzaketa plataformak bere komisioak izan ditzake.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index 6be300d430..7eed896dea 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "با تنظیم این تنظیمات، تغییرات به طور کلی برای همه کاربران اعمال می\u200cشود.", "admin": "مدیر", "Admin": "مدیر", + "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.": "مدیران همیشه به تمام ابزارها دسترسی دارند؛ کاربران نیاز به ابزارهای اختصاص داده شده برای هر مدل در فضای کاری دارند.", @@ -101,7 +102,6 @@ "Allow Continue Response": "مجاز کردن ادامه پاسخ", "Allow Delete Messages": "مجاز کردن حذف پیام\u200cها", "Allow File Upload": "اجازه بارگذاری فایل", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "اجازه استفاده از چند مدل در گفتگو", "Allow non-local voices": "اجازه صداهای غیر محلی", "Allow Rate Response": "مجاز کردن امتیازدهی به پاسخ", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "و {{COUNT}} مورد دیگر", "and create a new shared link.": "و یک پیوند اشتراک\u200cگذاری جدید ایجاد کنید.", "Android": "اندروید", + "Anyone": "", "API Base URL": "نشانی پایهٔ API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "آدرس پایه API برای سرویس مارکر دیتا\u200cلب. پیش\u200cفرض: https://www.datalab.to/api/v1/marker", "API Key": "کلید API", @@ -175,6 +176,7 @@ "Authenticate": "احراز هویت", "Authentication": "احراز هویت", "Auto": "خودکار", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "کپی خودکار پاسخ به کلیپ بورد", "Auto-playback response": "پخش خودکار پاسخ", "Autocomplete Generation": "تولید تکمیل خودکار", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "رشته احراز هویت API اتوماتیک1111", "AUTOMATIC1111 Base URL": "پایه URL AUTOMATIC1111 ", "AUTOMATIC1111 Base URL is required.": "به URL پایه AUTOMATIC1111 مورد نیاز است.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "فهرست دردسترس", "Available Tools": "ابزارهای موجود", "available users": "کاربران در دسترس", @@ -201,6 +204,7 @@ "before": "قبل", "Being lazy": "حالت سازنده", "Beta": "بتا", + "Bing": "", "Bing Search V7 Endpoint": "نقطه پایانی جستجوی Bing V7", "Bing Search V7 Subscription Key": "کلید اشتراک جستجوی Bing V7", "Bio": "بیوگرافی", @@ -209,7 +213,9 @@ "Bocha Search API Key": "کلید API جستجوی Bocha", "Bold": "ضخیم", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "تقویت یا جریمه توکن\u200cهای خاص برای پاسخ\u200cهای محدود. مقادیر بایاس بین -100 و 100 (شامل) محدود خواهند شد. (پیش\u200cفرض: هیچ)", + "Brave": "", "Brave Search API Key": "کلید API جستجوی شجاع", + "Builtin Tools": "", "Bullet List": "لیست گلوله\u200cای", "Button ID": "شناسه دکمه", "Button Label": "برچسب دکمه", @@ -256,8 +262,10 @@ "Check for updates": "بررسی به\u200cروزرسانی", "Checking for updates...": "در حال بررسی برای به\u200cروزرسانی..", "Choose a model before saving...": "قبل از ذخیره یک مدل را انتخاب کنید...", + "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.": "", "Ciphers": "رمزها", "Citation": "استناد", "Citations": "ارجاعات", @@ -293,7 +301,6 @@ "Code Block": "بلاک کد", "Code Editor": "ویرایشگر کد", "Code execution": "اجرای کد", - "Code Execution": "اجرای کد", "Code Execution Engine": "موتور اجرای کد", "Code Execution Timeout": "مهلت اجرای کد", "Code formatted successfully": "کد با موفقیت قالب\u200cبندی شد", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "برای دسترسی به WebUI با مدیر تماس بگیرید", "Content": "محتوا", "Content Extraction Engine": "موتور استخراج محتوا", + "Content lengths (character counts only)": "", "Continue Response": "ادامه پاسخ", "Continue with {{provider}}": "با {{provider}} ادامه دهید", "Continue with Email": "با ایمیل ادامه دهید", @@ -393,6 +401,7 @@ "Database": "پایگاه داده", "Datalab Marker API": "API مارکر دیتا\u200cلب", "DD/MM/YYYY": "روز/ماه/سال", + "DDGS Backend": "", "December": "دسامبر", "Decrease UI Scale": "", "Deepgram": "دیپ\u200cگرام", @@ -474,6 +483,7 @@ "Dive into knowledge": "غوطه\u200cور شدن در دانش", "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": "", "Docling Server URL required.": "آدرس سرور داکلینگ مورد نیاز است.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "نقطه پایانی هوش سند مورد نیاز است.", "Document Intelligence Model": "", "Documentation": "مستندات", - "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.": "pipelineهای تصادفی را از منابع غیرقابل اعتماد دریافت نکنید.", @@ -493,11 +502,14 @@ "Done": "انجام شد", "Download": "دانلود کن", "Download & Delete": "دانلود و حذف", + "Download as JSON": "", "Download as SVG": "دانلود به صورت SVG", "Download canceled": "دانلود لغو شد", "Download Database": "دانلود پایگاه داده", + "Downloading stats...": "", "Draw": "رسم کردن", "Drop any files here to upload": "فایل\u200cها را برای آپلود به اینجا بکشید و رها کنید", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "به طور مثال '30s','10m'. واحد\u200cهای زمانی معتبر 's', 'm', 'h' هستند.", "e.g. \"json\" or a JSON schema": "مثلا \"json\" یا یک طرح JSON", "e.g. 60": "مثلا 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "کلید API جستجوی Bocha را وارد کنید", "Enter Brave Search API Key": "کلید API جستجوی شجاع را وارد کنید", "Enter certificate path": "مسیر گواهینامه را وارد کنید", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "مقدار Chunk Overlap را وارد کنید", "Enter Chunk Size": "مقدار Chunk Size را وارد کنید", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "جفت\u200cهای \"توکن:مقدار_بایاس\" را با کاما جدا شده وارد کنید (مثال: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "آدرس URL جستجوی وب خارجی را وارد کنید", "Enter Firecrawl API Base URL": "آدرس پایه API فایرکراول را وارد کنید", "Enter Firecrawl API Key": "کلید API فایرکراول را وارد کنید", + "Enter Firecrawl Timeout": "", "Enter folder name": "نام پوشه را وارد کنید", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "آدرس Github Raw را وارد کنید", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "رنگ هگزادسیمال را وارد کنید (مثلاً #FF0000)", "Enter ID": "شناسه را وارد کنید", "Enter Image Size (e.g. 512x512)": "اندازه تصویر را وارد کنید (مثال: 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "کلید API جینا را وارد کنید", "Enter JSON config (e.g., {\"disable_links\": true})": "پیکربندی JSON را وارد کنید (مثلاً، {\"disable_links\": true})", "Enter Jupyter Password": "رمز عبور ژوپیتر را وارد کنید", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "کلید API جستجوی کاگی را وارد کنید", "Enter Key Behavior": "رفتار کلید را وارد کنید", "Enter language codes": "کد زبان را وارد کنید", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "آدرس پایه API میسترال را وارد کنید", "Enter Mistral API Key": "کلید API میسترال را وارد کنید", "Enter Model ID": "شناسه مدل را وارد کنید", @@ -736,6 +753,7 @@ "Failed to generate title": "تولید عنوان ناموفق بود", "Failed to import models": "وارد کردن مدل\u200cها ناموفق بود", "Failed to load chat preview": "بارگیری پیش\u200cنمایش چت ناموفق بود", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "بارگیری محتوای فایل ناموفق بود.", "Failed to move chat": "انتقال چت ناموفق بود", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "ویژگی\u200cها", "Features Permissions": "مجوزهای ویژگی\u200cها", "February": "فوریه", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "جزئیات بازخورد", "Feedback History": "تاریخچهٔ بازخورد", - "Feedbacks": "بازخوردها", "Feel free to add specific details": "اگر به دلخواه، معلومات خاصی اضافه کنید", "Female": "زن", "File": "پرونده", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "فانگ سرفیس شناسایی شد: نمی توان از نمایه شما به عنوان آواتار استفاده کرد. پیش فرض به عکس پروفایل پیش فرض برگشت داده شد.", "Firecrawl API Base URL": "آدرس پایه API فایرکراول", "Firecrawl API Key": "کلید API فایرکراول", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "اقدامات سریع شناور", "Focus Chat Input": "فوکوس روی ورودی چت", "Folder": "پوشه", "Folder Background Image": "تصویر پس\u200cزمینه پوشه", "Folder deleted successfully": "پوشه با موفقیت حذف شد", + "Folder Max File Count": "", "Folder Name": "نام پوشه", "Folder name cannot be empty.": "نام پوشه نمی\u200cتواند خالی باشد.", "Folder name updated successfully": "نام پوشه با موفقیت به\u200cروز شد", @@ -826,7 +846,6 @@ "General": "عمومی", "Generate": "تولید", "Generate an image": "تولید یک تصویر", - "Generate Image": "تولید تصویر", "Generate Message Pair": "تولید جفت پیام", "Generated Image": "تصویر تولید شده", "Generating search query": "در حال تولید پرسوجوی جستجو", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "شروع کار با {{WEBUI_NAME}}", "Global": "سراسری", "Good Response": "پاسخ خوب", + "Google": "", "Google Drive": "گوگل درایو", "Google PSE API Key": "گوگل PSE API کلید", "Google PSE Engine Id": "شناسه موتور PSE گوگل", "Gravatar": "گراواتار", "Grid": "", + "Grokipedia": "", "Group": "گروه", "Group Channel": "", "Group created successfully": "گروه با موفقیت ایجاد شد", @@ -895,7 +916,6 @@ "Image Prompt Generation": "تولید پرامپت تصویر", "Image Prompt Generation Prompt": "پرامپت تولید پرامپت تصویر", "Image Size": "اندازه تصویر", - "Images": "تصاویر", "Import": "وارد کردن", "Import Chats": "درون\u200cریزی گفتگوها", "Import Config from JSON File": "درون\u200cریزی از پروندهٔ JSON", @@ -927,6 +947,7 @@ "Integration": "یکپارچه\u200cسازی", "Integrations": "یکپارچه\u200cسازی\u200cها", "Interface": "رابط", + "Interface Settings Access": "", "Invalid file content": "محتوای فایل نامعتبر است", "Invalid file format.": "قالب فایل نامعتبر است.", "Invalid JSON file": "فایل JSON نامعتبر است", @@ -940,6 +961,7 @@ "is typing...": "در حال تایپ...", "Italic": "ایتالیک", "January": "ژانویه", + "Jina API Base URL": "", "Jina API Key": "کلید API جینا", "join our Discord for help.": "برای کمک به دیسکورد ما بپیوندید.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "برای شامل شدن همه مدل\u200cها از نقطه پایانی \"{{url}}/api/tags\" خالی بگذارید", "Leave empty to include all models from \"{{url}}/models\" endpoint": "برای شامل شدن همه مدل\u200cها از نقطه پایانی \"{{url}}/models\" خالی بگذارید", "Leave empty to include all models or select specific models": "برای شامل شدن همه مدل\u200cها خالی بگذارید یا مدل\u200cهای خاص را انتخاب کنید", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "برای استفاده از مدل پیش\u200cفرض (voxtral-mini-latest) خالی بگذارید.", "Leave empty to use the default prompt, or enter a custom prompt": "برای استفاده از پرامپت پیش\u200cفرض خالی بگذارید، یا یک پرامپت سفارشی وارد کنید", "Leave model field empty to use the default model.": "برای استفاده از مدل پیش\u200cفرض، فیلد مدل را خالی بگذارید.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "اطلاعات حساب خود را مدیریت کنید.", "March": "مارچ", "Markdown": "مارک\u200cداون", - "Markdown (Header)": "مارک\u200cداون (هدر)", + "Markdown Header Text Splitter": "", "Max Speakers": "حداکثر تعداد بلندگوها", "Max Upload Count": "حداکثر تعداد آپلود", "Max Upload Size": "حداکثر اندازه آپلود", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "حداکثر 3 مدل را می توان به طور همزمان دانلود کرد. لطفاً بعداً دوباره امتحان کنید.", "May": "ماهی", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "حافظه های دسترسی به LLMs در اینجا نمایش داده می شوند.", "Memory": "حافظه", "Memory added successfully": "حافظه با موفقیت اضافه شد", @@ -1051,6 +1077,7 @@ "Merge Responses": "ادغام پاسخ\u200cها", "Merged Response": "پاسخ ادغام شده", "Message": "پیام", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "برای استفاده از این ویژگی باید امتیازدهی پیام\u200cها فعال باشد", "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": "وان\u200cدرایو مایکروسافت", @@ -1083,9 +1110,11 @@ "Model Name": "نام مدل", "Model name already exists, please choose a different one": "نام مدل قبلاً وجود دارد، لطفاً یک نام دیگر انتخاب کنید", "Model Name is required.": "نام مدل مورد نیاز است.", + "Model names and usage frequency": "", "Model not selected": "مدل انتخاب نشده", "Model Params": "مدل پارامز", "Model Permissions": "مجوزهای مدل", + "Model responses or outputs": "", "Model unloaded successfully": "مدل با موفقیت خارج شد", "Model updated successfully": "مدل با موفقیت به\u200cروز شد", "Model(s) do not support file upload": "مدل(ها) از بارگذاری فایل پشتیبانی نمی\u200cکنند", @@ -1096,6 +1125,7 @@ "Models imported successfully": "مدل\u200cها با موفقیت وارد شدند", "Models Public Sharing": "اشتراک\u200cگذاری عمومی مدل\u200cها", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "کلید API جستجوی موجیک", "More": "بیشتر", "More Concise": "خلاصه\u200cتر", @@ -1129,7 +1159,7 @@ "No conversation to save": "هیچ مکالمه\u200cای برای ذخیره وجود ندارد", "No distance available": "فاصله\u200cای در دسترس نیست", "No expiration can pose security risks.": "عدم انقضا می\u200cتواند خطرات امنیتی ایجاد کند.", - "No feedbacks found": "بازخوردی یافت نشد", + "No feedback found": "", "No file selected": "فایلی انتخاب نشده است", "No files in this knowledge base.": "", "No functions found": "هیچ تابعی یافت نشد", @@ -1144,6 +1174,7 @@ "No models selected": "مدلی انتخاب نشده است", "No Notes": "هیچ یادداشتی وجود ندارد", "No notes found": "هیچ یادداشتی یافت نشد", + "No one": "", "No pinned messages": "", "No prompts found": "هیچ پرامپتی یافت نشد", "No results": "نتیجه\u200cای یافت نشد", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "فقط فایل\u200cهای مارک\u200cداون مجاز هستند", "Only select users and groups with permission can access": "فقط کاربران و گروه\u200cهای دارای مجوز می\u200cتوانند دسترسی داشته باشند", + "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.": "اوه! هنوز فایل\u200cهایی در حال آپلود هستند. لطفاً منتظر تکمیل آپلود بمانید.", "Oops! There was an error in the previous response.": "اوه! در پاسخ قبلی خطایی رخ داد.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI می\u200cتواند از ابزارهای ارائه شده توسط هر سرور OpenAPI استفاده کند.", "Open WebUI uses faster-whisper internally.": "Open WebUI به صورت داخلی از faster-whisper استفاده می\u200cکند.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI از SpeechT5 و جاسازی\u200cهای گوینده CMU Arctic استفاده می\u200cکند.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "نسخه Open WebUI (v{{OPEN_WEBUI_VERSION}}) پایین\u200cتر از نسخه مورد نیاز (v{{REQUIRED_VERSION}}) است", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "صفحه", "Paginate": "صفحه\u200cبندی", "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.": "", "Password": "رمز عبور", "Passwords do not match.": "رمزهای عبور مطابقت ندارند.", "Paste Large Text as File": "چسباندن متن بزرگ به عنوان فایل", @@ -1260,7 +1295,6 @@ "Pipe": "خط لوله", "Pipeline deleted successfully": "خط لوله با موفقیت حذف شد", "Pipeline downloaded successfully": "خط لوله با موفقیت دانلود شد", - "Pipelines": "خط لوله", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines یک سیستم افزونه با امکان اجرای دلخواه کد است —", "Pipelines Not Detected": "خطوط لوله شناسایی نشدند", "Pipelines Valves": "شیرالات خطوط لوله", @@ -1498,6 +1532,7 @@ "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.": "توالی\u200cهای توقف مورد استفاده را تنظیم می\u200cکند. وقتی این الگو مشاهده شود، LLM تولید متن را متوقف کرده و برمی\u200cگردد. الگوهای توقف متعدد می\u200cتوانند با مشخص کردن پارامترهای توقف جداگانه متعدد در فایل مدل تنظیم شوند.", "Setting": "", "Settings": "تنظیمات", + "Settings Permissions": "", "Settings saved successfully!": "تنظیمات با موفقیت ذخیره شد!", "Share": "اشتراک\u200cگذاری", "Share Chat": "اشتراک\u200cگذاری چت", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "خطای تشخیص گفتار: {{error}}", "Speech-to-Text": "گفتار به متن", "Speech-to-Text Engine": "موتور گفتار به متن", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "شروع یک مکالمه جدید", "Start of the channel": "آغاز کانال", "Start Tag": "تگ شروع", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "مراحل", "Stop": "توقف", + "Stop Download": "", "Stop Generating": "توقف تولید", "Stop Sequence": "توقف توالی", "Stream Chat Response": "پاسخ چت جریانی", @@ -1571,7 +1608,14 @@ "Support": "حمایت", "Support this plugin:": "حمایت از این افزونه", "Supported MIME Types": "انواع MIME پشتیبانی شده", + "Sync": "", + "Sync Complete!": "", "Sync directory": "هم\u200cگام\u200cسازی پوشه", + "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": "دستورالعمل\u200cهای سیستم", "System Prompt": "پرامپت سیستم", @@ -1616,6 +1660,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "وزن جستجوی ترکیبی BM25. ۰ معنایی\u200cتر، ۱ لغوی\u200cتر. پیش\u200cفرض ۰.۵", "The width in pixels to compress images to. Leave empty for no compression.": "عرض بر حسب پیکسل برای فشرده\u200cسازی تصاویر. برای عدم فشرده\u200cسازی خالی بگذارید.", "Theme": "پوسته", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "در حال فکر کردن...", "This action cannot be undone. Do you wish to continue?": "این عمل قابل بازگشت نیست. آیا می\u200cخواهید ادامه دهید؟", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "این کانال در {{createdAt}} ایجاد شد. این آغاز کانال {{channelName}} است.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "خط تولید آپلود", "Upload Progress": "پیشرفت آپلود", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "پیشرفت آپلود: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}٪)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "آدرس اینترنتی", "URL is required": "آدرس URL مورد نیاز است", @@ -1747,6 +1793,7 @@ "User Groups": "گروه\u200cهای کاربری", "User location successfully retrieved.": "موقعیت مکانی کاربر با موفقیت دریافت شد.", "User menu": "منوی کاربر", + "User ratings (thumbs up/down)": "", "User Webhooks": "وب\u200cهوک\u200cهای کاربر", "Username": "نام کاربری", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI به \"{{url}}/chat/completions\" درخواست خواهد داد", "What are you trying to achieve?": "به دنبال دستیابی به چه هدفی هستید؟", "What are you working on?": "روی چه چیزی کار می\u200cکنید؟", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "چه چیز جدیدی در", "What's on your mind?": "", "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.": "وقتی فعال باشد، مدل به هر پیام گفتگو در زمان واقعی پاسخ می\u200cدهد و به محض ارسال پیام توسط کاربر، پاسخی تولید می\u200cکند. این حالت برای برنامه\u200cهای گفتگوی زنده مفید است، اما ممکن است در سخت\u200cافزارهای کندتر بر عملکرد تأثیر بگذارد.", "wherever you are": "هر جا که هستید", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "آیا خروجی صفحه\u200cبندی شود یا خیر. هر صفحه با یک خط افقی و شماره صفحه از هم جدا می\u200cشود. پیش\u200cفرض: False.", "Whisper (Local)": "ویسپر (محلی)", + "Who can share to this group": "", "Why?": "چرا؟", "Widescreen Mode": "حالت صفحهٔ عریض", "Width": "عرض", + "Wikipedia": "", "Won": "برنده شد", "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 همکاری می\u200cکند. مقدار بالاتر (مثلاً 0.95) منجر به متن متنوع\u200cتر می\u200cشود، در حالی که مقدار پایین\u200cتر (مثلاً 0.5) متن متمرکزتر و محافظه\u200cکارانه\u200cتری تولید می\u200cکند.", "Workspace": "محیط کار", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "آدرس URL نمونه Yacy", "Yacy Password": "رمز عبور Yacy", "Yacy Username": "نام کاربری Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "دیروز", "Yesterday at {{LOCALIZED_TIME}}": "دیروز در {{LOCALIZED_TIME}}", "You": "شما", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "شما در هر زمان نهایتا می\u200cتوانید با {{maxCount}} پرونده گفتگو کنید.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "شما می\u200cتوانید تعاملات خود با LLM\u200cها را با افزودن خاطرات از طریق دکمه 'مدیریت' در زیر شخصی\u200cسازی کنید تا آنها مفیدتر و متناسب\u200cتر با شما شوند.", "You cannot upload an empty file.": "نمی\u200cتوانید فایل خالی آپلود کنید.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "حساب کاربری شما", "Your account status is currently pending activation.": "وضعیت حساب شما در حال حاضر در انتظار فعال\u200cسازی است.", "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.": "تمام مشارکت شما مستقیماً به توسعه\u200cدهنده افزونه می\u200cرسد؛ Open WebUI هیچ درصدی دریافت نمی\u200cکند. با این حال، پلتفرم تأمین مالی انتخاب شده ممکن است کارمزد خود را داشته باشد.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "یوتیوب", "Youtube Language": "زبان یوتیوب", "Youtube Proxy URL": "آدرس پراکسی یوتیوب" diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index 75ef465b43..949bb64868 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Näiden asetusten säätäminen vaikuttaa kaikkiin käyttäjiin.", "admin": "hallinta", "Admin": "Ylläpito", + "Admin Contact Email": "", "Admin Panel": "Ylläpitopaneeli", "Admin Settings": "Ylläpitoasetukset", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Ylläpitäjillä on pääsy kaikkiin työkaluihin koko ajan; käyttäjät tarvitsevat työkaluja mallille määritettynä työtilassa.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Salli jatka vastausta", "Allow Delete Messages": "Salli viestien poisto", "Allow File Upload": "Salli tiedostojen lataus", - "Allow Group Sharing": "Salli ryhmäjako", "Allow Multiple Models in Chat": "Salli useampi malli keskustelussa", "Allow non-local voices": "Salli ei-paikalliset äänet", "Allow Rate Response": "Salli viestien arviointi", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "ja {{COUNT}} muuta", "and create a new shared link.": "ja luo uusi jaettu linkki.", "Android": "Android", + "Anyone": "", "API Base URL": "API:n verkko-osoite", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "API verkko-osoite Datalabb Marker palveluun. Oletuksena: https://www.datalab.to/api/v1/marker", "API Key": "API-avain", @@ -175,6 +176,7 @@ "Authenticate": "Todentaa", "Authentication": "Todennus", "Auto": "Automaattinen", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Kopioi vastaus automaattisesti leikepöydälle", "Auto-playback response": "Toista vastaus automaattisesti", "Autocomplete Generation": "Automaattisen täydennyksen luonti", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 API:n todennusmerkkijono", "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.)": "", "Available list": "Käytettävissä oleva luettelo", "Available Tools": "Käytettävissä olevat työkalut", "available users": "käytettävissä olevat käyttäjät", @@ -201,6 +204,7 @@ "before": "ennen", "Being lazy": "Oli laiska", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 -päätepisteen osoite", "Bing Search V7 Subscription Key": "Bing Search V7 -tilauskäyttäjäavain", "Bio": "Elämänkerta", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search API -avain", "Bold": "Lihavointi", "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", + "Builtin Tools": "", "Bullet List": "Luettelo", "Button ID": "Painikkeen ID", "Button Label": "Painikkeen nimi", @@ -256,8 +262,10 @@ "Check for updates": "Tarkista päivitykset", "Checking for updates...": "Tarkistetaan päivityksiä...", "Choose a model before saving...": "Valitse malli ennen tallentamista...", + "Chunk Min Size Target": "", "Chunk Overlap": "Päällekkäisten osien määrä", "Chunk Size": "Osien koko", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Salausalgoritmi", "Citation": "Lähdeviite", "Citations": "Lähdeviitteet", @@ -293,7 +301,6 @@ "Code Block": "Koodilohko", "Code Editor": "Koodieditori", "Code execution": "Koodin suoritus", - "Code Execution": "Koodin Suoritus", "Code Execution Engine": "Koodin suoritusmoottori", "Code Execution Timeout": "Koodin suorittamisen aikakatkaisu", "Code formatted successfully": "Koodin muotoilu onnistui", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Ota yhteyttä ylläpitäjään WebUI-käyttöä varten", "Content": "Sisältö", "Content Extraction Engine": "Sisällönpoimintamoottori", + "Content lengths (character counts only)": "", "Continue Response": "Jatka vastausta", "Continue with {{provider}}": "Jatka palvelulla {{provider}}", "Continue with Email": "Jatka sähköpostilla", @@ -393,6 +401,7 @@ "Database": "Tietokanta", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "DD/MM/YYYY", + "DDGS Backend": "", "December": "joulukuu", "Decrease UI Scale": "Pienennä käyttöliittymän kokoa", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Uppoudu tietoon", "Do not install functions from sources you do not fully trust.": "Älä asenna toimintoja lähteistä, joihin et luota täysin.", "Do not install tools from sources you do not fully trust.": "Älä asenna työkaluja lähteistä, joihin et luota täysin.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "Docling parametrit", "Docling Server URL required.": "Docling palvelimen verkko-osoite vaaditaan.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Document Intelligence pääte vaaditaan", "Document Intelligence Model": "Document Intelligence malli", "Documentation": "Dokumentaatio", - "Documents": "Asiakirjat", "does not make any external connections, and your data stays securely on your locally hosted server.": "ei tee ulkoisia yhteyksiä, ja tietosi pysyvät turvallisesti paikallisesti isännöidyllä palvelimellasi.", "Domain Filter List": "Verkko-osoitteiden suodatuslista", "don't fetch random pipelines from sources you don't trust.": "Älä hae satunnaisia pipelineja epäluotettavista lähteistä.", @@ -493,11 +502,14 @@ "Done": "Valmis", "Download": "Lataa", "Download & Delete": "Lataa ja poista", + "Download as JSON": "", "Download as SVG": "Lataa SVG:nä", "Download canceled": "Lataus peruutettu", "Download Database": "Lataa tietokanta", + "Downloading stats...": "", "Draw": "Piirros", "Drop any files here to upload": "Pudota tähän ladattavat tiedostot", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "esim. '30s', '10m'. Kelpoiset aikayksiköt ovat 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "esim. \"json\" tai JSON kaava", "e.g. 60": "esim. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Kirjoita Bocha Search API -avain", "Enter Brave Search API Key": "Kirjoita Brave Search API -avain", "Enter certificate path": "Kirjoita varmennepolku", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Syötä osien päällekkäisyys", "Enter Chunk Size": "Syötä osien koko", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Syötä pilkulla erottaen \"token:bias_value\" parit (esim. 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Kirjoita ulkoisen Web Search verkko-osoite", "Enter Firecrawl API Base URL": "Kirjoita Firecrawl API -verkko-osoite", "Enter Firecrawl API Key": "Kirjoita Firecrawl API-avain", + "Enter Firecrawl Timeout": "", "Enter folder name": "Kirjoita kansion nimi", "Enter function name filter list (e.g. func1, !func2)": "Kirjoita funktion nimen suodatinluettelo (esim. func1, !func2)", "Enter Github Raw URL": "Kirjoita Github Raw -verkko-osoite", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Kirjota hex väri (esim. #FF0000)", "Enter ID": "Kirjoita ID", "Enter Image Size (e.g. 512x512)": "Kirjoita kuvan koko (esim. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Kirjoita Jina API -avain", "Enter JSON config (e.g., {\"disable_links\": true})": "Kirjoita JSON asetus (esim. {\"disable_links\": true})", "Enter Jupyter Password": "Kirjoita Jupyter salasana", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kirjoita Kagi Search API -avain", "Enter Key Behavior": "Enter näppäimen käyttäytyminen", "Enter language codes": "Kirjoita kielikoodit", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Kirjoita Mistral API verkko-osoite", "Enter Mistral API Key": "Kirjoita Mistral API-avain", "Enter Model ID": "Kirjoita mallitunnus", @@ -736,6 +753,7 @@ "Failed to generate title": "Otsikon luonti epäonnistui", "Failed to import models": "Mallien tuonti epäonnistui", "Failed to load chat preview": "Keskustelun esikatselun lataaminen epäonnistui", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Tiedoston sisällön lataaminen epäonnistui.", "Failed to move chat": "Keskustelun siirto epäonnistui", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Ominaisuudet", "Features Permissions": "Ominaisuuksien käyttöoikeudet", "February": "helmikuu", + "Feedback": "", "Feedback deleted successfully": "Palaute poistettu onnistuneesti", "Feedback Details": "Palautteen tiedot", "Feedback History": "Palautehistoria", - "Feedbacks": "Palautteet", "Feel free to add specific details": "Voit lisätä tarkempia tietoja", "Female": "Nainen", "File": "Tiedosto", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Sormenjäljen väärentäminen havaittu: Alkukirjaimia ei voi käyttää avatarina. Käytetään oletusprofiilikuvaa.", "Firecrawl API Base URL": "Firecrawl API -verkko-osoite", "Firecrawl API Key": "Firecrawl API-avain", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Kelluvat pikakomennot", "Focus Chat Input": "Kohdista keskustelu tekstikenttään", "Folder": "Kansio", "Folder Background Image": "Kansion taustakuva", "Folder deleted successfully": "Kansio poistettu onnistuneesti", + "Folder Max File Count": "", "Folder Name": "Kansion nimi", "Folder name cannot be empty.": "Kansion nimi ei voi olla tyhjä.", "Folder name updated successfully": "Kansion nimi päivitetty onnistuneesti", @@ -826,7 +846,6 @@ "General": "Yleinen", "Generate": "Luo", "Generate an image": "Luo kuva", - "Generate Image": "Luo kuva", "Generate Message Pair": "Luo viesti pari", "Generated Image": "Luo kuva", "Generating search query": "Luodaan hakukyselyä", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Aloita käyttämään {{WEBUI_NAME}}:iä", "Global": "Yleinen", "Good Response": "Hyvä vastaus", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API -avain", "Google PSE Engine Id": "Google PSE -moottorin tunnus", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Ryhmä", "Group Channel": "Ryhmäkanava", "Group created successfully": "Ryhmä luotu onnistuneesti", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Kuvan kehote generointi", "Image Prompt Generation Prompt": "Kuvan generoinnin kehote", "Image Size": "Kuvan koko", - "Images": "Kuvat", "Import": "Tuo", "Import Chats": "Tuo keskustelut", "Import Config from JSON File": "Tuo asetukset JSON-tiedostosta", @@ -927,6 +947,7 @@ "Integration": "Integrointi", "Integrations": "Integraatiot", "Interface": "Käyttöliittymä", + "Interface Settings Access": "", "Invalid file content": "Virheellinen tiedostosisältö", "Invalid file format.": "Virheellinen tiedostomuoto.", "Invalid JSON file": "Virheellinen JSON tiedosto", @@ -940,6 +961,7 @@ "is typing...": "Kirjoittaa...", "Italic": "Kursiivi", "January": "tammikuu", + "Jina API Base URL": "", "Jina API Key": "Jina API -avain", "join our Discord for help.": "liity Discordiimme saadaksesi apua.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Jätä tyhjäksi sisällyttääksesi \"{{url}}/api/tags\" päätepisteen mallit", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Jätä tyhjäksi sisällyttääksesi \"{{url}}/models\" päätepisteen mallit", "Leave empty to include all models or select specific models": "Jätä tyhjäksi, jos haluat sisällyttää kaikki mallit tai valitse tietyt mallit", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Jätä tyhjäks käyttääksesi oletusmallia (voxtral-mini-latest)", "Leave empty to use the default prompt, or enter a custom prompt": "Jätä tyhjäksi käyttääksesi oletuskehotetta tai kirjoita mukautettu kehote", "Leave model field empty to use the default model.": "Jätä malli kenttä tyhjäksi käyttääksesi oletus mallia.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Hallitse tilitietojasi", "March": "maaliskuu", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (otsikko)", + "Markdown Header Text Splitter": "", "Max Speakers": "Puhujien enimmäismäärä", "Max Upload Count": "Latausten enimmäismäärä", "Max Upload Size": "Latausten enimmäiskoko", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Enintään 3 mallia voidaan ladata samanaikaisesti. Yritä myöhemmin uudelleen.", "May": "toukokuu", "MBR": "MBR", @@ -1042,6 +1067,7 @@ "Member removed successfully": "Jäsen poistettu onnistuneesti", "Members": "Jäsenet", "Members added successfully": "Jäsen lisätty onnistuneesti", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Muistitiedostot, joita LLM-ohjelmat käyttävät, näkyvät tässä.", "Memory": "Muisti", "Memory added successfully": "Muisti lisätty onnistuneesti", @@ -1051,6 +1077,7 @@ "Merge Responses": "Yhdistä vastaukset", "Merged Response": "Yhdistetty vastaus", "Message": "Viesti", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Tämän toiminnon käyttämiseksi viestiarviointi on otettava käyttöön", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Linkin luomisen jälkeen lähettämäsi viestit eivät ole jaettuja. Käyttäjät, joilla on verkko-osoite, voivat tarkastella jaettua keskustelua.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Mallin nimi", "Model name already exists, please choose a different one": "Mallin nimi on jo olemassa, valitse toinen nimi.", "Model Name is required.": "Mallin nimi on pakollinen", + "Model names and usage frequency": "", "Model not selected": "Mallia ei ole valittu", "Model Params": "Mallin parametrit", "Model Permissions": "Mallin käyttöoikeudet", + "Model responses or outputs": "", "Model unloaded successfully": "Malli purettu onnistuneesti", "Model updated successfully": "Malli päivitetty onnistuneesti", "Model(s) do not support file upload": "Malli(t) ei tue tiedostojen lataamista", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Mallit tuotiin onnistuneesti", "Models Public Sharing": "Mallin julkinen jakaminen", "Models Sharing": "Mallien jako", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API -avain", "More": "Lisää", "More Concise": "Ytimekkäämpi", @@ -1129,7 +1159,7 @@ "No conversation to save": "Ei tallennettavaa keskustelua", "No distance available": "Etäisyyttä ei saatavilla", "No expiration can pose security risks.": "Vanhenemisen laittamatta jättäminen voi altistaa tietoturvariskeille.", - "No feedbacks found": "Palautteita ei löytynyt", + "No feedback found": "", "No file selected": "Tiedostoa ei ole valittu", "No files in this knowledge base.": "", "No functions found": "Funktioita ei löytynyt", @@ -1144,6 +1174,7 @@ "No models selected": "Malleja ei ole valittu", "No Notes": "Ei muistiinpanoja", "No notes found": "Muistiinpanoja ei löytynyt", + "No one": "", "No pinned messages": "Ei kiinnitettyjä viestejä", "No prompts found": "Kehoitteita ei löytynyt", "No results": "Ei tuloksia", @@ -1195,6 +1226,7 @@ "Only invited users can access": "Vain kutsutut jäsenet voivat päästä", "Only markdown files are allowed": "Vain markdown tiedostot ovat sallittuja", "Only select users and groups with permission can access": "Vain valitut käyttäjät ja ryhmät, joilla on käyttöoikeus, pääsevät käyttämään", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Hups! Näyttää siltä, että verkko-osoite on virheellinen. Tarkista se ja yritä uudelleen.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Hups! Tiedostoja on vielä ladattavana. Odota, että lataus on valmis.", "Oops! There was an error in the previous response.": "Hups! Edellisessä vastauksessa oli virhe.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI voi käyttää minkä tahansa OpenAPI-palvelimen tarjoamia työkaluja.", "Open WebUI uses faster-whisper internally.": "Open WebUI käyttää faster-whisperia sisäisesti.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI käyttää SpeechT5:tä ja CMU Arctic -kaiuttimen upotuksia.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI -versio (v{{OPEN_WEBUI_VERSION}}) on alempi kuin vaadittu versio (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "sivu", "Paginate": "Sivutus", "Parameters": "Parametrit", + "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.": "", "Password": "Salasana", "Passwords do not match.": "Salasanat eivät täsmää", "Paste Large Text as File": "Liitä suuri teksti tiedostona", @@ -1260,7 +1295,6 @@ "Pipe": "Putki", "Pipeline deleted successfully": "Putki poistettu onnistuneesti", "Pipeline downloaded successfully": "Putki ladattu onnistuneesti", - "Pipelines": "Putkistot", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines on liitännäisjärjestelmä, jossa voidaan suorittaa mielivaltaista koodia —", "Pipelines Not Detected": "Putkistoja ei havaittu", "Pipelines Valves": "Putkistojen venttiilit", @@ -1498,6 +1532,7 @@ "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.": "Määrittää käytettävät lopetussekvenssit. Kun tämä kuvio havaitaan, LLM lopettaa tekstin tuottamisen ja palauttaa. Useita lopetuskuvioita voidaan asettaa määrittämällä useita erillisiä lopetusparametreja mallitiedostoon.", "Setting": "Asetus", "Settings": "Asetukset", + "Settings Permissions": "", "Settings saved successfully!": "Asetukset tallennettu onnistuneesti!", "Share": "Jaa", "Share Chat": "Jaa keskustelu", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Puheentunnistusvirhe: {{error}}", "Speech-to-Text": "Puheentunnistus", "Speech-to-Text Engine": "Puheentunnistusmoottori", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Aloita uusi keskustelu", "Start of the channel": "Kanavan alku", "Start Tag": "Aloitus tagi", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Askeleet", "Stop": "Pysäytä", + "Stop Download": "", "Stop Generating": "Lopeta generointi", "Stop Sequence": "Lopetussekvenssi", "Stream Chat Response": "Streamaa keskusteluvastaus", @@ -1571,7 +1608,14 @@ "Support": "Tuki", "Support this plugin:": "Tue tätä lisäosaa:", "Supported MIME Types": "Tuetut MIME-tyypit", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synkronoitu hakemisto", + "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": "Järjestelmä", "System Instructions": "Järjestelmäohjeet", "System Prompt": "Järjestelmäkehote", @@ -1616,6 +1660,7 @@ "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.": "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.": "", "Thinking...": "Ajattelee...", "This action cannot be undone. Do you wish to continue?": "Tätä toimintoa ei voi peruuttaa. Haluatko jatkaa?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Tämä kanava on luotiin {{createdAt}}. Tämä on {{channelName}} kanavan alku.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Lataa putki", "Upload Progress": "Latauksen edistyminen", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Latauksen edistyminen: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "Ladataan tiedostoa...", "URL": "URL", "URL is required": "URL vaaditaan", @@ -1747,6 +1793,7 @@ "User Groups": "Käyttäjäryhmät", "User location successfully retrieved.": "Käyttäjän sijainti haettu onnistuneesti.", "User menu": "Käyttäjävalikko", + "User ratings (thumbs up/down)": "", "User Webhooks": "Käyttäjän Webhook:it", "Username": "Käyttäjätunnus", "users": "käyttäjät", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI lähettää pyyntöjä osoitteeseen \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Mitä yrität saavuttaa?", "What are you working on?": "Mitä olet työskentelemässä?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Mitä uutta", "What's on your mind?": "Mitä ajattelet?", "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ä.", "Whisper (Local)": "Whisper (paikallinen)", + "Who can share to this group": "", "Why?": "Miksi?", "Widescreen Mode": "Laajakuvatila", "Width": "Leveys", + "Wikipedia": "", "Won": "Voitti", "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.": "", "Workspace": "Työtila", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy instanssin verkko-osoite", "Yacy Password": "Yacy salasana", "Yacy Username": "Yacy käyttäjänimi", + "Yahoo": "", + "Yandex": "", "Yesterday": "Eilen", "Yesterday at {{LOCALIZED_TIME}}": "Eilen {{LOCALIZED_TIME}}", "You": "Sinä", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Voit keskustella enintään {{maxCount}} tiedoston kanssa kerralla.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Voit personoida vuorovaikutustasi LLM-ohjelmien kanssa lisäämällä muistoja 'Hallitse'-painikkeen kautta, jolloin ne ovat hyödyllisempiä ja räätälöityjä sinua varten.", "You cannot upload an empty file.": "Et voi ladata tyhjää tiedostoa.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "Sinulla ei ole oikeuksia lähettää viestejä tähän kanavaan.", "You do not have permission to send messages in this thread.": "Sinulla ei ole oikeuksia lähettää viestejä tähän ketjuun.", "You do not have permission to upload files to this knowledge base.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Tilisi", "Your account status is currently pending activation.": "Tilisi tila on tällä hetkellä odottaa aktivointia.", "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.": "Koko panoksesi menee suoraan lisäosan kehittäjälle; Open WebUI ei pidätä prosenttiosuutta. Valittu rahoitusalusta voi kuitenkin periä omia maksujaan.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "Youtube kieli", "Youtube Proxy URL": "Youtube-välityspalvelimen verkko-osoite" diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index f0edb1e2c6..a6bf3946bf 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "L'ajustement de ces réglages appliquera universellement les changements à tous les utilisateurs.", "admin": "administrateur", "Admin": "Administrateur", + "Admin Contact Email": "", "Admin Panel": "Panneau d'administration", "Admin Settings": "Réglages d'administration", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Les administrateurs ont accès à tous les outils en permanence ; les utilisateurs doivent se voir attribuer des outils pour chaque modèle dans l'espace de travail.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Autoriser le téléversement de fichiers", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Autoriser plusieurs modèles dans la conversation", "Allow non-local voices": "Autoriser les voix non locales", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "et {{COUNT}} autres", "and create a new shared link.": "et créer un nouveau lien partagé.", "Android": "Android", + "Anyone": "", "API Base URL": "URL de base de l'API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Clé d'API", @@ -175,6 +176,7 @@ "Authenticate": "Authentifier", "Authentication": "Authentification", "Auto": "Automatique", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Copie automatique de la réponse vers le presse-papiers", "Auto-playback response": "Lire automatiquement la réponse", "Autocomplete Generation": "Génération des suggestions", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Chaîne d'authentification de l'API", "AUTOMATIC1111 Base URL": "URL de base AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "L'URL de base {AUTOMATIC1111} est requise.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Liste disponible", "Available Tools": "Outils disponibles", "available users": "utilisateurs disponibles", @@ -201,6 +204,7 @@ "before": "avant", "Being lazy": "Être fainéant", "Beta": "Bêta", + "Bing": "", "Bing Search V7 Endpoint": "Point de terminaison Bing Search V7", "Bing Search V7 Subscription Key": "Clé d'abonnement Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Clé API Bocha Search", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Renforcer ou pénaliser des éléments spécifiques pour les réponses contraintes. Les valeurs du biais seront comprises entre -100 et 100 (inclus). (Par défaut : aucun)", + "Brave": "", "Brave Search API Key": "Clé API Brave Search", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Vérifier les mises à jour disponibles", "Checking for updates...": "Recherche de mises à jour...", "Choose a model before saving...": "Choisissez un modèle avant de sauvegarder...", + "Chunk Min Size Target": "", "Chunk Overlap": "Chevauchement des chunks", "Chunk Size": "Taille des chunks", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Chiffres", "Citation": "Citation", "Citations": "Citations", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Exécution de code", - "Code Execution": "Exécution de code", "Code Execution Engine": "Moteur d'execution de code", "Code Execution Timeout": "Délai d'exécution du code dépassé", "Code formatted successfully": "Le code a été formaté avec succès", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contacter l'administrateur pour obtenir l'accès à WebUI", "Content": "Contenu", "Content Extraction Engine": "Moteur d'extraction de contenu", + "Content lengths (character counts only)": "", "Continue Response": "Continuer la réponse", "Continue with {{provider}}": "Continuer avec {{provider}}", "Continue with Email": "Continuer avec le courriel", @@ -393,6 +401,7 @@ "Database": "Base de données", "Datalab Marker API": "API Datalab Marker", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Décembre", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Plonger dans les connaissances", "Do not install functions from sources you do not fully trust.": "N'installez pas de fonctions provenant de sources auxquelles vous ne faites pas entièrement confiance.", "Do not install tools from sources you do not fully trust.": "N'installez pas d'outils provenant de sources auxquelles vous ne faites pas entièrement confiance.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "URL du serveur Docling requise.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Documentation", - "Documents": "Documents", "does not make any external connections, and your data stays securely on your locally hosted server.": "n'établit aucune connexion externe et garde vos données en sécurité sur votre serveur local.", "Domain Filter List": "Liste des domaines à filtrés", "don't fetch random pipelines from sources you don't trust.": "Ne récupérez pas des pipelines aléatoires à partir de sources non fiables.", @@ -493,11 +502,14 @@ "Done": "Terminé", "Download": "Télécharger", "Download & Delete": "Télécharger et supprimer", + "Download as JSON": "", "Download as SVG": "Télécharger au format SVG", "Download canceled": "Téléchargement annulé", "Download Database": "Télécharger la base de données", + "Downloading stats...": "", "Draw": "Match nul", "Drop any files here to upload": "Déposez des fichiers ici pour les téléverser", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "par ex. '30s', '10 min'. Les unités de temps valides sont 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "par ex. \"json\" ou un schéma JSON", "e.g. 60": "par ex. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Entrez la clé API Bocha Search", "Enter Brave Search API Key": "Entrez la clé API Brave Search", "Enter certificate path": "Entrez le chemin du certificat", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Entrez le chevauchement des chunks", "Enter Chunk Size": "Entrez la taille des chunks", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Entrez des paires \"token:valeur_biais\" séparées par des virgules (exemple : 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Entrez l'URL de la recherche Web externe", "Enter Firecrawl API Base URL": "Entrez l'URL de base de l'API Firecrawl", "Enter Firecrawl API Key": "Entrez la clé API de Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Entrez l'URL brute de GitHub", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Entrez la taille de l'image (par ex. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Entrez la clé API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Entrez le mot de passe Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Entrez la clé API Kagi Search", "Enter Key Behavior": "Entrez la clé Behavior", "Enter language codes": "Entrez les codes de langue", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Entrez la clé APU de Mistral", "Enter Model ID": "Entrez l'ID du modèle", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Échec du chargement du contenu du fichier", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Fonctionnalités", "Features Permissions": "Autorisations des fonctionnalités", "February": "Février", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Détails du retour d'information", "Feedback History": "Historique des avis", - "Feedbacks": "Avis", "Feel free to add specific details": "N'hésitez pas à ajouter des détails spécifiques", "Female": "", "File": "Fichier", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Spoofing détecté : impossible d'utiliser les initiales comme avatar. Retour à l'image de profil par défaut.", "Firecrawl API Base URL": "Url de l'API Base Firecrawl", "Firecrawl API Key": "Clé de l'API Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Dossier supprimé avec succès", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Le nom du dossier ne peut pas être vide.", "Folder name updated successfully": "Le nom du dossier a été mis à jour avec succès", @@ -826,7 +846,6 @@ "General": "Général", "Generate": "Génére", "Generate an image": "Génère une image", - "Generate Image": "Générer une image", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Génération d'une requête de recherche", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Démarrez avec {{WEBUI_NAME}}", "Global": "Globale", "Good Response": "Bonne réponse", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Clé API Google PSE", "Google PSE Engine Id": "ID du moteur de recherche PSE de Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Groupe", "Group Channel": "", "Group created successfully": "Groupe créé avec succès", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Génération de prompts d'images", "Image Prompt Generation Prompt": "Prompt de génération de prompts d'images", "Image Size": "", - "Images": "Images", "Import": "Importer", "Import Chats": "Importer les conversations", "Import Config from JSON File": "Importer la configuration depuis un fichier JSON", @@ -927,6 +947,7 @@ "Integration": "Intégration", "Integrations": "", "Interface": "Interface utilisateur", + "Interface Settings Access": "", "Invalid file content": "Contenu de fichier invalide", "Invalid file format.": "Format de fichier non valide.", "Invalid JSON file": "Fichier JSON non valide", @@ -940,6 +961,7 @@ "is typing...": "est en train d'écrire...", "Italic": "", "January": "Janvier", + "Jina API Base URL": "", "Jina API Key": "Clé API Jina", "join our Discord for help.": "Rejoignez notre Discord pour obtenir de l'aide.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Laissez vide pour inclure tous les modèles de l'endpoint \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Laissez vide pour inclure tous les modèles de l'endpoint \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Laissez vide pour inclure tous les modèles ou sélectionnez des modèles spécifiques", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Laissez vide pour utiliser le prompt par défaut, ou entrez un prompt personnalisé", "Leave model field empty to use the default model.": "Laisser le champ du modèle vide pour utiliser le modèle par défaut.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Mars", "Markdown": "Markdown", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "Nombre maximal d'intervenants", "Max Upload Count": "Nombre maximal de téléversements", "Max Upload Size": "Limite de taille de téléversement", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Un maximum de 3 modèles peut être téléchargé en même temps. Veuillez réessayer ultérieurement.", "May": "Mai", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Les souvenirs accessibles par les LLMs seront affichées ici.", "Memory": "Mémoire", "Memory added successfully": "Souvenir ajoutée avec succès", @@ -1051,6 +1077,7 @@ "Merge Responses": "Fusionner les réponses", "Merged Response": "Réponse fusionnée", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "L'évaluation des messages doit être activée pour pouvoir utiliser cette fonctionnalité", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Les messages que vous envoyez après avoir créé votre lien ne seront pas partagés. Les utilisateurs disposant de l'URL pourront voir la conversation partagée.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Nom du modèle", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Modèle non sélectionné", "Model Params": "Réglages du modèle", "Model Permissions": "Autorisations du modèle", + "Model responses or outputs": "", "Model unloaded successfully": "Le modèle a été déchargé avec succès", "Model updated successfully": "Le modèle a été mis à jour avec succès", "Model(s) do not support file upload": "Le(s) modèle(s) ne supportent pas le téléversement de fichiers", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Partage public des modèles", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Clé API Mojeek", "More": "Plus", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Aucune distance disponible", "No expiration can pose security risks.": "", - "No feedbacks found": "Aucun avis trouvé", + "No feedback found": "", "No file selected": "Aucun fichier sélectionné", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Aucun modèle sélectionné", "No Notes": "Pas de note", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Aucun résultat trouvé", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Seul les fichiers markdown sont autorisés", "Only select users and groups with permission can access": "Seuls les utilisateurs et groupes autorisés peuvent accéder", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oups ! Il semble que l'URL soit invalide. Veuillez vérifier à nouveau et réessayer.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Oups ! Des fichiers sont encore en cours de téléversement. Veuillez patienter jusqu'à la fin du téléversement.", "Oops! There was an error in the previous response.": "Oups ! Il y a eu une erreur dans la réponse précédente.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI peut utiliser les outils fournis par n'importe quel serveur OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI utilise faster-whisper en interne.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI utilise SpeechT5 et les embeddings de locuteur CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "La version Open WebUI (v{{OPEN_WEBUI_VERSION}}) est inférieure à la version requise (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API compatibles OpenAI", @@ -1235,6 +1268,8 @@ "page": "page", "Paginate": "Paginer", "Parameters": "Réglages", + "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.": "", "Password": "Mot de passe", "Passwords do not match.": "", "Paste Large Text as File": "Coller un texte volumineux comme fichier", @@ -1260,7 +1295,6 @@ "Pipe": "Pipeline", "Pipeline deleted successfully": "Le pipeline a été supprimé avec succès", "Pipeline downloaded successfully": "Le pipeline a été téléchargé avec succès", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines est un système de plug‑ins permettant l’exécution arbitraire de code —", "Pipelines Not Detected": "Aucun pipelines détecté", "Pipelines Valves": "Vannes de pipelines", @@ -1499,6 +1533,7 @@ "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.": "Définit les séquences d'arrêt à utiliser. Lorsque ce motif est rencontré, le LLM cessera de générer du texte et retournera. Plusieurs motifs d'arrêt peuvent être définis en spécifiant plusieurs réglages d'arrêt distincts dans un fichier modèle.", "Setting": "", "Settings": "Réglages", + "Settings Permissions": "", "Settings saved successfully!": "Réglages enregistrés avec succès !", "Share": "Partager", "Share Chat": "Partage de conversation", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Erreur de reconnaissance vocale : {{error}}", "Speech-to-Text": "Reconnaissance vocale", "Speech-to-Text Engine": "Moteur de reconnaissance vocale", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Début du canal", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Stop", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Séquence d'arrêt", "Stream Chat Response": "Streamer la réponse de la conversation", @@ -1572,7 +1609,14 @@ "Support": "Supporter", "Support this plugin:": "Supporter ce module", "Supported MIME Types": "Types MIME pris en charge", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synchroniser le répertoire", + "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": "Système", "System Instructions": "Instructions système", "System Prompt": "Prompt système", @@ -1617,6 +1661,7 @@ "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.": "Largeur en pixels à laquelle les images doivent être compressées. Laisser vide pour ne pas compresser.", "Theme": "Thème", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "En train de réfléchir...", "This action cannot be undone. Do you wish to continue?": "Cette action ne peut pas être annulée. Souhaitez-vous continuer ?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Ce canal a été créé le {{createdAt}}. Voici le tout début du canal {{channelName}}.", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Pipeline de téléchargement", "Upload Progress": "Progression de l'envoi", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "L'emplacement de l'utilisateur a été récupéré avec succès.", "User menu": "Menu utilisateur", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooks utilisateur", "Username": "Nom d'utilisateur", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI fera des requêtes à \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Que cherchez-vous à accomplir ?", "What are you working on?": "Sur quoi travaillez-vous ?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Quoi de neuf dans", "What's on your mind?": "", "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.": "Lorsqu'il est activé, le modèle répondra à chaque message de la conversation en temps réel, générant une réponse dès que l'utilisateur envoie un message. Ce mode est utile pour les applications de conversation en direct, mais peut affecter les performances sur un matériel plus lent.", "wherever you are": "où que vous soyez", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Indique si la sortie doit être paginée. Chaque page sera séparée par une règle horizontale et un numéro de page. La valeur par défaut est False.", "Whisper (Local)": "Whisper (local)", + "Who can share to this group": "", "Why?": "Pourquoi ?", "Widescreen Mode": "Mode grand écran", "Width": "", + "Wikipedia": "", "Won": "Victoires", "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.": "Fonctionne avec top-k. Une valeur élevée (par exemple, 0,95) conduira à un texte plus diversifié, tandis qu'une valeur plus faible (par exemple, 0,5) générera un texte plus ciblé et conservateur.", "Workspace": "Espace de travail", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "URL de l'instance Yacy", "Yacy Password": "Mot de passe Yacy", "Yacy Username": "Nom d'utilisateur Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Hier", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Vous", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Vous ne pouvez discuter qu'avec un maximum de {{maxCount}} fichier(s) à la fois.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Vous pouvez personnaliser vos interactions avec les LLM en ajoutant des mémoires à l'aide du bouton « Gérer » ci-dessous, ce qui les rendra plus utiles et mieux adaptées à vos besoins.", "You cannot upload an empty file.": "Vous ne pouvez pas envoyer un fichier vide.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Votre statut de compte est actuellement en attente d'activation.", "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.": "L'intégralité de votre contribution ira directement au développeur du plugin ; Open WebUI ne prend aucun pourcentage. Cependant, la plateforme de financement choisie peut avoir ses propres frais.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "Langue de Youtube", "Youtube Proxy URL": "URL du proxy YouTube" diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 47f4e01f95..ba72240a49 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "L'ajustement de ces réglages appliquera universellement les changements à tous les utilisateurs.", "admin": "administrateur", "Admin": "Administrateur", + "Admin Contact Email": "", "Admin Panel": "Panneau d'administration", "Admin Settings": "Réglages d'administration", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Les administrateurs ont accès à tous les outils en permanence ; les utilisateurs doivent se voir attribuer des outils pour chaque modèle dans l'espace de travail.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Autoriser la réponse continue", "Allow Delete Messages": "Autoriser la suppression des messages", "Allow File Upload": "Autoriser le téléversement de fichiers", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Autoriser plusieurs modèles dans la conversation", "Allow non-local voices": "Autoriser les voix non locales", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "et {{COUNT}} autres", "and create a new shared link.": "et créer un nouveau lien partagé.", "Android": "Android", + "Anyone": "", "API Base URL": "URL de base de l'API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "URL de base de l'API pour le service Datalab Marker. Par défaut : https://www.datalab.to/api/v1/marker", "API Key": "Clé d'API", @@ -175,6 +176,7 @@ "Authenticate": "Authentifier", "Authentication": "Authentification", "Auto": "Automatique", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Copie automatique de la réponse vers le presse-papiers", "Auto-playback response": "Lire automatiquement la réponse", "Autocomplete Generation": "Génération des suggestions", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Chaîne d'authentification de l'API", "AUTOMATIC1111 Base URL": "URL de base AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "L'URL de base {AUTOMATIC1111} est requise.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Liste disponible", "Available Tools": "Outils disponibles", "available users": "utilisateurs disponibles", @@ -201,6 +204,7 @@ "before": "avant", "Being lazy": "Être fainéant", "Beta": "Bêta", + "Bing": "", "Bing Search V7 Endpoint": "Point de terminaison Bing Search V7", "Bing Search V7 Subscription Key": "Clé d'abonnement Bing Search V7", "Bio": "Bio", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Clé API Bocha Search", "Bold": "Gras", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Renforcer ou pénaliser des éléments spécifiques pour les réponses contraintes. Les valeurs du biais seront comprises entre -100 et 100 (inclus). (Par défaut : aucun)", + "Brave": "", "Brave Search API Key": "Clé API Brave Search", + "Builtin Tools": "", "Bullet List": "Liste à puces", "Button ID": "Button ID", "Button Label": "Button Label", @@ -256,8 +262,10 @@ "Check for updates": "Vérifier les mises à jour disponibles", "Checking for updates...": "Recherche de mises à jour...", "Choose a model before saving...": "Choisissez un modèle avant de sauvegarder...", + "Chunk Min Size Target": "", "Chunk Overlap": "Chevauchement des chunks", "Chunk Size": "Taille des chunks", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Chiffres", "Citation": "Citation", "Citations": "Citations", @@ -293,7 +301,6 @@ "Code Block": "Bloc de code", "Code Editor": "", "Code execution": "Exécution de code", - "Code Execution": "Exécution de code", "Code Execution Engine": "Moteur d'execution de code", "Code Execution Timeout": "Délai d'exécution du code dépassé", "Code formatted successfully": "Le code a été formaté avec succès", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contacter l'administrateur pour obtenir l'accès à WebUI", "Content": "Contenu", "Content Extraction Engine": "Moteur d'extraction de contenu", + "Content lengths (character counts only)": "", "Continue Response": "Continuer la réponse", "Continue with {{provider}}": "Continuer avec {{provider}}", "Continue with Email": "Continuer avec l'email", @@ -393,6 +401,7 @@ "Database": "Base de données", "Datalab Marker API": "API Datalab Marker", "DD/MM/YYYY": "JJ/MM/AAAA", + "DDGS Backend": "", "December": "Décembre", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Plonger dans les connaissances", "Do not install functions from sources you do not fully trust.": "N'installez pas de fonctions provenant de sources auxquelles vous ne faites pas entièrement confiance.", "Do not install tools from sources you do not fully trust.": "N'installez pas d'outils provenant de sources auxquelles vous ne faites pas entièrement confiance.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "URL du serveur Docling requise.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Point de terminaison Document Intelligence requis.", "Document Intelligence Model": "", "Documentation": "Documentation", - "Documents": "Documents", "does not make any external connections, and your data stays securely on your locally hosted server.": "n'établit aucune connexion externe et garde vos données en sécurité sur votre serveur local.", "Domain Filter List": "Liste des domaines à filtrés", "don't fetch random pipelines from sources you don't trust.": "Ne récupérez pas des pipelines aléatoires depuis des sources non fiables.", @@ -493,11 +502,14 @@ "Done": "Terminé", "Download": "Télécharger", "Download & Delete": "Télécharger et supprimer", + "Download as JSON": "", "Download as SVG": "Télécharger au format SVG", "Download canceled": "Téléchargement annulé", "Download Database": "Télécharger la base de données", + "Downloading stats...": "", "Draw": "Match nul", "Drop any files here to upload": "Déposez des fichiers ici pour les téléverser", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "par ex. '30s', '10 min'. Les unités de temps valides sont 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "par ex. \"json\" ou un schéma JSON", "e.g. 60": "par ex. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Entrez la clé API Bocha Search", "Enter Brave Search API Key": "Entrez la clé API Brave Search", "Enter certificate path": "Entrez le chemin du certificat", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Entrez le chevauchement des chunks", "Enter Chunk Size": "Entrez la taille des chunks", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Entrez des paires \"token:valeur_biais\" séparées par des virgules (exemple : 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Entrez l'URL de la recherche Web externe", "Enter Firecrawl API Base URL": "Entrez l'URL de base de l'API Firecrawl", "Enter Firecrawl API Key": "Entrez la clé API de Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Entrez le nom du dossier", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Entrez l'URL brute de GitHub", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Entrez la couleur hexadécimale (Ex : #FF0000)", "Enter ID": "Entrez l'ID", "Enter Image Size (e.g. 512x512)": "Entrez la taille de l'image (par ex. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Entrez la clé API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Entrez le mot de passe Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Entrez la clé API Kagi Search", "Enter Key Behavior": "Entrez la clé Behavior", "Enter language codes": "Entrez les codes de langue", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Entrez la clé APU de Mistral", "Enter Model ID": "Entrez l'ID du modèle", @@ -736,6 +753,7 @@ "Failed to generate title": "Échec de la génération du titre", "Failed to import models": "", "Failed to load chat preview": "Échec du chargement de l'aperçu du chat", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Échec du chargement du contenu du fichier", "Failed to move chat": "Échec du déplacement du chat", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Fonctionnalités", "Features Permissions": "Autorisations des fonctionnalités", "February": "Février", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Détails du retour d'information", "Feedback History": "Historique des avis", - "Feedbacks": "Avis", "Feel free to add specific details": "N'hésitez pas à ajouter des détails spécifiques", "Female": "Femme", "File": "Fichier", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Spoofing détecté : impossible d'utiliser les initiales comme avatar. Retour à l'image de profil par défaut.", "Firecrawl API Base URL": "Url de l'API Base Firecrawl", "Firecrawl API Key": "Clé de l'API Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Actions rapides flottantes", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "Image d'arrière-plan du dossier", "Folder deleted successfully": "Dossier supprimé avec succès", + "Folder Max File Count": "", "Folder Name": "Nom du dossier", "Folder name cannot be empty.": "Le nom du dossier ne peut pas être vide.", "Folder name updated successfully": "Le nom du dossier a été mis à jour avec succès", @@ -826,7 +846,6 @@ "General": "Général", "Generate": "Génére", "Generate an image": "Génère une image", - "Generate Image": "Générer une image", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Génération d'une requête de recherche", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Démarrez avec {{WEBUI_NAME}}", "Global": "Globale", "Good Response": "Bonne réponse", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Clé API Google PSE", "Google PSE Engine Id": "ID du moteur de recherche PSE de Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Groupe", "Group Channel": "", "Group created successfully": "Groupe créé avec succès", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Génération de prompts d'images", "Image Prompt Generation Prompt": "Prompt de génération de prompts d'images", "Image Size": "", - "Images": "Images", "Import": "Importer", "Import Chats": "Importer les conversations", "Import Config from JSON File": "Importer la configuration depuis un fichier JSON", @@ -927,6 +947,7 @@ "Integration": "Intégration", "Integrations": "Integrations", "Interface": "Interface utilisateur", + "Interface Settings Access": "", "Invalid file content": "Contenu de fichier invalide", "Invalid file format.": "Format de fichier non valide.", "Invalid JSON file": "Fichier JSON non valide", @@ -940,6 +961,7 @@ "is typing...": "est en train d'écrire...", "Italic": "Italique", "January": "Janvier", + "Jina API Base URL": "", "Jina API Key": "Clé API Jina", "join our Discord for help.": "Rejoignez notre Discord pour obtenir de l'aide.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Laissez vide pour inclure tous les modèles de l'endpoint \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Laissez vide pour inclure tous les modèles de l'endpoint \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Laissez vide pour inclure tous les modèles ou sélectionnez des modèles spécifiques", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Laissez vide pour utiliser le prompt par défaut, ou entrez un prompt personnalisé", "Leave model field empty to use the default model.": "Laisser le champ du modèle vide pour utiliser le modèle par défaut.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Gérez les informations de votre compte.", "March": "Mars", "Markdown": "Markdown", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "Nombre maximal d'intervenants", "Max Upload Count": "Nombre maximal de téléversements", "Max Upload Size": "Limite de taille de téléversement", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Un maximum de 3 modèles peut être téléchargé en même temps. Veuillez réessayer ultérieurement.", "May": "Mai", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Les souvenirs accessibles par les LLMs seront affichées ici.", "Memory": "Mémoire", "Memory added successfully": "Souvenir ajoutée avec succès", @@ -1051,6 +1077,7 @@ "Merge Responses": "Fusionner les réponses", "Merged Response": "Réponse fusionnée", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "L'évaluation des messages doit être activée pour pouvoir utiliser cette fonctionnalité", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Les messages que vous envoyez après avoir créé votre lien ne seront pas partagés. Les utilisateurs disposant de l'URL pourront voir la conversation partagée.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Nom du modèle", "Model name already exists, please choose a different one": "Le nom du modèle existe déjà, veuillez en choisir un autre", "Model Name is required.": "Le nom du modèle est requis.", + "Model names and usage frequency": "", "Model not selected": "Modèle non sélectionné", "Model Params": "Réglages du modèle", "Model Permissions": "Autorisations du modèle", + "Model responses or outputs": "", "Model unloaded successfully": "Le modèle a été déchargé avec succès", "Model updated successfully": "Le modèle a été mis à jour avec succès", "Model(s) do not support file upload": "Le(s) modèle(s) ne supportent pas le téléversement de fichiers", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Partage public des modèles", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Clé API Mojeek", "More": "Plus", "More Concise": "Plus concis", @@ -1129,7 +1159,7 @@ "No conversation to save": "Aucune conversation à sauvegarder", "No distance available": "Aucune distance disponible", "No expiration can pose security risks.": "", - "No feedbacks found": "Aucun avis trouvé", + "No feedback found": "", "No file selected": "Aucun fichier sélectionné", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Aucun modèle sélectionné", "No Notes": "Pas de note", "No notes found": "Aucune note trouvée", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Aucun résultat trouvé", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Seul les fichiers markdown sont autorisés", "Only select users and groups with permission can access": "Seuls les utilisateurs et groupes autorisés peuvent accéder", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oups ! Il semble que l'URL soit invalide. Veuillez vérifier à nouveau et réessayer.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Oups ! Des fichiers sont encore en cours de téléversement. Veuillez patienter jusqu'à la fin du téléversement.", "Oops! There was an error in the previous response.": "Oups ! Il y a eu une erreur dans la réponse précédente.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI peut utiliser les outils fournis par n'importe quel serveur OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI utilise faster-whisper en interne.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI utilise SpeechT5 et les embeddings de locuteur CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "La version Open WebUI (v{{OPEN_WEBUI_VERSION}}) est inférieure à la version requise (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API compatibles OpenAI", @@ -1235,6 +1268,8 @@ "page": "page", "Paginate": "Paginer", "Parameters": "Réglages", + "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.": "", "Password": "Mot de passe", "Passwords do not match.": "Les mots de passe ne correspondent pas.", "Paste Large Text as File": "Coller un texte volumineux comme fichier", @@ -1260,7 +1295,6 @@ "Pipe": "Pipeline", "Pipeline deleted successfully": "Le pipeline a été supprimé avec succès", "Pipeline downloaded successfully": "Le pipeline a été téléchargé avec succès", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines est un système de plug‑ins permettant l’exécution arbitraire de code —", "Pipelines Not Detected": "Aucun pipelines détecté", "Pipelines Valves": "Vannes de pipelines", @@ -1499,6 +1533,7 @@ "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.": "Définit les séquences d'arrêt à utiliser. Lorsque ce motif est rencontré, le LLM cessera de générer du texte et retournera. Plusieurs motifs d'arrêt peuvent être définis en spécifiant plusieurs réglages d'arrêt distincts dans un fichier modèle.", "Setting": "", "Settings": "Réglages", + "Settings Permissions": "", "Settings saved successfully!": "Réglages enregistrés avec succès !", "Share": "Partager", "Share Chat": "Partage de conversation", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Erreur de reconnaissance vocale : {{error}}", "Speech-to-Text": "Reconnaissance vocale", "Speech-to-Text Engine": "Moteur de reconnaissance vocale", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Début du canal", "Start Tag": "Balise de départ", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Stop", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Séquence d'arrêt", "Stream Chat Response": "Streamer la réponse de la conversation", @@ -1572,7 +1609,14 @@ "Support": "Supporter", "Support this plugin:": "Supporter ce module", "Supported MIME Types": "Types MIME pris en charge", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synchroniser le répertoire", + "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": "Système", "System Instructions": "Instructions système", "System Prompt": "Prompt système", @@ -1617,6 +1661,7 @@ "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.": "Largeur en pixels à laquelle les images doivent être compressées. Laisser vide pour ne pas compresser.", "Theme": "Thème", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "En train de réfléchir...", "This action cannot be undone. Do you wish to continue?": "Cette action ne peut pas être annulée. Souhaitez-vous continuer ?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Ce canal a été créé le {{createdAt}}. Voici le tout début du canal {{channelName}}.", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Pipeline de téléchargement", "Upload Progress": "Progression de l'envoi", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Progression du téléchargement\u00a0: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "L'URL est requise", @@ -1748,6 +1794,7 @@ "User Groups": "Groupes d'utilisateurs", "User location successfully retrieved.": "L'emplacement de l'utilisateur a été récupéré avec succès.", "User menu": "Menu utilisateur", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooks utilisateur", "Username": "Nom d'utilisateur", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI fera des requêtes à \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Que cherchez-vous à accomplir ?", "What are you working on?": "Sur quoi travaillez-vous ?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Quoi de neuf dans", "What's on your mind?": "", "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.": "Lorsqu'il est activé, le modèle répondra à chaque message de la conversation en temps réel, générant une réponse dès que l'utilisateur envoie un message. Ce mode est utile pour les applications de conversation en direct, mais peut affecter les performances sur un matériel plus lent.", "wherever you are": "où que vous soyez", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Indique si la sortie doit être paginée. Chaque page sera séparée par une règle horizontale et un numéro de page. La valeur par défaut est False.", "Whisper (Local)": "Whisper (local)", + "Who can share to this group": "", "Why?": "Pourquoi ?", "Widescreen Mode": "Mode grand écran", "Width": "Largeur", + "Wikipedia": "", "Won": "Victoires", "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.": "Fonctionne avec top-k. Une valeur élevée (par exemple, 0,95) conduira à un texte plus diversifié, tandis qu'une valeur plus faible (par exemple, 0,5) générera un texte plus ciblé et conservateur.", "Workspace": "Espace de travail", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "URL de l'instance Yacy", "Yacy Password": "Mot de passe Yacy", "Yacy Username": "Nom d'utilisateur Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Hier", "Yesterday at {{LOCALIZED_TIME}}": "Hier à {{LOCALIZED_TIME}}", "You": "Vous", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Vous ne pouvez discuter qu'avec un maximum de {{maxCount}} fichier(s) à la fois.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Vous pouvez personnaliser vos interactions avec les LLM en ajoutant des mémoires à l'aide du bouton « Gérer » ci-dessous, ce qui les rendra plus utiles et mieux adaptées à vos besoins.", "You cannot upload an empty file.": "Vous ne pouvez pas envoyer un fichier vide.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "Votre compte", "Your account status is currently pending activation.": "Votre statut de compte est actuellement en attente d'activation.", "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.": "L'intégralité de votre contribution ira directement au développeur du plugin ; Open WebUI ne prend aucun pourcentage. Cependant, la plateforme de financement choisie peut avoir ses propres frais.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "Langue de Youtube", "Youtube Proxy URL": "URL du proxy YouTube" diff --git a/src/lib/i18n/locales/gl-ES/translation.json b/src/lib/i18n/locales/gl-ES/translation.json index 8ba25d5c10..cf7e9aef11 100644 --- a/src/lib/i18n/locales/gl-ES/translation.json +++ b/src/lib/i18n/locales/gl-ES/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Axustar estas opcions aplicará os cambios universalmente a todos os usuarios.", "admin": "admin", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Panel de Administración", "Admin Settings": "Configuración de Administrador", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Os administradores teñen acceso a todas as ferramentas en todo momento; os usuarios necesitan ferramentas asignadas por modelo no espacio de trabajo.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Permitir asubida de Arquivos", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Permitir voces non locales", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "e {{COUNT}} mais", "and create a new shared link.": "e xerar un novo enlace compartido.", "Android": "", + "Anyone": "", "API Base URL": "Dirección URL da API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Chave da API ", @@ -175,6 +176,7 @@ "Authenticate": "Autenticar", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Copiar a resposta automáticamente o portapapeis", "Auto-playback response": "Respuesta de reproducción automática", "Autocomplete Generation": "xeneración de autocompletado", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "API de autenticación para a instancia de AUTOMATIC1111", "AUTOMATIC1111 Base URL": "Dirección URL de AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "A dirección URL de AUTOMATIC1111 e requerida.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Lista dispoñible", "Available Tools": "", "available users": "usuarios dispoñibles", @@ -201,6 +204,7 @@ "before": "antes", "Being lazy": "Ser pregizeiro", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Punto final da busqueda de Bing versión V7", "Bing Search V7 Subscription Key": "Chave de suscripción da busqueda de Bing versión V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Chave de API da busqueda Brave", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Verificar actualizacions", "Checking for updates...": "Verificando actualizacions...", "Choose a model before saving...": "Escolle un modelo antes de gardar os cambios...", + "Chunk Min Size Target": "", "Chunk Overlap": "Superposición de fragmentos", "Chunk Size": "Tamaño de fragmentos", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Cifrado", "Citation": "Cita", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Execución de código", - "Code Execution": "Execución de código", "Code Execution Engine": "Motor de execución de código", "Code Execution Timeout": "Tempo de espera esgotado para a execución de código", "Code formatted successfully": "Formateouse correctamente o código.", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contacta o administrador para obter acceso o WebUI", "Content": "Contido", "Content Extraction Engine": "Motor extractor de contido", + "Content lengths (character counts only)": "", "Continue Response": "Continuar Respuesta", "Continue with {{provider}}": "Continuar co {{provider}}", "Continue with Email": "Continuar co email", @@ -393,6 +401,7 @@ "Database": "Base de datos", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Decembro", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Sumérgete no coñecemento", "Do not install functions from sources you do not fully trust.": "Non instale funcións desde fontes nas que no confíe totalmente.", "Do not install tools from sources you do not fully trust.": "Non instale ferramentas desde fontes nas que no confíe totalmente.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Documentación", - "Documents": "Documentos", "does not make any external connections, and your data stays securely on your locally hosted server.": "non realiza ninguna conexión externa y sus datos permanecen seguros en su servidor alojado localmente.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Non obteñas pipelines aleatorias de fontes non fiables.", @@ -493,11 +502,14 @@ "Done": "Feito", "Download": "Descargar", "Download & Delete": "Descargar e eliminar", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Descarga cancelada", "Download Database": "Descarga a Base de Datos", + "Downloading stats...": "", "Draw": "Dibujar", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "p.ej. '30s','10m'. Unidades válidas detempo son 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "e.g. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Ingresa a chave de API da busqueda de Bocha", "Enter Brave Search API Key": "Ingresa a chave de API de busqueda de Brave", "Enter certificate path": "Ingrese a ruta do certificado", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Ingresar superposición de fragmentos", "Enter Chunk Size": "Ingrese o tamaño do fragmento", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Ingresa a URL sin procesar de Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Ingrese o tamaño da imaxen (p.ej. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Ingrese a chave API de Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Ingrese o contrasinal de Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Ingrese a chave API de Kagi Search", "Enter Key Behavior": "Ingrese o comportamento da chave", "Enter language codes": "Ingrese códigos de idioma", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Ingresa o ID do modelo", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Características", "Features Permissions": "Permisos de características", "February": "Febreiro", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Historial de retroalimentación", - "Feedbacks": "Retroalimentacions", "Feel free to add specific details": "Libre de agregar detalles específicos", "Female": "", "File": "Arquivo", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Destectouse suplantación de pegadas: Non puderon usarse as iniciais como avatar. Por defecto utilizase a imaxen de perfil predeterminada.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Carpeta eliminada correctamente", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "O nome da carpeta non pode estar vacío", "Folder name updated successfully": "Nombre da carpeta actualizado correctamente", @@ -826,7 +846,6 @@ "General": "General", "Generate": "", "Generate an image": "Generar unha imaxen", - "Generate Image": "Generar imaxen", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "xeneración de consultas de búsqueda", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Empezar con {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Buena Respuesta", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "chave API de Google PSE", "Google PSE Engine Id": "ID do motor PSE de Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grupo", "Group Channel": "", "Group created successfully": "Grupo creado correctamente", @@ -895,7 +916,6 @@ "Image Prompt Generation": "xeneración de prompt de imaxen", "Image Prompt Generation Prompt": "Prompt de xeneración de prompt de imaxen", "Image Size": "", - "Images": "imaxes", "Import": "", "Import Chats": "Importar chats", "Import Config from JSON File": "Importar configuración desde Arquivo JSON", @@ -927,6 +947,7 @@ "Integration": "Integración", "Integrations": "", "Interface": "Interfaz", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Formato de Arquivo inválido.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "está escribindo...", "Italic": "", "January": "Xaneiro", + "Jina API Base URL": "", "Jina API Key": "chave API de Jina", "join our Discord for help.": "Únase o noso Discord para obter axuda.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "Deixa vacío para incluir todos os modelos o seleccione modelos específicos", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Deixa vacío para usar o prompt predeterminado, o ingrese un prompt personalizado", "Leave model field empty to use the default model.": "Deixa o campo do modelo vacío para usar o modelo predeterminado.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Marzo", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Cantidad máxima de cargas", "Max Upload Size": "Tamaño máximo de Cargas", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Podense descargar un máximo de 3 modelos simultáneamente. Por favor, intenteo de novo mais tarde.", "May": "Mayo", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "As memorias accesibles por os LLMs mostraránse aquí.", "Memory": "Memoria", "Memory added successfully": "Memoria añadida correctamente", @@ -1051,6 +1077,7 @@ "Merge Responses": "Fusionar Respuestas", "Merged Response": "Resposta combinada", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "a calificación de mensaxes debe estar habilitada para usar esta función", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Os mensaxes que envíe despois de xerar su enlace no compartiránse. os usuarios co enlace podrán ver o chat compartido.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Nombre do modelo", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Modelo no seleccionado", "Model Params": "Parámetros do modelo", "Model Permissions": "Permisos do modelo", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Modelo actualizado correctamente", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "chave API de Mojeek Search", "More": "mais", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Non ten distancia disponible", "No expiration can pose security risks.": "", - "No feedbacks found": "No se encontraron retroalimentacions", + "No feedback found": "", "No file selected": "Ningún arquivo fué seleccionado", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "No se seleccionaron modelos", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "No se han encontrado resultados", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Solo os usuarios y grupos con permiso pueden acceder", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "¡Ups! Parece que a URL no es válida. Vuelva a verificar e inténtelo novamente.", "Oops! There are files still uploading. Please wait for the upload to complete.": "¡Ups! Todavía hay arquivos subiendo. Por favor, espere a que a subida se complete.", "Oops! There was an error in the previous response.": "¡Ups! Hubo un error en a resposta anterior.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI usa faster-whisper internamente.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI usa SpeechT5 y embeddings de locutores CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Aversión de Open WebUI (v{{OPEN_WEBUI_VERSION}}) es inferior a aversión requerida (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "Páxina", "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.": "", "Password": "Contrasinal ", "Passwords do not match.": "", "Paste Large Text as File": "Pegar texto grande como arquivo", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline borrada exitosamente", "Pipeline downloaded successfully": "Pipeline descargada exitosamente", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines é un sistema de complementos con execución arbitraria de código —", "Pipelines Not Detected": "Pipeline No Detectada", "Pipelines Valves": "Tuberías Válvulas", @@ -1498,6 +1532,7 @@ "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.": "Establece as secuencias de parada a usar. Cuando se encuentre este patrón, o LLM dejará de generar texto y devolverá. Se pueden establecer varios patrones de parada especificando múltiples parámetros de parada separados en un arquivo de modelo.", "Setting": "", "Settings": "Configuración", + "Settings Permissions": "", "Settings saved successfully!": "¡Configuración gardada con éxito!", "Share": "Compartir", "Share Chat": "Compartir Chat", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Error de recoñecemento de voz: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Motor de voz a texto", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Inicio da canle", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Detener", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Detener secuencia", "Stream Chat Response": "Transmitir resposta de chat", @@ -1571,7 +1608,14 @@ "Support": "Soporte", "Support this plugin:": "Brinda soporte a este plugin:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sincroniza directorio", + "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": "Sistema", "System Instructions": "Instruccions do sistema", "System Prompt": "Prompt do sistema", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Pensando...", "This action cannot be undone. Do you wish to continue?": "Esta acción no se puede deshacer. ¿Desea continuar?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Subir Pipeline", "Upload Progress": "Progreso de carga", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Localización do usuario recuperada con éxito.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Nombre de usuario", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI hará solicitudes a \"{{url}}/chat/completions\"", "What are you trying to achieve?": "¿Qué estás tratando de lograr?", "What are you working on?": "¿En qué estás trabajando?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Novedades en", "What's on your mind?": "", "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.": "Cando está habilitado, o modelo responderá a cada mensaxe de chat en tempo real, generando unha resposta tan pronto como o usuario envíe un mensaxe. Este modo es útil para aplicacions de chat en vivo, pero puede afectar o rendimiento en hardware mais lento.", "wherever you are": "Donde queira que estés", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", "Whisper (Local)": "Xextor de voz (Local)", + "Who can share to this group": "", "Why?": "¿Por qué?", "Widescreen Mode": "Modo de pantalla ancha", "Width": "", + "Wikipedia": "", "Won": "Ganado", "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.": "Funciona xunto con top-k. Un valor máis alto (por exemplo, 0,95) dará lugar a un texto máis diverso, mentres que un valor máis baixo (por exemplo, 0,5) xerará un texto máis centrado e conservador.", "Workspace": "Espacio de traballo", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Onte", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Vostede", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Solo puede chatear con un máximo de {{maxCount}} arquivo(s) a la vez.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Puede personalizar as suas interaccions con LLMs añadiendo memorias a través do botón 'Xestionar' debajo, haciendo que sean mais útiles y personalizados para vostede.", "You cannot upload an empty file.": "Non pode subir un arquivo vacío.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "O estado da sua conta actualmente encontrase pendente de activación.", "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.": "A sua contribución completa irá directamente o desarrollador do plugin; Open WebUI non toma ningun porcentaxe. Sin embargo, a plataforma de financiación elegida podría ter as suas propias tarifas.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index 0740298032..e7a9013618 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "התאמת הגדרות אלו תחול על כל המשתמשים.", "admin": "מנהל", "Admin": "מנהל", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "אפשר העלאת קובץ", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "וצור קישור משותף חדש.", "Android": "", + "Anyone": "", "API Base URL": "כתובת URL בסיסית ל-API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "מפתח API", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "אוטומטי", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "העתקה אוטומטית של תגובה ללוח", "Auto-playback response": "תגובת השמעה אוטומטית", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "כתובת URL בסיסית של AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "נדרשת כתובת URL בסיסית של AUTOMATIC1111", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "כלים זמינים", "available users": "משתמשים זמינים", @@ -201,6 +204,7 @@ "before": "לפני", "Being lazy": "להיות עצלן", "Beta": "בטא", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "מפתח API של חיפוש אמיץ", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "בדוק עדכונים", "Checking for updates...": "בודק עדכונים...", "Choose a model before saving...": "בחר מודל לפני השמירה...", + "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.": "", "Ciphers": "", "Citation": "ציטוט", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "הרצת קוד", - "Code Execution": "הרצת קוד", "Code Execution Engine": "מנוע הרצת קוד", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "תוכן", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "המשך תגובה", "Continue with {{provider}}": "המשך עם {{provider}}", "Continue with Email": "המשך עם מייל", @@ -393,6 +401,7 @@ "Database": "מסד נתונים", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "דצמבר", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "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.": "אל תמשוך pipelines אקראיים ממקורות שאינך סומך עליהם.", @@ -493,11 +502,14 @@ "Done": "", "Download": "הורד", "Download & Delete": "הורדה ומחיקה", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "ההורדה בוטלה", "Download Database": "הורד מסד נתונים", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "למשל '30s', '10m'. יחידות זמן חוקיות הן 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "הזן מפתח API של חיפוש אמיץ", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "הזן חפיפת נתונים", "Enter Chunk Size": "הזן גודל נתונים", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "הזן כתובת URL של Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "הזן גודל תמונה (למשל 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "הזן קודי שפה", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "פברואר", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "נא להוסיף פרטים ספציפיים לפי רצון", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "התגלתה הזיית טביעת אצבע: לא ניתן להשתמש בראשי תיבות כאווטאר. משתמש בתמונת פרופיל ברירת מחדל.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "כללי", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "יצירת שאילתת חיפוש", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "גלובלי", "Good Response": "תגובה טובה", + "Google": "", "Google Drive": "", "Google PSE API Key": "מפתח API של Google PSE", "Google PSE Engine Id": "מזהה מנוע PSE של Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "קבוצה", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "תמונות", "Import": "", "Import Chats": "יבוא צ'אטים", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "ממשק", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "מקליד...", "Italic": "", "January": "ינואר", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "הצטרף ל-Discord שלנו לעזרה.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "מרץ", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ניתן להוריד מקסימום 3 מודלים בו זמנית. אנא נסה שוב מאוחר יותר.", "May": "מאי", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "מזכירים נגישים על ידי LLMs יוצגו כאן.", "Memory": "זיכרון", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "תגובה ממוזגת", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "דירוג הודעות צריך להיות מאופשר כדי להשתמש בפיצ'ר הזה", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "הודעות שתשלח לאחר יצירת הקישור לא ישותפו. משתמשים עם כתובת האתר יוכלו לצפות בצ'אט המשותף.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "שם המודל", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "לא נבחר מודל", "Model Params": "פרמטרי המודל", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "עוד", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "לא נמצאו תוצאות", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "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.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "API של OpenAI", @@ -1235,6 +1268,8 @@ "page": "עמוד", "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.": "", "Password": "סיסמה", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "צינורות", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines הוא מערכת תוספים עם יכולת להריץ קוד שרירותי —", "Pipelines Not Detected": "", "Pipelines Valves": "צינורות שסתומים", @@ -1499,6 +1533,7 @@ "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.": "", "Setting": "", "Settings": "הגדרות", + "Settings Permissions": "", "Settings saved successfully!": "ההגדרות נשמרו בהצלחה!", "Share": "שתף", "Share Chat": "שתף צ'אט", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "שגיאת תחקור שמע: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "מנוע תחקור שמע", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "תחילת הערוץ", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "סידור עצירה", "Stream Chat Response": "", @@ -1572,7 +1609,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "מערכת", "System Instructions": "", "System Prompt": "תגובת מערכת", @@ -1617,6 +1661,7 @@ "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.": "", "Theme": "נושא", + "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.": "", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "", "Upload Progress": "תקדמות העלאה", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "מה חדש ב", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "סביבה", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "אתמול", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "אתה", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index 2e790c08f2..d267131542 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "इन सेटिंग्स को समायोजित करने से परिवर्तन सभी उपयोगकर्ताओं पर सार्वभौमिक रूप से लागू होंगे।", "admin": "व्यवस्थापक", "Admin": "", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "और एक नई साझा लिंक बनाएं.", "Android": "", + "Anyone": "", "API Base URL": "एपीआई बेस यूआरएल", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "एपीआई कुंजी", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "क्लिपबोर्ड पर प्रतिक्रिया ऑटोकॉपी", "Auto-playback response": "ऑटो-प्लेबैक प्रतिक्रिया", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 बेस यूआरएल", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 का बेस यूआरएल आवश्यक है।", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "उपलब्ध उपयोगकर्ता", @@ -201,6 +204,7 @@ "before": "पहले", "Being lazy": "आलसी होना", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave सर्च एपीआई कुंजी", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "अपडेट के लिए जाँच", "Checking for updates...": "अपडेट के लिए जांच कर रहा है...", "Choose a model before saving...": "सहेजने से पहले एक मॉडल चुनें...", + "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.": "", "Ciphers": "", "Citation": "उद्धरण", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "सामग्री", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "प्रतिक्रिया जारी रखें", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "डेटाबेस", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "डिसेंबर", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "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.": "अविश्वसनीय स्रोतों से यादृच्छिक पाइपलाइन न लें।", @@ -493,11 +502,14 @@ "Done": "", "Download": "डाउनलोड", "Download & Delete": "डाउनलोड और हटाएँ", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "डाउनलोड रद्द किया गया", "Download Database": "डेटाबेस डाउनलोड करें", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "जैसे '30s', '10m', मान्य समय इकाइयाँ 's', 'm', 'h' हैं।", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Brave सर्च एपीआई कुंजी डालें", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "चंक ओवरलैप दर्ज करें", "Enter Chunk Size": "खंड आकार दर्ज करें", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Github Raw URL दर्ज करें", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "छवि का आकार दर्ज करें (उदा. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "भाषा कोड दर्ज करें", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "फरवरी", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "विशिष्ट विवरण जोड़ने के लिए स्वतंत्र महसूस करें", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "फ़िंगरप्रिंट स्पूफ़िंग का पता चला: प्रारंभिक अक्षरों को अवतार के रूप में उपयोग करने में असमर्थ। प्रोफ़ाइल छवि को डिफ़ॉल्ट पर डिफ़ॉल्ट किया जा रहा है.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "सामान्य", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "खोज क्वेरी जनरेट करना", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "अच्छी प्रतिक्रिया", + "Google": "", "Google Drive": "", "Google PSE API Key": "Google PSE API कुंजी", "Google PSE Engine Id": "Google PSE इंजन आईडी", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "समूह", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "इमेजिस", "Import": "", "Import Chats": "चैट आयात करें", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "इंटरफेस", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "जनवरी", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "मदद के लिए हमारे डिस्कोर्ड में शामिल हों।", "JSON": "ज्ञान प्रकार", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "मार्च", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "अधिकतम 3 मॉडल एक साथ डाउनलोड किये जा सकते हैं। कृपया बाद में पुन: प्रयास करें।", "May": "मेई", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "एलएलएम द्वारा सुलभ यादें यहां दिखाई जाएंगी।", "Memory": "मेमोरी", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "मिली-जुली प्रतिक्रिया", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "अपना लिंक बनाने के बाद आपके द्वारा भेजे गए संदेश साझा नहीं किए जाएंगे। यूआरएल वाले यूजर्स शेयर की गई चैट देख पाएंगे।", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "मॉडल चयनित नहीं है", "Model Params": "मॉडल Params", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "और..", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "कोई परिणाम नहीं मिला", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "उफ़! ऐसा लगता है कि यूआरएल अमान्य है. कृपया दोबारा जांचें और पुनः प्रयास करें।", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "पासवर्ड", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "पाइपलाइनों", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines एक प्लगइन सिस्टम है जिसमें मनमाना कोड चलाया जा सकता है —", "Pipelines Not Detected": "", "Pipelines Valves": "पाइपलाइन वाल्व", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "सेटिंग्स", + "Settings Permissions": "", "Settings saved successfully!": "सेटिंग्स सफलतापूर्वक सहेजी गईं!", "Share": "साझा करें", "Share Chat": "चैट साझा करें", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "वाक् पहचान त्रुटि: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "वाक्-से-पाठ इंजन", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "चैनल की शुरुआत", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "अनुक्रम रोकें", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "सिस्टम", "System Instructions": "", "System Prompt": "सिस्टम प्रॉम्प्ट", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "थीम", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "प्रगति अपलोड करें", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "इसमें नया क्या है", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "वर्कस्पेस", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "कल", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "आप", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/hr-HR/translation.json b/src/lib/i18n/locales/hr-HR/translation.json index 889654a1a1..146caa2db0 100644 --- a/src/lib/i18n/locales/hr-HR/translation.json +++ b/src/lib/i18n/locales/hr-HR/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Podešavanje će se primijeniti univerzalno na sve korisnike.", "admin": "administrator", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Admin ploča", "Admin Settings": "Admin postavke", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Dopusti nelokalne glasove", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "i stvorite novu dijeljenu vezu.", "Android": "", + "Anyone": "", "API Base URL": "Osnovni URL API-ja", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API ključ", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatsko kopiranje odgovora u međuspremnik", "Auto-playback response": "Automatska reprodukcija odgovora", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 osnovni URL", "AUTOMATIC1111 Base URL is required.": "Potreban je AUTOMATIC1111 osnovni URL.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "dostupni korisnici", @@ -201,6 +204,7 @@ "before": "prije", "Being lazy": "Biti lijen", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave tražilica - API ključ", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Provjeri za ažuriranja", "Checking for updates...": "Provjeravam ažuriranja...", "Choose a model before saving...": "Odaberite model prije spremanja...", + "Chunk Min Size Target": "", "Chunk Overlap": "Preklapanje dijelova", "Chunk Size": "Veličina dijela", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Citiranje", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Kontaktirajte admina za WebUI pristup", "Content": "Sadržaj", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Nastavi odgovor", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Baza podataka", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Prosinac", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentacija", - "Documents": "Dokumenti", "does not make any external connections, and your data stays securely on your locally hosted server.": "ne uspostavlja vanjske veze, a vaši podaci ostaju sigurno na vašem lokalno hostiranom poslužitelju.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Ne preuzimajte nasumične pipelines iz izvora kojima ne vjerujete.", @@ -493,11 +502,14 @@ "Done": "", "Download": "Preuzimanje", "Download & Delete": "Preuzmi i izbriši", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Preuzimanje otkazano", "Download Database": "Preuzmi bazu podataka", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "npr. '30s','10m'. Važeće vremenske jedinice su 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Unesite Brave Search API ključ", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Unesite preklapanje dijelova", "Enter Chunk Size": "Unesite veličinu dijela", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Unesite Github sirovi URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Unesite veličinu slike (npr. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Unesite kodove jezika", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Veljača", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "Slobodno dodajte specifične detalje", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Otkriveno krivotvorenje otisaka prstiju: Nemoguće je koristiti inicijale kao avatar. Postavljanje na zadanu profilnu sliku.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Općenito", "Generate": "", "Generate an image": "", - "Generate Image": "Gneriraj sliku", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Generiranje upita za pretraživanje", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "Dobar odgovor", + "Google": "", "Google Drive": "", "Google PSE API Key": "Google PSE API ključ", "Google PSE Engine Id": "ID Google PSE modula", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grupa", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Slike", "Import": "", "Import Chats": "Uvoz razgovora", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Sučelje", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Siječanj", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "pridružite se našem Discordu za pomoć.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Ožujak", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksimalno 3 modela se mogu preuzeti istovremeno. Pokušajte ponovo kasnije.", "May": "Svibanj", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Ovdje će biti prikazana memorija kojoj mogu pristupiti LLM-ovi.", "Memory": "Memorija", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Spojeni odgovor", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Poruke koje pošaljete nakon stvaranja veze neće se dijeliti. Korisnici s URL-om moći će vidjeti zajednički chat.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model nije odabran", "Model Params": "Model parametri", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Više", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Nema rezultata", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Izgleda da je URL nevažeći. Molimo provjerite ponovno i pokušajte ponovo.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Lozinka", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "Cjevovodi", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines je sustav dodataka s proizvoljnim izvršavanjem koda —", "Pipelines Not Detected": "", "Pipelines Valves": "Ventili za cjevovode", @@ -1499,6 +1533,7 @@ "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.": "", "Setting": "", "Settings": "Postavke", + "Settings Permissions": "", "Settings saved successfully!": "Postavke su uspješno spremljene!", "Share": "Podijeli", "Share Chat": "Podijeli razgovor", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Pogreška prepoznavanja govora: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Stroj za prepoznavanje govora", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Početak kanala", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Zaustavi sekvencu", "Stream Chat Response": "", @@ -1572,7 +1609,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "Sustav", "System Instructions": "", "System Prompt": "Sistemski prompt", @@ -1617,6 +1661,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Razmišljam", "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.": "", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Prijenos kanala", "Upload Progress": "Napredak učitavanja", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Što je novo u", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (lokalno)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "Mod širokog zaslona", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "Radna ploča", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Jučer", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Vi", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Možete personalizirati svoje interakcije s LLM-ima dodavanjem uspomena putem gumba 'Upravljanje' u nastavku, čineći ih korisnijima i prilagođenijima vama.", "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 save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Status vašeg računa trenutno čeka aktivaciju.", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/hu-HU/translation.json b/src/lib/i18n/locales/hu-HU/translation.json index 66773cb188..dc281904d7 100644 --- a/src/lib/i18n/locales/hu-HU/translation.json +++ b/src/lib/i18n/locales/hu-HU/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ezen beállítások módosítása minden felhasználóra érvényes lesz.", "admin": "admin", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Admin Panel", "Admin Settings": "Admin beállítások", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Az adminok mindig hozzáférnek minden eszközhöz; a felhasználóknak modellenként kell eszközöket hozzárendelni a munkaterületen.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Fájlfeltöltés engedélyezése", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Nem helyi hangok engedélyezése", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "és még {{COUNT}} db", "and create a new shared link.": "és hozz létre egy új megosztott linket.", "Android": "", + "Anyone": "", "API Base URL": "API alap URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API kulcs", @@ -175,6 +176,7 @@ "Authenticate": "Hitelesítés", "Authentication": "Hitelesítés", "Auto": "Automatikus", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Válasz automatikus másolása a vágólapra", "Auto-playback response": "Automatikus válasz lejátszás", "Autocomplete Generation": "Automatikus kiegészítés generálása", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api hitelesítési karakterlánc", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 alap URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 alap URL szükséges.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Elérhető lista", "Available Tools": "Elérhető eszközök", "available users": "elérhető felhasználók", @@ -201,6 +204,7 @@ "before": "előtt", "Being lazy": "Lustaság", "Beta": "Béta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 végpont", "Bing Search V7 Subscription Key": "Bing Search V7 előfizetési kulcs", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search API kulcs", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Specifikus tokenek növelése vagy büntetése korlátozott válaszokhoz. Az elfogultság értékei -100 és 100 között lesznek rögzítve (beleértve). (Alapértelmezett: nincs)", + "Brave": "", "Brave Search API Key": "Brave Search API kulcs", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Frissítések keresése", "Checking for updates...": "Frissítések keresése...", "Choose a model before saving...": "Válassz modellt mentés előtt...", + "Chunk Min Size Target": "", "Chunk Overlap": "Darab átfedés", "Chunk Size": "Darab méret", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Titkosítási algoritmusok", "Citation": "Idézet", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Kód végrehajtás", - "Code Execution": "Kód végrehajtás", "Code Execution Engine": "Kód végrehajtási motor", "Code Execution Timeout": "Kód végrehajtási időtúllépés", "Code formatted successfully": "Kód sikeresen formázva", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Lépj kapcsolatba az adminnal a WebUI hozzáférésért", "Content": "Tartalom", "Content Extraction Engine": "Tartalom kinyerési motor", + "Content lengths (character counts only)": "", "Continue Response": "Válasz folytatása", "Continue with {{provider}}": "Folytatás {{provider}} szolgáltatóval", "Continue with Email": "Folytatás emaillel", @@ -393,6 +401,7 @@ "Database": "Adatbázis", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "December", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Merülj el a tudásban", "Do not install functions from sources you do not fully trust.": "Ne telepíts funkciókat olyan forrásokból, amelyekben nem bízol teljesen.", "Do not install tools from sources you do not fully trust.": "Ne telepíts eszközöket olyan forrásokból, amelyekben nem bízol teljesen.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "Docling szerver URL szükséges.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentáció", - "Documents": "Dokumentumok", "does not make any external connections, and your data stays securely on your locally hosted server.": "nem létesít külső kapcsolatokat, és az adataid biztonságban maradnak a helyileg hosztolt szervereden.", "Domain Filter List": "Domain szűrőlista", "don't fetch random pipelines from sources you don't trust.": "Ne tölts le véletlenszerű pipeline-okat megbízhatatlan forrásokból.", @@ -493,11 +502,14 @@ "Done": "Kész", "Download": "Letöltés", "Download & Delete": "Letöltés és törlés", + "Download as JSON": "", "Download as SVG": "Letöltés SVG-ként", "Download canceled": "Letöltés megszakítva", "Download Database": "Adatbázis letöltése", + "Downloading stats...": "", "Draw": "Rajzolás", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "pl. '30s','10m'. Érvényes időegységek: 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "pl. \"json\" vagy egy JSON séma", "e.g. 60": "pl. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Add meg a Bocha Search API kulcsot", "Enter Brave Search API Key": "Add meg a Brave Search API kulcsot", "Enter certificate path": "Add meg a tanúsítvány útvonalát", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Add meg a darab átfedést", "Enter Chunk Size": "Add meg a darab méretet", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Add meg vesszővel elválasztott \"token:bias_érték\" párokat (példa: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Add meg a Github Raw URL-t", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Add meg a kép méretet (pl. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Add meg a Jina API kulcsot", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Add meg a Jupyter jelszavát", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Add meg a Kagi Search API kulcsot", "Enter Key Behavior": "Add meg a kulcs viselkedését", "Enter language codes": "Add meg a nyelvi kódokat", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Add meg a Mistral API kulcsot", "Enter Model ID": "Add meg a modell azonosítót", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Funkciók", "Features Permissions": "Funkciók engedélyei", "February": "Február", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Visszajelzés előzmények", - "Feedbacks": "Visszajelzések", "Feel free to add specific details": "Nyugodtan adj hozzá specifikus részleteket", "Female": "", "File": "Fájl", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Ujjlenyomat hamisítás észlelve: Nem lehet a kezdőbetűket avatárként használni. Alapértelmezett profilkép használata.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Mappa sikeresen törölve", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "A mappa neve nem lehet üres.", "Folder name updated successfully": "Mappa neve sikeresen frissítve", @@ -826,7 +846,6 @@ "General": "Általános", "Generate": "", "Generate an image": "Kép generálása", - "Generate Image": "Kép generálása", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Keresési lekérdezés generálása", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Kezdj neki a {{WEBUI_NAME}}-val", "Global": "Globális", "Good Response": "Jó válasz", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API kulcs", "Google PSE Engine Id": "Google PSE motor azonosító", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Csoport", "Group Channel": "", "Group created successfully": "Csoport sikeresen létrehozva", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Kép prompt generálás", "Image Prompt Generation Prompt": "Kép prompt generálási prompt", "Image Size": "", - "Images": "Képek", "Import": "", "Import Chats": "Beszélgetések importálása", "Import Config from JSON File": "Konfiguráció importálása JSON fájlból", @@ -927,6 +947,7 @@ "Integration": "Integráció", "Integrations": "", "Interface": "Felület", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Érvénytelen fájlformátum.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "ír...", "Italic": "", "January": "Január", + "Jina API Base URL": "", "Jina API Key": "Jina API kulcs", "join our Discord for help.": "Csatlakozz a Discord szerverünkhöz segítségért.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Hagyja üresen, hogy az összes modellt tartalmazza a \"{{url}}/api/tags\" végpontból", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Hagyja üresen, hogy az összes modellt tartalmazza a \"{{url}}/models\" végpontból", "Leave empty to include all models or select specific models": "Hagyja üresen az összes modell használatához, vagy válasszon ki konkrét modelleket", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Hagyja üresen az alapértelmezett prompt használatához, vagy adjon meg egyéni promptot", "Leave model field empty to use the default model.": "Hagyja üresen a modell mezőt az alapértelmezett modell használatához.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Március", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Maximum feltöltések száma", "Max Upload Size": "Maximum feltöltési méret", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximum 3 modell tölthető le egyszerre. Kérjük, próbálja újra később.", "May": "Május", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Az LLM-ek által elérhető emlékek itt jelennek meg.", "Memory": "Memória", "Memory added successfully": "Memória sikeresen hozzáadva", @@ -1051,6 +1077,7 @@ "Merge Responses": "Válaszok egyesítése", "Merged Response": "Összevont válasz", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Az üzenetértékelésnek engedélyezve kell lennie ehhez a funkcióhoz", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "A link létrehozása után küldött üzenetei nem lesznek megosztva. A URL-lel rendelkező felhasználók megtekinthetik a megosztott beszélgetést.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Modell neve", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Nincs kiválasztva modell", "Model Params": "Modell paraméterek", "Model Permissions": "Modell engedélyek", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Modell sikeresen frissítve", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Modellek nyilvános megosztása", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API kulcs", "More": "Több", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Nincs elérhető távolság", "No expiration can pose security risks.": "", - "No feedbacks found": "Nem található visszajelzés", + "No feedback found": "", "No file selected": "Nincs kiválasztva fájl", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Nincs kiválasztott modell", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Nincs találat", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Csak a kiválasztott, engedéllyel rendelkező felhasználók és csoportok férhetnek hozzá", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Hoppá! Úgy tűnik, az URL érvénytelen. Kérjük, ellenőrizze és próbálja újra.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Hoppá! Még vannak feltöltés alatt álló fájlok. Kérjük, várja meg a feltöltés befejezését.", "Oops! There was an error in the previous response.": "Hoppá! Hiba történt az előző válaszban.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Az Open WebUI bármely OpenAPI szerver által biztosított eszközöket használhat.", "Open WebUI uses faster-whisper internally.": "Az Open WebUI belsőleg a faster-whispert használja.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Az Open WebUI a SpeechT5-öt és a CMU Arctic hangszóró beágyazásokat használja.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Az Open WebUI verzió (v{{OPEN_WEBUI_VERSION}}) alacsonyabb, mint a szükséges verzió (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "oldal", "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.": "", "Password": "Jelszó", "Passwords do not match.": "", "Paste Large Text as File": "Nagy szöveg beillesztése fájlként", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Folyamat sikeresen törölve", "Pipeline downloaded successfully": "Folyamat sikeresen letöltve", - "Pipelines": "Folyamatok", "Pipelines are a plugin system with arbitrary code execution —": "A Pipelines egy bővítményrendszer tetszőleges kódvégrehajtással —", "Pipelines Not Detected": "Folyamatok nem észlelhetők", "Pipelines Valves": "Folyamat szelepek", @@ -1498,6 +1532,7 @@ "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.": "Beállítja a használandó leállítási szekvenciákat. Ha ezt a mintát észleli, az LLM leállítja a szöveg generálását és visszatér. Több leállítási minta is megadható különálló stop paraméterek megadásával egy modellfájlban.", "Setting": "", "Settings": "Beállítások", + "Settings Permissions": "", "Settings saved successfully!": "Beállítások sikeresen mentve!", "Share": "Megosztás", "Share Chat": "Beszélgetés megosztása", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Beszédfelismerési hiba: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Beszéd-szöveg motor", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "A csatorna eleje", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Leállítás", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Leállítási szekvencia", "Stream Chat Response": "Chat válasz streamelése", @@ -1571,7 +1608,14 @@ "Support": "Támogatás", "Support this plugin:": "Támogassa ezt a bővítményt:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Könyvtár szinkronizálása", + "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": "Rendszer", "System Instructions": "Rendszer utasítások", "System Prompt": "Rendszer prompt", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Téma", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Gondolkodik...", "This action cannot be undone. Do you wish to continue?": "Ez a művelet nem vonható vissza. Szeretné folytatni?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Ez a csatorna {{createdAt}} időpontban jött létre. Ez a {{channelName}} csatorna legeslegeleje.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Folyamat feltöltése", "Upload Progress": "Feltöltési folyamat", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Felhasználó helye sikeresen lekérve.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "Felhasználói webhookok", "Username": "Felhasználónév", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "A WebUI kéréseket küld a \"{{url}}/chat/completions\" címre", "What are you trying to achieve?": "Mit próbálsz elérni?", "What are you working on?": "Min dolgozol?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Mi újság a", "What's on your mind?": "", "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.": "Ha engedélyezve van, a modell valós időben válaszol minden csevegőüzenetre, amint a felhasználó elküldi az üzenetet. Ez a mód hasznos élő csevegőalkalmazásokhoz, de lassabb hardveren befolyásolhatja a teljesítményt.", "wherever you are": "bárhol is vagy", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", "Whisper (Local)": "Whisper (helyi)", + "Who can share to this group": "", "Why?": "Miért?", "Widescreen Mode": "Szélesvásznú mód", "Width": "", + "Wikipedia": "", "Won": "Nyert", "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.": "A top-k-val együtt működik. Magasabb érték (pl. 0,95) változatosabb szöveget eredményez, alacsonyabb érték (pl. 0,5) fókuszáltabb és konzervatívabb szöveget generál.", "Workspace": "Munkaterület", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Tegnap", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Ön", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Egyszerre maximum {{maxCount}} fájllal tud csevegni.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Az LLM-ekkel való interakcióit személyre szabhatja emlékek hozzáadásával a lenti 'Kezelés' gomb segítségével, így azok még hasznosabbak és személyre szabottabbak lesznek.", "You cannot upload an empty file.": "Nem tölthet fel üres fájlt.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Fiókja jelenleg aktiválásra vár.", "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.": "A teljes hozzájárulása közvetlenül a bővítmény fejlesztőjéhez kerül; az Open WebUI nem vesz le százalékot. Azonban a választott támogatási platformnak lehetnek saját díjai.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "YouTube nyelv", "Youtube Proxy URL": "YouTube proxy URL" diff --git a/src/lib/i18n/locales/id-ID/translation.json b/src/lib/i18n/locales/id-ID/translation.json index f79eae18f0..67cbf3d843 100644 --- a/src/lib/i18n/locales/id-ID/translation.json +++ b/src/lib/i18n/locales/id-ID/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Menyesuaikan pengaturan ini akan menerapkan perubahan secara universal ke semua pengguna.", "admin": "admin", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Panel Admin", "Admin Settings": "Pengaturan Admin", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Admin memiliki akses ke semua alat setiap saat; pengguna memerlukan alat yang ditetapkan per model di ruang kerja.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Izinkan suara non-lokal", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "dan membuat tautan bersama baru.", "Android": "", + "Anyone": "", "API Base URL": "URL Dasar API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Kunci API", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Tanggapan Salin Otomatis ke Papan Klip", "Auto-playback response": "Respons pemutaran otomatis", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "URL Dasar AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 URL Dasar diperlukan.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "pengguna yang tersedia", @@ -201,6 +204,7 @@ "before": "sebelum", "Being lazy": "Menjadi malas", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Kunci API Pencarian Berani", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Memeriksa pembaruan", "Checking for updates...": "Memeriksa pembaruan...", "Choose a model before saving...": "Pilih model sebelum menyimpan...", + "Chunk Min Size Target": "", "Chunk Overlap": "Tumpang Tindih Potongan", "Chunk Size": "Ukuran Potongan", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Kutipan", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "Kode berhasil diformat", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Hubungi Admin untuk Akses WebUI", "Content": "Konten", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Lanjutkan Tanggapan", "Continue with {{provider}}": "Lanjutkan dengan {{provider}}", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Basis data", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Desember", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentasi", - "Documents": "Dokumen", "does not make any external connections, and your data stays securely on your locally hosted server.": "tidak membuat koneksi eksternal apa pun, dan data Anda tetap aman di server yang dihosting secara lokal.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Jangan mengambil pipeline acak dari sumber yang tidak Anda percayai.", @@ -493,11 +502,14 @@ "Done": "Selesai", "Download": "Unduh", "Download & Delete": "Unduh & Hapus", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Unduh dibatalkan", "Download Database": "Unduh Basis Data", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "misalnya '30-an', '10m'. Satuan waktu yang valid adalah 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Masukkan Kunci API Pencarian Berani", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Masukkan Tumpang Tindih Chunk", "Enter Chunk Size": "Masukkan Ukuran Potongan", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Masukkan URL Mentah Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Masukkan Ukuran Gambar (mis. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Masukkan kode bahasa", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Februari", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "Jangan ragu untuk menambahkan detail spesifik", "Female": "", "File": "Berkas", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Pemalsuan sidik jari terdeteksi: Tidak dapat menggunakan inisial sebagai avatar. Default ke gambar profil default.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Umum", "Generate": "", "Generate an image": "", - "Generate Image": "Menghasilkan Gambar", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Membuat kueri penelusuran", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "Global", "Good Response": "Respons yang Baik", + "Google": "", "Google Drive": "", "Google PSE API Key": "Kunci API Google PSE", "Google PSE Engine Id": "Id Mesin Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grup", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Gambar", "Import": "", "Import Chats": "Impor Obrolan", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Antarmuka", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Januari", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "bergabunglah dengan Discord kami untuk mendapatkan bantuan.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Maret", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksimal 3 model dapat diunduh secara bersamaan. Silakan coba lagi nanti.", "May": "Mei", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Memori yang dapat diakses oleh LLM akan ditampilkan di sini.", "Memory": "Memori", "Memory added successfully": "Memori berhasil ditambahkan", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Tanggapan yang Digabungkan", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Pesan yang Anda kirim setelah membuat tautan tidak akan dibagikan. Pengguna yang memiliki URL tersebut akan dapat melihat obrolan yang dibagikan.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model tidak dipilih", "Model Params": "Parameter Model", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Model berhasil diperbarui", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Lainnya", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "Tidak ada file yang dipilih", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Tidak ada hasil yang ditemukan", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Sepertinya URL tidak valid. Mohon periksa ulang dan coba lagi.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Kata sandi", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline berhasil dihapus", "Pipeline downloaded successfully": "Saluran pipa berhasil diunduh", - "Pipelines": "Saluran pipa", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines adalah sistem plugin dengan eksekusi kode sewenang‑wenang —", "Pipelines Not Detected": "Saluran Pipa Tidak Terdeteksi", "Pipelines Valves": "Katup Saluran Pipa", @@ -1497,6 +1531,7 @@ "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.": "", "Setting": "", "Settings": "Pengaturan", + "Settings Permissions": "", "Settings saved successfully!": "Pengaturan berhasil disimpan!", "Share": "Berbagi", "Share Chat": "Bagikan Obrolan", @@ -1540,6 +1575,7 @@ "Speech recognition error: {{error}}": "Kesalahan pengenalan suara: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Mesin Pengenal Ucapan ke Teks", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Awal saluran", "Start Tag": "", @@ -1550,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Hentikan Urutan", "Stream Chat Response": "", @@ -1570,7 +1607,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "Sistem", "System Instructions": "", "System Prompt": "Permintaan Sistem", @@ -1615,6 +1659,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Berpikir", "This action cannot be undone. Do you wish to continue?": "Tindakan ini tidak dapat dibatalkan. Apakah Anda ingin melanjutkan?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1729,6 +1774,7 @@ "Upload Pipeline": "Unggah Pipeline", "Upload Progress": "Kemajuan Unggah", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1746,6 +1792,7 @@ "User Groups": "", "User location successfully retrieved.": "Lokasi pengguna berhasil diambil.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1795,15 +1842,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Apa yang Baru di", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Bisikan (Lokal)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "Mode Layar Lebar", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "Ruang Kerja", @@ -1815,6 +1866,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Kemarin", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Anda", @@ -1822,6 +1875,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Anda dapat mempersonalisasi interaksi Anda dengan LLM dengan menambahkan kenangan melalui tombol 'Kelola' di bawah ini, sehingga lebih bermanfaat dan disesuaikan untuk Anda.", "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 save this prompt.": "", "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.": "", @@ -1833,6 +1889,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Status akun Anda saat ini sedang menunggu aktivasi.", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/ie-GA/translation.json b/src/lib/i18n/locales/ie-GA/translation.json index 8acf996d4f..950fdab43a 100644 --- a/src/lib/i18n/locales/ie-GA/translation.json +++ b/src/lib/i18n/locales/ie-GA/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Cuirfear na socruithe seo ag coigeartú athruithe go huilíoch ar gach úsáideoir.", "admin": "riarachán", "Admin": "Riarachán", + "Admin Contact Email": "", "Admin Panel": "Painéal Riaracháin", "Admin Settings": "Socruithe Riaracháin", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Bíonn rochtain ag riarthóirí ar na huirlisí go léir i gcónaí; teastaíonn ó úsáideoirí uirlisí a shanntar de réir samhail sa spás oibre.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Ceadaigh Leanúint ar aghaidh leis an bhFreagra", "Allow Delete Messages": "Ceadaigh Teachtaireachtaí a Scriosadh", "Allow File Upload": "Ceadaigh Uaslódáil Comhad", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Ceadaigh Il-Samhlacha i gComhrá", "Allow non-local voices": "Lig guthanna neamh-áitiúla", "Allow Rate Response": "Ceadaigh Freagairt Ráta", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "agus {{COUNT}} eile", "and create a new shared link.": "agus cruthaigh nasc nua roinnte.", "Android": "Android", + "Anyone": "", "API Base URL": "URL Bonn API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "URL Bunúsach API do sheirbhís Marcóra Datalab. Réamhshocraithe go: https://www.datalab.to/api/v1/marker", "API Key": "Eochair API", @@ -175,6 +176,7 @@ "Authenticate": "Fíordheimhnigh", "Authentication": "Fíordheimhniú", "Auto": "Uath", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Freagra AutoCopy go Gearrthaisce", "Auto-playback response": "Freagra uathsheinm", "Autocomplete Generation": "Giniúint Uathchríochnaithe", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "UATHOIBRÍOCH1111 Api Auth Teaghrán", "AUTOMATIC1111 Base URL": "UATHOIBRÍOCH1111 Bun URL", "AUTOMATIC1111 Base URL is required.": "Tá URL bonn UATHOIBRÍOCH1111 ag teastáil.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Liosta atá ar fáil", "Available Tools": "Uirlisí ar Fáil", "available users": "úsáideoirí ar fáil", @@ -201,6 +204,7 @@ "before": "roimh", "Being lazy": "A bheith leisciúil", "Beta": "Béite", + "Bing": "", "Bing Search V7 Endpoint": "Cuardach Bing V7 Críochphointe", "Bing Search V7 Subscription Key": "Eochair Síntiúis Bing Cuardach V7", "Bio": "Beathaisnéis", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Eochair API Cuardach Bocha", "Bold": "Trom", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Treisiú nó pionós a ghearradh ar chomharthaí sonracha as freagraí srianta. Déanfar luachanna laofachta a chlampáil idir -100 agus 100 (san áireamh). (Réamhshocrú: ceann ar bith)", + "Brave": "", "Brave Search API Key": "Eochair API Cuardaigh Brave", + "Builtin Tools": "", "Bullet List": "Liosta Urchair", "Button ID": "Aitheantas an Chnaipe", "Button Label": "Lipéad Cnaipe", @@ -256,8 +262,10 @@ "Check for updates": "Seiceáil nuashonruithe", "Checking for updates...": "Seiceáil le haghaidh nuashonruithe...", "Choose a model before saving...": "Roghnaigh samhail sula sábhálann tú...", + "Chunk Min Size Target": "", "Chunk Overlap": "Forluí smután", "Chunk Size": "Méid an Píosa", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Cipéirí", "Citation": "Lua", "Citations": "Comhlua", @@ -293,7 +301,6 @@ "Code Block": "Bloc Cód", "Code Editor": "Eagarthóir Cód", "Code execution": "Cód a fhorghníomhú", - "Code Execution": "Forghníomhú Cóid", "Code Execution Engine": "Inneall Forghníomhaithe Cóid", "Code Execution Timeout": "Teorainn Ama Forghníomhaithe Cóid", "Code formatted successfully": "Cód formáidithe go rathúil", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Déan teagmháil le Riarachán le haghaidh Rochtana WebUI", "Content": "Ábhar", "Content Extraction Engine": "Inneall Eastóscadh Ábhar", + "Content lengths (character counts only)": "", "Continue Response": "Leanúint ar aghaidh", "Continue with {{provider}}": "Lean ar aghaidh le {{provider}}", "Continue with Email": "Lean ar aghaidh le Ríomhphost", @@ -393,6 +401,7 @@ "Database": "Bunachar Sonraí", "Datalab Marker API": "API Marcóra Datalab", "DD/MM/YYYY": "LL/MM/LLLL", + "DDGS Backend": "", "December": "Nollaig", "Decrease UI Scale": "", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Léim isteach eolas", "Do not install functions from sources you do not fully trust.": "Ná suiteáil feidhmeanna ó fhoinsí nach bhfuil muinín iomlán agat.", "Do not install tools from sources you do not fully trust.": "Ná suiteáil uirlisí ó fhoinsí nach bhfuil muinín iomlán agat.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "URL Freastalaí Doling ag teastáil.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Críochphointe Faisnéise Doiciméad ag teastáil.", "Document Intelligence Model": "", "Documentation": "Doiciméadú", - "Documents": "Doiciméid", "does not make any external connections, and your data stays securely on your locally hosted server.": "ní dhéanann sé aon naisc sheachtracha, agus fanann do chuid sonraí go slán ar do fhreastalaí a óstáiltear go háitiúil.", "Domain Filter List": "Liosta Scagairí Fearainn", "don't fetch random pipelines from sources you don't trust.": "ná faigh píblínte randamacha ó fhoinsí nach bhfuil muinín agat astu.", @@ -493,11 +502,14 @@ "Done": "Déanta", "Download": "Íoslódáil", "Download & Delete": "Íoslódáil agus scrios", + "Download as JSON": "", "Download as SVG": "Íoslódáil i SVG", "Download canceled": "Íoslódáil cealaithe", "Download Database": "Íoslódáil Bunachair", + "Downloading stats...": "", "Draw": "Tarraing", "Drop any files here to upload": "Scaoil aon chomhaid anseo le huaslódáil", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "m.sh. '30s', '10m'. Is iad aonaid ama bailí ná 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "m.sh. \"json\" nó scéimre JSON", "e.g. 60": "m.sh. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Cuir isteach Eochair API Bocha Cuardach", "Enter Brave Search API Key": "Cuir isteach Eochair API Brave Cuardach", "Enter certificate path": "Cuir isteach cosán an teastais", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Cuir isteach Chunk Forluí", "Enter Chunk Size": "Cuir isteach Méid an Smután", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Cuir isteach péirí camóg-scartha \"comhartha:luach laofachta\" (mar shampla: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Cuir isteach URL Cuardaigh Gréasáin Sheachtrach", "Enter Firecrawl API Base URL": "Cuir isteach URL Bonn API Firecrawl", "Enter Firecrawl API Key": "Cuir isteach Eochair API Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Cuir isteach ainm an fhillteáin", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Cuir isteach URL Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Cuir isteach dath heicsidheachúlach (m.sh. #FF0000)", "Enter ID": "Cuir isteach aitheantas", "Enter Image Size (e.g. 512x512)": "Iontráil Méid Íomhá (m.sh. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Cuir isteach Eochair API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Cuir isteach cumraíocht JSON (m.sh., {\"disable_links\": true})", "Enter Jupyter Password": "Cuir isteach Pasfhocal Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Cuir isteach Eochair Kagi Cuardach API", "Enter Key Behavior": "Iontráil Iompar Eochair", "Enter language codes": "Cuir isteach cóid teanga", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Cuir isteach URL Bunúsach API Mistral", "Enter Mistral API Key": "Cuir isteach Eochair API Mistral", "Enter Model ID": "Cuir isteach ID an tSamhail", @@ -736,6 +753,7 @@ "Failed to generate title": "Theip ar an teideal a ghiniúint", "Failed to import models": "Theip ar samhail a iompórtáil", "Failed to load chat preview": "Theip ar réamhamharc comhrá a lódáil", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Theip ar lódáil ábhar an chomhaid.", "Failed to move chat": "Theip ar an gcomhrá a bhogadh", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Gnéithe", "Features Permissions": "Ceadanna Gnéithe", "February": "Feabhra", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Sonraí Aiseolais", "Feedback History": "Stair Aiseolais", - "Feedbacks": "Aiseolas", "Feel free to add specific details": "Ná bíodh leisce ort sonraí ar leith a chur leis", "Female": "Baineann", "File": "Comhad", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Braithíodh spoofing méarloirg: Ní féidir teachlitreacha a úsáid mar avatar. Réamhshocrú ar íomhá próifíle réamhshocraithe.", "Firecrawl API Base URL": "URL Bunús API Firecrawl", "Firecrawl API Key": "Eochair API Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Gníomhartha Tapa Snámha", "Focus Chat Input": "Dírigh ar Ionchur Comhrá", "Folder": "Fillteán", "Folder Background Image": "Íomhá Chúlra Fillteáin", "Folder deleted successfully": "Scriosadh an fillteán go rathúil", + "Folder Max File Count": "", "Folder Name": "Ainm an Fhillteáin", "Folder name cannot be empty.": "Ní féidir ainm fillteáin a bheith folamh.", "Folder name updated successfully": "D'éirigh le hainm an fhillteáin a nuashonrú", @@ -826,7 +846,6 @@ "General": "Ginearálta", "Generate": "Gin", "Generate an image": "Gin íomhá", - "Generate Image": "Gin Íomhá", "Generate Message Pair": "Gin Péire Teachtaireachta", "Generated Image": "Íomhá Ginithe", "Generating search query": "Giniúint ceist cuardaigh", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Cuir tús le {{WEBUI_NAME}}", "Global": "Domhanda", "Good Response": "Freagra Mhaith", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Eochair API Google PSE", "Google PSE Engine Id": "ID Inneall Google PSE", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Grúpa", "Group Channel": "", "Group created successfully": "Grúpa cruthaithe go rathúil", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Giniúint Leid Íomhá", "Image Prompt Generation Prompt": "Leid Giniúint Leide Íomhá", "Image Size": "Méid na hÍomhá", - "Images": "Íomhánna", "Import": "Iompórtáil", "Import Chats": "Comhráite iompórtá", "Import Config from JSON File": "Cumraíocht Iompórtáil ó Chomhad JSON", @@ -927,6 +947,7 @@ "Integration": "Comhtháthú", "Integrations": "Comhtháthúcháin", "Interface": "Comhéadan", + "Interface Settings Access": "", "Invalid file content": "Ábhar comhaid neamhbhailí", "Invalid file format.": "Formáid comhaid neamhbhailí.", "Invalid JSON file": "Comhad JSON neamhbhailí", @@ -940,6 +961,7 @@ "is typing...": "ag clóscríobh...", "Italic": "Iodálach", "January": "Eanáir", + "Jina API Base URL": "", "Jina API Key": "Jina API Eochair", "join our Discord for help.": "bí inár Discord chun cabhair a fháil.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Fág folamh chun gach samhail ó chríochphointe \"{{url}}/api/tags\" a chur san áireamh", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Fág folamh chun gach samhail ón gcríochphointe \"{{url}}/models\" a chur san áireamh", "Leave empty to include all models or select specific models": "Fág folamh chun gach samhail a chur san áireamh nó roghnaigh samhail sonracha", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Fág folamh chun an tsamhail réamhshocraithe (voxtral-mini-latest) a úsáid.", "Leave empty to use the default prompt, or enter a custom prompt": "Fág folamh chun an leid réamhshocraithe a úsáid, nó cuir isteach leid saincheaptha", "Leave model field empty to use the default model.": "Fág an réimse samhail folamh chun an tsamhail réamhshocraithe a úsáid.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Bainistigh faisnéis do chuntais.", "March": "Márta", "Markdown": "Marcáil síos", - "Markdown (Header)": "Marcáil síos (Ceanntásc)", + "Markdown Header Text Splitter": "", "Max Speakers": "Uasmhéid Cainteoirí", "Max Upload Count": "Líon Uaslódála Max", "Max Upload Size": "Méid Uaslódála Max", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Is féidir uasmhéid de 3 samhail a íoslódáil ag an am Bain triail as arís níos déanaí.", "May": "Bealtaine", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Taispeánfar cuimhní atá inrochtana ag LLManna anseo.", "Memory": "Cuimhne", "Memory added successfully": "Cuireadh cuimhne leis go", @@ -1051,6 +1077,7 @@ "Merge Responses": "Cumaisc Freagraí", "Merged Response": "Freagra Cumaiscthe", "Message": "Teachtaireacht", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Ba cheart rátáil teachtaireachta a chumasú chun an ghné seo a úsáid", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Ní roinnfear teachtaireachtaí a sheolann tú tar éis do nasc a chruthú. Beidh úsáideoirí leis an URL in ann féachaint ar an gcomhrá roinnte.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Ainm an tSamhail", "Model name already exists, please choose a different one": "Tá ainm samhail ann cheana féin, roghnaigh ceann eile le do thoil", "Model Name is required.": "Tá Ainm an tSamhail de dhíth.", + "Model names and usage frequency": "", "Model not selected": "Níor roghnaíodh an tsamhail", "Model Params": "Paraiméadair Samhail", "Model Permissions": "Ceadanna Samhail", + "Model responses or outputs": "", "Model unloaded successfully": "Díluchtaíodh an tsamhail go rathúil", "Model updated successfully": "An tsamhail nuashonraithe", "Model(s) do not support file upload": "Ní thacaíonn samhail(í) le huaslódáil comhaid", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Iompórtáladh samhlacha go rathúil", "Models Public Sharing": "Samhlacha Comhroinnt Phoiblí", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Eochair API Cuardach Mojeek", "More": "Tuilleadh", "More Concise": "Níos Gonta", @@ -1129,7 +1159,7 @@ "No conversation to save": "Gan aon chomhrá le sábháil", "No distance available": "Níl achar ar fáil", "No expiration can pose security risks.": "Ní féidir le haon dáta éaga rioscaí slándála a chruthú.", - "No feedbacks found": "Níor aimsíodh aon aiseolas", + "No feedback found": "", "No file selected": "Níl aon chomhad roghnaithe", "No files in this knowledge base.": "", "No functions found": "Níor aimsíodh aon fheidhmeanna", @@ -1144,6 +1174,7 @@ "No models selected": "Uimh samhlacha roghnaithe", "No Notes": "Gan Nótaí", "No notes found": "Níor aimsíodh aon nótaí", + "No one": "", "No pinned messages": "", "No prompts found": "Níor aimsíodh aon leideanna", "No results": "Níl aon torthaí le fáil", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Ní cheadaítear ach comhaid marcála síos", "Only select users and groups with permission can access": "Ní féidir ach le húsáideoirí roghnaithe agus le grúpaí a bhfuil cead acu rochtain a fháil", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Is cosúil go bhfuil an URL neamhbhailí. Seiceáil faoi dhó le do thoil agus iarracht arís.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Úps! Tá comhaid fós á n-uaslódáil. Fan go mbeidh an uaslódáil críochnaithe.", "Oops! There was an error in the previous response.": "Úps! Bhí earráid sa fhreagra roimhe seo.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Is féidir le WebUI Oscailte uirlisí a úsáid a sholáthraíonn aon fhreastalaí OpenAPI.", "Open WebUI uses faster-whisper internally.": "Úsáideann Open WebUI cogar níos tapúla go hinmheánach.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Úsáideann Open WebUI úsáidí SpeechT5 agus CMU leabaithe cainteoir Artach.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Tá leagan WebUI oscailte (v{{OPEN_WEBUI_VERSION}}) níos ísle ná an leagan riachtanach (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "leathanach", "Paginate": "Leathanaigh", "Parameters": "Paraiméadair", + "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.": "", "Password": "Pasfhocal", "Passwords do not match.": "Ní hionann na pasfhocail.", "Paste Large Text as File": "Greamaigh Téacs Mór mar Chomhad", @@ -1260,7 +1295,6 @@ "Pipe": "Píopa", "Pipeline deleted successfully": "Scriosta píblíne go rathúil", "Pipeline downloaded successfully": "Íoslódáilte píblíne", - "Pipelines": "Píblínte", "Pipelines are a plugin system with arbitrary code execution —": "Is córas breiseán é Pipelines a ligeann cód a rith go treallach —", "Pipelines Not Detected": "Níor aimsíodh píblínte", "Pipelines Valves": "Comhlaí Píblíne", @@ -1498,6 +1532,7 @@ "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.": "Socraíonn sé na stadanna le húsáid. Nuair a thagtar ar an bpatrún seo, stopfaidh an LLM ag giniúint téacs agus ag filleadh. Is féidir patrúin stad iolracha a shocrú trí pharaiméadair stadanna iolracha a shonrú i gcomhad samhail.", "Setting": "", "Settings": "Socruithe", + "Settings Permissions": "", "Settings saved successfully!": "Socruithe sábhálta go rathúil!", "Share": "Comhroinn", "Share Chat": "Comhroinn Comhrá", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Earráid aitheantais cainte: {{error}}", "Speech-to-Text": "Urlabhra-go-Téacs", "Speech-to-Text Engine": "Inneall Cainte-go-Téacs", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Tosaigh comhrá nua", "Start of the channel": "Tús an chainéil", "Start Tag": "Clib Tosaigh", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Céimeanna", "Stop": "Stad", + "Stop Download": "", "Stop Generating": "Stop a Ghiniúint", "Stop Sequence": "Stop Seicheamh", "Stream Chat Response": "Freagra Comhrá Sruth", @@ -1571,7 +1608,14 @@ "Support": "Tacaíocht", "Support this plugin:": "Tacaigh leis an mbreiseán seo:", "Supported MIME Types": "Cineálacha MIME a Tacaítear leo", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Eolaire sioncronaithe", + "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": "Córas", "System Instructions": "Treoracha Córas", "System Prompt": "Córas Leid", @@ -1616,6 +1660,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "Meáchan Chuardaigh Hibrideach BM25. 0 níos séimeantacha, 1 níos leicseach. Réamhshocrú 0.5", "The width in pixels to compress images to. Leave empty for no compression.": "An leithead i bpicteilíní le híomhánna a chomhbhrú. Fág folamh mura bhfuil aon chomhbhrú ann.", "Theme": "Téama", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Ag smaoineamh...", "This action cannot be undone. Do you wish to continue?": "Ní féidir an gníomh seo a chur ar ais. Ar mhaith leat leanúint ar aghaidh?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Cruthaíodh an cainéal seo ar {{createdAt}}. Seo tús an chainéil {{channelName}}.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Uaslódáil píblíne", "Upload Progress": "Dul Chun Cinn an Uaslódála", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Dul Chun Cinn Uaslódála: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "Tá URL ag teastáil", @@ -1747,6 +1793,7 @@ "User Groups": "Grúpaí Úsáideoirí", "User location successfully retrieved.": "Fuarthas suíomh an úsáideora go rathúil.", "User menu": "Roghchlár úsáideora", + "User ratings (thumbs up/down)": "", "User Webhooks": "Crúcaí Gréasáin Úsáideoir", "Username": "Ainm Úsáideora", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "Déanfaidh WebUI iarratais ar \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Cad atá tú ag iarraidh a bhaint amach?", "What are you working on?": "Cad air a bhfuil tú ag obair?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Cad atá Nua i", "What's on your mind?": "", "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.": "Nuair a bheidh sé cumasaithe, freagróidh an tsamhail gach teachtaireacht comhrá i bhfíor-am, ag giniúint freagra a luaithe a sheolann an t-úsáideoir teachtaireacht. Tá an mód seo úsáideach le haghaidh feidhmchláir chomhrá beo, ach d'fhéadfadh tionchar a bheith aige ar fheidhmíocht ar chrua-earraí níos moille.", "wherever you are": "aon áit a bhfuil tú", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Cibé acu an ndéanfar an t-aschur a roinnt le leathanaigh nó nach ndéanfar. Beidh riail chothrománach agus uimhir leathanaigh ag scartha ó gach leathanach. Is é Bréag an rogha réamhshocraithe.", "Whisper (Local)": "Whisper (Áitiúil)", + "Who can share to this group": "", "Why?": "Cén fáth?", "Widescreen Mode": "Mód Leathanscáileán", "Width": "Leithead", + "Wikipedia": "", "Won": "Bhuaigh", "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.": "Oibríonn sé le barr-k. Beidh téacs níos éagsúla mar thoradh ar luach níos airde (m.sh., 0.95), agus ginfidh luach níos ísle (m.sh., 0.5) téacs níos dírithe agus níos coimeádaí.", "Workspace": "Spás oibre", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "URL Cás Yacy", "Yacy Password": "Pasfhocal Yacy", "Yacy Username": "Ainm úsáideora Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Inné", "Yesterday at {{LOCALIZED_TIME}}": "Inné ag {{LOCALIZED_TIME}}", "You": "Tú", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Ní féidir leat comhrá a dhéanamh ach le comhad {{maxCount}} ar a mhéad ag an am.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Is féidir leat do chuid idirghníomhaíochtaí le LLManna a phearsantú ach cuimhní cinn a chur leis tríd an gcnaipe 'Bainistigh' thíos, rud a fhágann go mbeidh siad níos cabhrach agus níos oiriúnaí duit.", "You cannot upload an empty file.": "Ní féidir leat comhad folamh a uaslódáil.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "Níl cead agat teachtaireachtaí a sheoladh sa chainéal seo.", "You do not have permission to send messages in this thread.": "Níl cead agat teachtaireachtaí a sheoladh sa snáithe seo.", "You do not have permission to upload files to this knowledge base.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Do Chuntas", "Your account status is currently pending activation.": "Tá stádas do chuntais ar feitheamh faoi ghníomhachtú.", "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.": "Rachaidh do ranníocaíocht iomlán go díreach chuig an bhforbróir breiseán; Ní ghlacann Open WebUI aon chéatadán. Mar sin féin, d'fhéadfadh a tháillí féin a bheith ag an ardán maoinithe roghnaithe.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Teanga Youtube", "Youtube Proxy URL": "URL Seachfhreastalaí YouTube" diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index 4da276dd85..2e759b3bf6 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "La modifica di queste impostazioni applicherà le modifiche universalmente a tutti gli utenti.", "admin": "amministratore", "Admin": "Amministratore", + "Admin Contact Email": "", "Admin Panel": "Pannello di amministrazione", "Admin Settings": "Impostazioni amministratore", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Gli amministratori hanno accesso a tutti gli strumenti in qualsiasi momento; gli utenti necessitano di strumenti assegnati per ogni modello nello spazio di lavoro.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Consenti caricamento file", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Consenti più modelli in chat", "Allow non-local voices": "Consenti voci non locali", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "e {{COUNT}} altro", "and create a new shared link.": "e crea un nuovo link condiviso.", "Android": "Android", + "Anyone": "", "API Base URL": "URL base per API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Chiave API", @@ -175,6 +176,7 @@ "Authenticate": "Autentica", "Authentication": "Autenticazione", "Auto": "Automatico", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Copia automatica della risposta negli appunti", "Auto-playback response": "Riproduzione automatica della risposta", "Autocomplete Generation": "Generazione dell'autocompletamento", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Stringa autenticazione AUTOMATIC1111 Api", "AUTOMATIC1111 Base URL": "URL base AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "L'URL base AUTOMATIC1111 è obbligatorio.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Elenco disponibile", "Available Tools": "Strumenti disponibili", "available users": "utenti disponibili", @@ -201,6 +204,7 @@ "before": "prima", "Being lazy": "Faccio il pigro", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Endpoint di Bing Search V7", "Bing Search V7 Subscription Key": "Chiave di Iscrizione Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Chiave API di Bocha Search", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Potenziare o penalizzare token specifici per risposte vincolate. I valori di bias saranno limitati tra -100 e 100 (incluso). (Predefinito: nessuno)", + "Brave": "", "Brave Search API Key": "Chiave API di ricerca Brave", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Controlla aggiornamenti", "Checking for updates...": "Controllo aggiornamenti...", "Choose a model before saving...": "Scegli un modello prima di salvare...", + "Chunk Min Size Target": "", "Chunk Overlap": "Sovrapposizione chunk", "Chunk Size": "Dimensione chunk", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Cifrari", "Citation": "Citazione", "Citations": "Citazioni", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Esecuzione codice", - "Code Execution": "Esecuzione codice", "Code Execution Engine": "Motore di esecuzione codice", "Code Execution Timeout": "Timeout esecuzione codice", "Code formatted successfully": "Codice formattato con successo", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contatta l'amministratore per l'accesso al servizio WebUI", "Content": "Contenuto", "Content Extraction Engine": "Motore di estrazione contenuti", + "Content lengths (character counts only)": "", "Continue Response": "Continua risposta", "Continue with {{provider}}": "Continua con {{provider}}", "Continue with Email": "Continua con email", @@ -393,6 +401,7 @@ "Database": "Database", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Dicembre", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Immergiti nella conoscenza", "Do not install functions from sources you do not fully trust.": "Non installare funzioni da fonti di cui non ti fidi completamente.", "Do not install tools from sources you do not fully trust.": "Non installare strumenti da fonti di cui non ti fidi completamente.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "L'URL del server Docling è obbligatoria.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Documentazione", - "Documents": "Documenti", "does not make any external connections, and your data stays securely on your locally hosted server.": "non effettua connessioni esterne e i tuoi dati rimangono al sicuro sul tuo server ospitato localmente.", "Domain Filter List": "Elenco filtri dominio", "don't fetch random pipelines from sources you don't trust.": "Non recuperare pipeline casuali da fonti non affidabili.", @@ -493,11 +502,14 @@ "Done": "Fatto", "Download": "Scarica", "Download & Delete": "Scarica e elimina", + "Download as JSON": "", "Download as SVG": "Scarica come SVG", "Download canceled": "Scaricamento annullato", "Download Database": "Scarica database", + "Downloading stats...": "", "Draw": "Disegna", "Drop any files here to upload": "Rilascia qui i file per caricarli", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "ad esempio '30s','10m'. Le unità di tempo valide sono 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "ad esempio \"json\" o uno schema JSON", "e.g. 60": "ad esempio 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Inserisci Chiave API di Bocha Search", "Enter Brave Search API Key": "Inserisci Chiave API di Brave Search", "Enter certificate path": "Inserisci il percorso del certificato", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Inserisci Sovrapposizione Chunk", "Enter Chunk Size": "Inserisci Dimensione Chunk", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Inserisci coppie \"token:valore_bias\" separate da virgole (esempio: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Inserisci URL di Ricerca Web Esterna", "Enter Firecrawl API Base URL": "Inserisci l'URL base dell'API Firecrawl", "Enter Firecrawl API Key": "Inserisci Chiave API Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Inserisci URL Grezzo di Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Inserisci Dimensione Immagine (ad esempio 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Inserisci Chiave API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Inserisci Password Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Inserisci Chiave API Kagi Search", "Enter Key Behavior": "Comportamento Tasto Invio", "Enter language codes": "Inserisci i codici lingua", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Inserisci Chiave API Mistral", "Enter Model ID": "Inserisci ID Modello", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Impossibile caricare il contenuto del file.", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Caratteristiche", "Features Permissions": "Permessi delle funzionalità", "February": "Febbraio", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Dettagli feedback", "Feedback History": "Storico feedback", - "Feedbacks": "Feedback", "Feel free to add specific details": "Sentiti libero/a di aggiungere dettagli specifici", "Female": "", "File": "File", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Rilevato spoofing delle impronte digitali: impossibile utilizzare le iniziali come avatar. Ripristino all'immagine del profilo predefinita.", "Firecrawl API Base URL": "URL base dell'API Firecrawl", "Firecrawl API Key": "Chiave API Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Cartella rimossa con successo", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Il nome della cartella non può essere vuoto.", "Folder name updated successfully": "Nome cartella aggiornato con successo", @@ -826,7 +846,6 @@ "General": "Generale", "Generate": "Genera", "Generate an image": "Genera un'immagine", - "Generate Image": "Genera Immagine", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Generazione query di ricerca", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Inizia con {{WEBUI_NAME}}", "Global": "Globale", "Good Response": "Buona Risposta", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Chiave API PSE di Google", "Google PSE Engine Id": "ID motore PSE di Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Gruppo", "Group Channel": "", "Group created successfully": "Gruppo creato con successo", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Generazione Prompt Immagine", "Image Prompt Generation Prompt": "Prompt per la Generazione di Prompt Immagine", "Image Size": "", - "Images": "Immagini", "Import": "Importa", "Import Chats": "Importa Chat", "Import Config from JSON File": "Importa Configurazione da File JSON", @@ -927,6 +947,7 @@ "Integration": "Integrazione", "Integrations": "", "Interface": "Interfaccia", + "Interface Settings Access": "", "Invalid file content": "Contenuto del file non valido", "Invalid file format.": "Formato file non valido.", "Invalid JSON file": "File JSOn non valido", @@ -940,6 +961,7 @@ "is typing...": "sta digitando...", "Italic": "", "January": "Gennaio", + "Jina API Base URL": "", "Jina API Key": "Chiave API Jina", "join our Discord for help.": "unisciti al nostro Discord per ricevere aiuto.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Lascia vuoto per includere tutti i modelli dall'endpoint \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Lascia vuoto per includere tutti i modelli dall'endpoint \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Lascia vuoto per includere tutti i modelli o seleziona modelli specifici", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Lascia vuoto per utilizzare il prompt predefinito o inserisci un prompt personalizzato", "Leave model field empty to use the default model.": "Lascia vuoto il campo modello per utilizzare il modello predefinito.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Marzo", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "Numero Massimo di Parlanti", "Max Upload Count": "Conteggio massimo di caricamenti", "Max Upload Size": "Dimensione massima di caricamento", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "È possibile scaricare un massimo di 3 modelli contemporaneamente. Riprova più tardi.", "May": "Maggio", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "I memori accessibili ai LLM saranno mostrati qui.", "Memory": "Memoria", "Memory added successfully": "Memoria aggiunta con successo", @@ -1051,6 +1077,7 @@ "Merge Responses": "Unisci Risposte", "Merged Response": "Risposta Unita", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "La valutazione dei messaggi deve essere abilitata per utilizzare questa funzionalità", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "I messaggi inviati dopo la creazione del link non verranno condivisi. Gli utenti con l'URL saranno in grado di visualizzare la chat condivisa.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Nome modello", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Modello non selezionato", "Model Params": "Parametri del modello", "Model Permissions": "Permessi del modello", + "Model responses or outputs": "", "Model unloaded successfully": "Scaricamento dalla memoria del modello riuscito", "Model updated successfully": "Modello aggiornato con successo", "Model(s) do not support file upload": "I/l modello/i non supporta il caricamento file", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Conoscenza condivisione pubblica", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Chiave API di Mojeek Search", "More": "Altro", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Nessuna distanza disponibile", "No expiration can pose security risks.": "", - "No feedbacks found": "Nessun feedback trovato", + "No feedback found": "", "No file selected": "Nessun file selezionato", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Nessun modello selezionato", "No Notes": "Nessuna nota", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Nessun risultato trovato", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Sono consentiti solo file markdown", "Only select users and groups with permission can access": "Solo gli utenti e i gruppi selezionati con autorizzazione possono accedere", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ops! Sembra che l'URL non sia valido. Si prega di ricontrollare e riprovare.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ops! Ci sono file ancora in fase di caricamento. Si prega di attendere il completamento del caricamento.", "Oops! There was an error in the previous response.": "Ops! Si è verificato un errore nella risposta precedente.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI può utilizzare tool forniti da qualsiasi server OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI utilizza faster-whisper internamente.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI utilizza le incorporazioni vocali di SpeechT5 e CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "La versione di Open WebUI (v{{OPEN_WEBUI_VERSION}}) è inferiore alla versione richiesta (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "pagina", "Paginate": "Paginazione", "Parameters": "Parametri", + "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.": "", "Password": "Password", "Passwords do not match.": "", "Paste Large Text as File": "Incolla Molto Testo come File", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline rimossa con successo", "Pipeline downloaded successfully": "Pipeline scaricata con successo", - "Pipelines": "Pipeline", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines è un sistema di plugin con esecuzione arbitraria di codice —", "Pipelines Not Detected": "Pipeline Non Rilevate", "Pipelines Valves": "Valvole per pipelines", @@ -1499,6 +1533,7 @@ "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.": "Imposta le sequenze di arresto da utilizzare. Quando questo modello viene incontrato, l'LLM smetterà di generare testo e restituirà. Più modelli di arresto possono essere impostati specificando più parametri di arresto separati in un file modello.", "Setting": "", "Settings": "Impostazioni", + "Settings Permissions": "", "Settings saved successfully!": "Impostazioni salvate con successo!", "Share": "Condividi", "Share Chat": "Condividi chat", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Errore di riconoscimento vocale: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Motore da voce a testo", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Inizio del canale", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Arresta", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Sequenza di arresto", "Stream Chat Response": "Stream risposta chat", @@ -1572,7 +1609,14 @@ "Support": "Supporto", "Support this plugin:": "Supporta questo plugin:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sincronizza 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.": "", "System": "Sistema", "System Instructions": "Istruzioni di sistema", "System Prompt": "Prompt di sistema", @@ -1617,6 +1661,7 @@ "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.": "La larghezza in pixel per comprimere le immagini. Lascia vuoto per nessuna compressione.", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Sto pensando...", "This action cannot be undone. Do you wish to continue?": "Questa azione non può essere annullata. Vuoi continuare?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Questo canale è stato creato il {{createdAt}}. Questo è l'inizio del canale {{channelName}}.", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Carica Pipeline", "Upload Progress": "Avanzamento Caricamento", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "Posizione utente recuperata con successo.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhook Utente", "Username": "Nome Utente", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI farà richieste a \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Cosa stai cercando di ottenere?", "What are you working on?": "Su cosa stai lavorando?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Novità in", "What's on your mind?": "", "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 abilitato, il modello risponderà a ciascun messaggio della chat in tempo reale, generando una risposta non appena l'utente invia un messaggio. Questa modalità è utile per le applicazioni di chat dal vivo, ma potrebbe influire sulle prestazioni su hardware più lento.", "wherever you are": "Ovunque tu sia", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Specifica se paginare l'output. Ogni pagina sarà separata da una riga orizzontale e dal numero di pagina. Predefinito è Falso.", "Whisper (Local)": "Whisper (Locale)", + "Who can share to this group": "", "Why?": "Perché?", "Widescreen Mode": "Modalità widescreen", "Width": "", + "Wikipedia": "", "Won": "Vinto", "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.": "Lavora insieme a top-k. Un valore più alto (ad esempio, 0,95) porterà a un testo più vario, mentre un valore più basso (ad esempio, 0,5) genererà un testo più focalizzato e conservativo.", "Workspace": "Spazio di lavoro", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "URL dell'istanza Yacy", "Yacy Password": "Password Yacy", "Yacy Username": "Nome utente Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Ieri", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Tu", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Puoi chattare solo con un massimo di {{maxCount}} file alla volta.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Puoi personalizzare le tue interazioni con LLM aggiungendo memorie tramite il pulsante 'Gestisci' qui sotto, rendendole più utili e su misura per te.", "You cannot upload an empty file.": "Non puoi caricare un file vuoto.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Lo stato del tuo account è attualmente in attesa di attivazione.", "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.": "Il tuo intero contributo andrà direttamente allo sviluppatore del plugin; Open WebUI non prende alcuna percentuale. Tuttavia, la piattaforma di finanziamento scelta potrebbe avere le proprie commissioni.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Lingua Youtube", "Youtube Proxy URL": "URL proxy Youtube" diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index c7bac75680..fd7f62b011 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "これらの設定を変更すると、すべてのユーザーに変更が適用されます。", "admin": "管理者", "Admin": "管理者", + "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.": "管理者は全てのツールにアクセスできます。ユーザーからはワークスペースのモデルごとに割り当てられたツールのみ使用可能です。", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "ファイルのアップロードを許可", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "チャットで複数のモデルを許可", "Allow non-local voices": "ローカル以外のボイスを許可", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "および{{COUNT}}件", "and create a new shared link.": "そして、新しい共有リンクを作成します。", "Android": "", + "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 キー", @@ -175,6 +176,7 @@ "Authenticate": "認証", "Authentication": "認証", "Auto": "自動", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "クリップボードへの応答の自動コピー", "Auto-playback response": "応答の自動再生", "Autocomplete Generation": "自動補完の生成", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111のAuthを入力", "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.)": "", "Available list": "利用可能リスト", "Available Tools": "利用可能ツール", "available users": "利用可能なユーザー", @@ -201,6 +204,7 @@ "before": "以前", "Being lazy": "怠惰な", "Beta": "ベータ", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 エンドポイント", "Bing Search V7 Subscription Key": "Bing Search V7 サブスクリプションキー", "Bio": "自己紹介", @@ -209,7 +213,9 @@ "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 Search API Key": "Brave Search APIキー", + "Builtin Tools": "", "Bullet List": "箇条書きリスト", "Button ID": "ボタンID", "Button Label": "ボタンラベル", @@ -256,8 +262,10 @@ "Check for updates": "アップデートを確認", "Checking for updates...": "アップデートを確認しています...", "Choose a model before saving...": "保存する前にモデルを選択してください...", + "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.": "", "Ciphers": "暗号化方式", "Citation": "引用", "Citations": "引用", @@ -293,7 +301,6 @@ "Code Block": "コードブロック", "Code Editor": "", "Code execution": "コードの実行", - "Code Execution": "コードの実行", "Code Execution Engine": "コードの実行エンジン", "Code Execution Timeout": "コードの実行タイムアウト", "Code formatted successfully": "コードフォーマットに成功しました", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "WEBUIへのアクセスについて管理者に問い合わせ下さい。", "Content": "コンテンツ", "Content Extraction Engine": "コンテンツ抽出エンジン", + "Content lengths (character counts only)": "", "Continue Response": "続きの応答", "Continue with {{provider}}": "{{provider}}で続ける", "Continue with Email": "メールで続ける", @@ -393,6 +401,7 @@ "Database": "データベース", "Datalab Marker API": "", "DD/MM/YYYY": "YYYY/MM/DD", + "DDGS Backend": "", "December": "12月", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "知識に飛び込む", "Do not install functions from sources you do not fully trust.": "信頼できないソースからFunctionをインストールしないでください。", "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": "", "Docling Server URL required.": "DoclingサーバーURLが必要です。", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "ドキュメント", - "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.": "信頼できないソースからやみくもにパイプラインを取得しないでください。", @@ -493,11 +502,14 @@ "Done": "完了", "Download": "ダウンロード", "Download & Delete": "ダウンロードして削除", + "Download as JSON": "", "Download as SVG": "SVGとしてダウンロード", "Download canceled": "ダウンロードをキャンセルしました", "Download Database": "データベースをダウンロード", + "Downloading stats...": "", "Draw": "引き分け", "Drop any files here to upload": "ここにファイルをドロップしてアップロード", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "例: '30s'、'10m'。有効な時間単位は 's'、'm'、'h' です。", "e.g. \"json\" or a JSON schema": "例: \"json\" または JSON スキーマ", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Bocha Search APIキーを入力", "Enter Brave Search API Key": "Brave Search APIキーの入力", "Enter certificate path": "証明書パスを入力", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "チャンクオーバーラップを入力", "Enter Chunk Size": "チャンクサイズを入力", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "カンマ区切りの \"token:bias_value\" ペアを入力 (例: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "外部Web検索のURLを入力", "Enter Firecrawl API Base URL": "Firecrawl API Base URLを入力", "Enter Firecrawl API Key": "Firecrawl APIキーを入力", + "Enter Firecrawl Timeout": "", "Enter folder name": "フォルダ名を入力", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Github Raw URLを入力", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "16進数で色を入力", "Enter ID": "IDを入力", "Enter Image Size (e.g. 512x512)": "画像サイズを入力 (例: 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina APIキーを入力", "Enter JSON config (e.g., {\"disable_links\": true})": "JSON 設定を入力 (例: {\"disable_links\": true})", "Enter Jupyter Password": "Jupyterパスワードを入力", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search APIキーを入力", "Enter Key Behavior": "Enter Keyの動作", "Enter language codes": "言語コードを入力", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Mistral APIキーを入力", "Enter Model ID": "モデルIDを入力", @@ -736,6 +753,7 @@ "Failed to generate title": "タイトルの生成に失敗しました。", "Failed to import models": "", "Failed to load chat preview": "チャットプレビューを読み込めませんでした。", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "ファイルの内容を読み込めませんでした。", "Failed to move chat": "チャットの移動に失敗しました。", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "機能", "Features Permissions": "機能の許可", "February": "2月", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "フィードバックの詳細", "Feedback History": "フィードバック履歴", - "Feedbacks": "フィードバック", "Feel free to add specific details": "詳細を追加できます", "Female": "女性", "File": "ファイル", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "フィンガープリントのスプーフィングが検出されました: イニシャルをアバターとして使用できません。デフォルトのプロファイル画像が使用されます。", "Firecrawl API Base URL": "Firecrawl API ベースURL", "Firecrawl API Key": "Firecrawl APIキー", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "フローティング クイックアクション", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "フォルダー削除が成功しました。", + "Folder Max File Count": "", "Folder Name": "フォルダ名", "Folder name cannot be empty.": "フォルダー名を入力してください。", "Folder name updated successfully": "フォルダー名の変更に成功しました。", @@ -826,7 +846,6 @@ "General": "一般", "Generate": "生成", "Generate an image": "画像を生成", - "Generate Image": "画像生成", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "検索クエリの生成", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}}をはじめる", "Global": "グローバル", "Good Response": "良い応答", + "Google": "", "Google Drive": "Google ドライブ", "Google PSE API Key": "Google PSE APIキー", "Google PSE Engine Id": "Google PSE エンジン ID", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "グループ", "Group Channel": "", "Group created successfully": "グループの作成が成功しました。", @@ -895,7 +916,6 @@ "Image Prompt Generation": "画像プロンプト生成", "Image Prompt Generation Prompt": "画像プロンプト生成プロンプト", "Image Size": "", - "Images": "画像", "Import": "インポート", "Import Chats": "チャットをインポート", "Import Config from JSON File": "設定をJSONファイルからインポート", @@ -927,6 +947,7 @@ "Integration": "連携", "Integrations": "", "Interface": "インターフェース", + "Interface Settings Access": "", "Invalid file content": "無効なファイル内容", "Invalid file format.": "無効なファイル形式", "Invalid JSON file": "無効なJSONファイル", @@ -940,6 +961,7 @@ "is typing...": "入力中...", "Italic": "斜体", "January": "1月", + "Jina API Base URL": "", "Jina API Key": "Jina APIキー", "join our Discord for help.": "ヘルプについては、Discord に参加してください。", "JSON": "JSON", @@ -990,6 +1012,7 @@ "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 model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "カスタムプロンプトを入力。空欄ならデフォルトプロンプト", "Leave model field empty to use the default model.": "モデル欄を空欄にしてデフォルトモデルを使用", @@ -1029,10 +1052,12 @@ "Manage your account information.": "あなたのアカウント情報を管理", "March": "3月", "Markdown": "マークダウン", - "Markdown (Header)": "マークダウン (見出し)", + "Markdown Header Text Splitter": "", "Max Speakers": "最大話者数", "Max Upload Count": "最大アップロード数", "Max Upload Size": "最大アップロードサイズ", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "同時にダウンロードできるモデルは最大 3 つです。後でもう一度お試しください。", "May": "5月", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLM がアクセスできるメモリはここに表示されます。", "Memory": "メモリ", "Memory added successfully": "メモリに追加されました。", @@ -1051,6 +1077,7 @@ "Merge Responses": "応答を統合", "Merged Response": "統合された応答", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "この機能を使用するには、メッセージ評価を有効にする必要があります。", "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", @@ -1083,9 +1110,11 @@ "Model Name": "モデル名", "Model name already exists, please choose a different one": "モデル名はすでに存在します。他の名前を入力してください。", "Model Name is required.": "モデル名は必須です。", + "Model names and usage frequency": "", "Model not selected": "モデルが選択されていません", "Model Params": "モデルパラメータ", "Model Permissions": "モデルの許可", + "Model responses or outputs": "", "Model unloaded successfully": "モデルのアンロードが成功しました", "Model updated successfully": "モデルが正常に更新されました", "Model(s) do not support file upload": "モデルはファイルアップロードをサポートしていません", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "モデルの公開共有", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search APIキー", "More": "もっと見る", "More Concise": "より簡潔に", @@ -1129,7 +1159,7 @@ "No conversation to save": "保存する会話がありません。", "No distance available": "距離が利用できません", "No expiration can pose security risks.": "", - "No feedbacks found": "フィードバックが見つかりません", + "No feedback found": "", "No file selected": "ファイルが選択されていません", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "モデルが選択されていません", "No Notes": "ノートがありません", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "結果が見つかりません", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "マークダウンファイルのみが許可されています", "Only select users and groups with permission can access": "許可されたユーザーとグループのみがアクセスできます", + "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.": "おっと! 前の応答にエラーがありました。", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "OpenWebUI は任意のOpenAPI サーバーが提供するツールを使用できます。", "Open WebUI uses faster-whisper internally.": "OpenWebUI は内部でfaster-whisperを使用します。", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "OpenWebUI は SpeechT5とCMU Arctic スピーカー埋め込みを使用します。", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "OpenWebUI のバージョン (v{{OPEN_WEBUI_VERSION}}) は要求されたバージョン (v{{REQUIRED_VERSION}}) より低いです。", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "ページ", "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.": "", "Password": "パスワード", "Passwords do not match.": "パスワードが一致しません。", "Paste Large Text as File": "大きなテキストをファイルとして貼り付ける", @@ -1260,7 +1295,6 @@ "Pipe": "パイプ", "Pipeline deleted successfully": "パイプラインが正常に削除されました", "Pipeline downloaded successfully": "パイプラインが正常にダウンロードされました", - "Pipelines": "パイプライン", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines は任意のコード実行が可能なプラグインシステムです —", "Pipelines Not Detected": "パイプラインは検出されませんでした", "Pipelines Valves": "パイプラインのバルブ", @@ -1497,6 +1531,7 @@ "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はテキスト生成を停止し、結果を返します。複数の停止パターンは、モデルファイル内で複数のstopパラメータを指定することで設定可能です。", "Setting": "", "Settings": "設定", + "Settings Permissions": "", "Settings saved successfully!": "設定が正常に保存されました!", "Share": "共有", "Share Chat": "チャットを共有", @@ -1540,6 +1575,7 @@ "Speech recognition error: {{error}}": "音声認識エラー: {{error}}", "Speech-to-Text": "音声テキスト変換", "Speech-to-Text Engine": "音声テキスト変換エンジン", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "チャンネルの開始", "Start Tag": "", @@ -1550,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "停止", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "ストップシーケンス", "Stream Chat Response": "チャットレスポンスのストリーム", @@ -1570,7 +1607,14 @@ "Support": "サポート", "Support this plugin:": "このプラグインを支援する:", "Supported MIME Types": "対応するMIMEタイプ", + "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.": "", "System": "システム", "System Instructions": "システムインストラクション", "System Prompt": "システムプロンプト", @@ -1615,6 +1659,7 @@ "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.": "画像の圧縮後のピクセル単位での幅。空欄で圧縮を無効化します", "Theme": "テーマ", + "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}}チャンネルの始まりです。", @@ -1729,6 +1774,7 @@ "Upload Pipeline": "パイプラインをアップロード", "Upload Progress": "アップロードの進行状況", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "アップロード状況: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "URLは必須です", @@ -1746,6 +1792,7 @@ "User Groups": "ユーザーグループ", "User location successfully retrieved.": "ユーザーの位置情報が正常に取得されました。", "User menu": "ユーザーメニュー", + "User ratings (thumbs up/down)": "", "User Webhooks": "ユーザWebhook", "Username": "ユーザー名", "users": "", @@ -1795,15 +1842,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUIは\"{{url}}/chat/completions\"にリクエストを行います", "What are you trying to achieve?": "何を達成したいですか?", "What are you working on?": "何に取り組んでいますか?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "新機能", "What's on your mind?": "", "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.": "出力をページ分けするかどうか。各ページは水平線とページ番号で分割されます。デフォルトでは無効", "Whisper (Local)": "Whisper (ローカル)", + "Who can share to this group": "", "Why?": "どうしてですか?", "Widescreen Mode": "ワイドスクリーンモード", "Width": "幅", + "Wikipedia": "", "Won": "勝ち", "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": "ワークスペース", @@ -1815,6 +1866,8 @@ "Yacy Instance URL": "YacyインスタンスURL", "Yacy Password": "Yacyパスワード", "Yacy Username": "Yacyユーザー名", + "Yahoo": "", + "Yandex": "", "Yesterday": "昨日", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "あなた", @@ -1822,6 +1875,9 @@ "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 save this prompt.": "", "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.": "", @@ -1833,6 +1889,8 @@ "Your Account": "あなたのアカウント", "Your account status is currently pending activation.": "あなたのアカウント状態は現在登録認証待ちです。", "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.": "", "YouTube": "YouTube", "Youtube Language": "YouTubeの言語", "Youtube Proxy URL": "YouTubeのプロキシURL" diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index 0aa54524f7..eeeb80951c 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "ამ პარამეტრების რეგულირება ცვლილებებს უნივერსალურად გამოიყენებს ყველა მომხმარებლისთვის.", "admin": "ადმინისტრატორი", "Admin": "ადმინი", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "პასუხის გაგრძელების დაშვება", "Allow Delete Messages": "შეტყობინებების წაშლის დაშვება", "Allow File Upload": "ფაილის ატვირთვის დაშვება", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "ერთზე მეტი მოდელის დაშვება ჩატში", "Allow non-local voices": "არალოკალური ხმების დაშვება", "Allow Rate Response": "პასუხის შეფასების დაშვება", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "და კიდევ {{COUNT}}", "and create a new shared link.": "და ახალი გაზიარებული ბმულის შექმნა.", "Android": "Android", + "Anyone": "", "API Base URL": "API-ის საბაზისო URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API გასაღები", @@ -175,6 +176,7 @@ "Authenticate": "ავთენტიკაცია", "Authentication": "ავთენტიკაცია", "Auto": "ავტო", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "პასუხის ავტომატური კოპირება ბუფერში", "Auto-playback response": "ავტომატური დაკვრის პასუხი", "Autocomplete Generation": "ავტოდასრულების გენერაცია", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 საბაზისო მისამართი", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 საბაზისო მისამართი აუცილებელია.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "ხელმისაწვდომი სია", "Available Tools": "ხელმისაწვდომი ხელსაწყოები", "available users": "ხელმისაწვდომი მომხმარებლები", @@ -201,6 +204,7 @@ "before": "მითითებულ დრომდე", "Being lazy": "ზარმაცობა", "Beta": "ბეტა", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7-ის ბოლოწერტილი", "Bing Search V7 Subscription Key": "Bing Search V7-ის გამოწერის გასაღები", "Bio": "ბიო", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha-ის ძებნის API-ის გასაღები", "Bold": "სქელი", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave Search API-ის გასაღები", + "Builtin Tools": "", "Bullet List": "დაუნომრავი სია", "Button ID": "ღილაკის ID", "Button Label": "ღილაკის ჭდე", @@ -256,8 +262,10 @@ "Check for updates": "განახლებების შემოწმება", "Checking for updates...": "განახლებების შემოწმება...", "Choose a model before saving...": "აირჩიეთ მოდელი შენახვამდე...", + "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.": "", "Ciphers": "შიფრები", "Citation": "ციტატა", "Citations": "ციტატები", @@ -293,7 +301,6 @@ "Code Block": "კოდის ბლოკი", "Code Editor": "", "Code execution": "კოდის შესრულება", - "Code Execution": "კოდის შესრულება", "Code Execution Engine": "კოდის შესრულების ძრავა", "Code Execution Timeout": "კოდის შესრულების დროის ამოწურვა", "Code formatted successfully": "კოდი წარმატებით დაფორმატდა", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "შემცველობა", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "პასუხის გაგრძელება", "Continue with {{provider}}": "გაგრძელება {{provider}}-ით", "Continue with Email": "გაგრძელება ელფოსტით", @@ -393,6 +401,7 @@ "Database": "მონაცემთა ბაზა", "Datalab Marker API": "Datalab Marker-ის API", "DD/MM/YYYY": "დდ/თთ/წწწწ", + "DDGS Backend": "", "December": "დეკემბერი", "Decrease UI Scale": "", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "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", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "დოკუმენტის ანალიზის ბოლოწერტილი აუცილებელია.", "Document Intelligence Model": "", "Documentation": "დოკუმენტაცია", - "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.": "არ ჩამოტვირთოთ შემთხვევითი pipelines არასანდო წყაროებიდან.", @@ -493,11 +502,14 @@ "Done": "დასრულებული", "Download": "გადმოწერა", "Download & Delete": "ჩამოტვირთვა და წაშლა", + "Download as JSON": "", "Download as SVG": "გადმოწერა SVG-ის სახით", "Download canceled": "გადმოწერა გაუქმდა", "Download Database": "მონაცემთა ბაზის გადმოწერა", + "Downloading stats...": "", "Draw": "ხატვა", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "მაგ: '30წ', '10მ'. მოქმედი დროის ერთეულები: 'წ', 'წთ', 'სთ'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "მაგ: 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "შეიყვანეთ Brave Search API-ის გასაღები", "Enter certificate path": "შეიყვანეთ სერტიფიკატის ბილიკი", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "შეიყვანეთ ფრაგმენტის გადაფარვა", "Enter Chunk Size": "შეიყვანე ფრაგმენტის ზომა", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "შეიყვანეთ Github Raw URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "შეიყვანეთ ID", "Enter Image Size (e.g. 512x512)": "შეიყვანეთ სურათის ზომა (მაგ. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "შეიყვანეთ Jina API-ის გასაღები", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "შეიყვანეთ Jupyter-ის პაროლი", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "შეიყვანეთ გასაღების ქცევა", "Enter language codes": "შეიყვანეთ ენის კოდები", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "შეიყვანეთ მოდელის ID", @@ -736,6 +753,7 @@ "Failed to generate title": "სათაურის გენერაცია ჩავარდა", "Failed to import models": "მოდელების შემოტანა ჩავარდა", "Failed to load chat preview": "ვიდეოს მინიატურის ჩატვირთვა ჩავარდა", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "ფაილის შემცველობის ჩატვირთვა ჩავარდა.", "Failed to move chat": "ჩატის გადატანა ჩავარდა", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "მახასიათებლები", "Features Permissions": "უფლებები ფუნქციებზე", "February": "თებერვალი", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "უკუკავშირის დეტალები", "Feedback History": "უკუკავშირის ისტორია", - "Feedbacks": "უკუკავშირები", "Feel free to add specific details": "სპეციფიკური დეტალების დამატება პრობლემა არაა", "Female": "მდედრობითი", "File": "ფაილი", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "აღმოჩენილია ანაბეჭდის გაყალბება: ინიციალების გამოყენება ავატარად შეუძლებელია. გამოყენებული იქნეა ნაგულისხმევი პროფილის სურათი.", "Firecrawl API Base URL": "Firecrawl API-ის საბაზისო URL", "Firecrawl API Key": "Firecrawl API-ის გასაღები", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "საქაღალდე", "Folder Background Image": "საქაღალდის ფონის სურათი", "Folder deleted successfully": "საქაღალდე წარმატებით წაიშალა", + "Folder Max File Count": "", "Folder Name": "საქაღალდის სახელი", "Folder name cannot be empty.": "საქაღალდის სახელი ცარიელი ვერ იქნება.", "Folder name updated successfully": "საქაღალდის სახელი წარმატებით განახლდა", @@ -826,7 +846,6 @@ "General": "ზოგადი", "Generate": "გენერაცია", "Generate an image": "გამოსახულების გენერაცია", - "Generate Image": "სურათის განერაცია", "Generate Message Pair": "", "Generated Image": "გენერირებული გამოსახულება", "Generating search query": "ძებნის მოთხოვნის გენერაცია", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "გლობალური", "Good Response": "კარგი პასუხი", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API გასაღები", "Google PSE Engine Id": "Google PSE ძრავის Id", "Gravatar": "გრავატარი", "Grid": "", + "Grokipedia": "", "Group": "ჯგუფი", "Group Channel": "", "Group created successfully": "ჯგუფი წარმატებით შეიქმნა", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "გამოსახულებები", "Import": "შემოტანა", "Import Chats": "ჩატების შემოტანა", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "ინტეგრაცია", "Integrations": "ინტეგრაციები", "Interface": "ინტერფეისი", + "Interface Settings Access": "", "Invalid file content": "არასწორი ფაილის შემცველობა", "Invalid file format.": "არასწორი ფაილის ფორმატი.", "Invalid JSON file": "არასწორი JSON ფაილი", @@ -940,6 +961,7 @@ "is typing...": "კრეფს...", "Italic": "კურსივი", "January": "იანვარი", + "Jina API Base URL": "", "Jina API Key": "Jina API-ის გასაღები", "join our Discord for help.": "დახმარებისთვის შემოდით ჩვენს Discord-ზე.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "მართეთ თქვენი ანგარიშის ინფორმაცია.", "March": "მარტი", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (თავსართი)", + "Markdown Header Text Splitter": "", "Max Speakers": "დინამიკების მაქს. რაოდენობა", "Max Upload Count": "მაქს. ატვირთვების რაოდენობა", "Max Upload Size": "მაქს. ატვირთვის ზომა", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ერთდროულად მაქსიმუმ 3 მოდელის ჩამოტვირთვაა შესაძლებელია. მოგვიანებით სცადეთ.", "May": "მაისი", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLM-ებისთვის ხელმისაწვდომი მეხსიერებები აქ გამოჩნდება.", "Memory": "მეხსიერება", "Memory added successfully": "მოგონება წარმატებით დაემატა", @@ -1051,6 +1077,7 @@ "Merge Responses": "პასუხების შერწყმა", "Merged Response": "შერწყმული პასუხი", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "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", @@ -1083,9 +1110,11 @@ "Model Name": "Მოდელის სახელი", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "მოდელი არჩეული არაა", "Model Params": "მოდელის პარამეტრები", "Model Permissions": "მოდელის წვდომები", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "მეტი", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "შესანახი საუბრების გარეშე", "No distance available": "მანძილი ხელმისაწვდომი არაა", "No expiration can pose security risks.": "", - "No feedbacks found": "უკუკავშირები აღმოჩენილი არაა", + "No feedback found": "", "No file selected": "ფაილი არჩეული არაა", "No files in this knowledge base.": "", "No functions found": "ფუნქციები აღმოჩენილი არაა", @@ -1144,6 +1174,7 @@ "No models selected": "მოდელები არჩეული არაა", "No Notes": "შენიშვნების გარეშე", "No notes found": "სანიშნების გარეშე", + "No one": "", "No pinned messages": "", "No prompts found": "შეყვანები აღმოჩენილი არაა", "No results": "შედეგების გარეშე", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "უი! როგორც ჩანს, მისამართი არასწორია. გთხოვთ, გადაამოწმოთ და ისევ სცადოთ.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "პანელი", "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.": "", "Password": "პაროლი", "Passwords do not match.": "პაროლები არ ემთხვევა.", "Paste Large Text as File": "დიდი ტექსტის ჩასმა ფაილის სახით", @@ -1260,7 +1295,6 @@ "Pipe": "ფაიფი", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "მილსადენები", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines არის პლაგინების სისტემა თვითნებური კოდის გაშვებით —", "Pipelines Not Detected": "", "Pipelines Valves": "მილსადენის სარქველები", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "მორგება", + "Settings Permissions": "", "Settings saved successfully!": "პარამეტრები შენახვა წარმატებულია!", "Share": "გაზიარება", "Share Chat": "ჩატის გაზიარება", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "საუბრის ამოცნობის შეცდომა: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "საუბრიდან-ტექსტამდე-ის ძრავი", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "არხის დასაწყისი", "Start Tag": "დაწყების ჭდე", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "გაჩერება", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "შეჩერების მიმდევრობა", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "მხარდაჭერა", "Support this plugin:": "დაუჭირეთ მხარი ამ დამატებას:", "Supported MIME Types": "მხარდაჭერილი MIME ტიპები", + "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.": "", "System": "სისტემა", "System Instructions": "სისტემური ინსტრუქციები", "System Prompt": "სისტემური მოთხოვნა", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "თემა", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "ფაიფლაინის ატვირთვა", "Upload Progress": "ატვირთვის მიმდინარეობა", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "URL საჭიროა", @@ -1747,6 +1793,7 @@ "User Groups": "მომხმარებლის ჯგუფები", "User location successfully retrieved.": "", "User menu": "მომხმარებლის მენიუ", + "User ratings (thumbs up/down)": "", "User Webhooks": "ვებჰუკების გამოყენება", "Username": "მომხმარებლის სახელი", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "რას ცდილობთ, მიაღწიოთ?", "What are you working on?": "რაზე მუშაობთ?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "რა არის ახალი", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (ლოკალური)", + "Who can share to this group": "", "Why?": "რატომ?", "Widescreen Mode": "ფართოეკრანიანი რეჟიმი", "Width": "სიგანე", + "Wikipedia": "", "Won": "ვონი", "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.": "", "Workspace": "სამუშაო სივრცე", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy-ის გაშვებული ასლის URL", "Yacy Password": "Yacy-ის პაროლი", "Yacy Username": "Yacy-ის მომხმარებლის სახელი", + "Yahoo": "", + "Yandex": "", "Yesterday": "გუშინ", "Yesterday at {{LOCALIZED_TIME}}": "გუშინ, {{LOCALIZED_TIME}}", "You": "თქვენ", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "თქვენი ანგარიში", "Your account status is currently pending activation.": "თქვენი ანგარიშის სტატუსი ამჟამად ელოდება აქტივაციას.", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube-ის ენა", "Youtube Proxy URL": "Youtube-ის პროქსის URL" diff --git a/src/lib/i18n/locales/kab-DZ/translation.json b/src/lib/i18n/locales/kab-DZ/translation.json index 3810556c02..8d0e3aa130 100644 --- a/src/lib/i18n/locales/kab-DZ/translation.json +++ b/src/lib/i18n/locales/kab-DZ/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Aswati n yiɣewwaren-a ad yessuter ibeddilen s wudem ameɣradan i yiseqdacen akk.", "admin": "anedbal", "Admin": "Anebdal", + "Admin Contact Email": "", "Admin Panel": "Agalis n tedbelt", "Admin Settings": "Iɣewwaṛen n unedbal", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Inedbalen sɛan anekcum ɣer meṛṛa ifecka melmi i bɣan; iseqdacen ilaq ad asen-ttwamudden yifecka i yal tamudemt deg tallunt n umahil.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Sireg akemmel n tririt", "Allow Delete Messages": "Sireg tukksa n yiznan", "Allow File Upload": "Sireg asali n yifuyla", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Sireg ugar n timudmiwin deg usqerdec", "Allow non-local voices": "Sireg tuɣac tirdiganin", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "d {{COUNT}} nniḍen", "and create a new shared link.": "rnu aseɣwen n beṭṭu amaynut.", "Android": "Android", + "Anyone": "", "API Base URL": "Tansa URL n taffa i API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Tasarutt API", @@ -175,6 +176,7 @@ "Authenticate": "Sesteb", "Authentication": "Asesteb", "Auto": "Awurman", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Anɣal n tiririt tawurmant ɣer tecfawt", "Auto-playback response": "Taɣuṛi tawurmant n tririt", "Autocomplete Generation": "Asirew n yisumar", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Azrir AUTOMATIC1111 n usesteb n API", "AUTOMATIC1111 Base URL": "URL n taffa i AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "L'URL n uzadur {AUTOMATIC1111} yettwasra.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Tabdart i yellan", "Available Tools": "Ifecka i yellan", "available users": "Iseqdacen yellan", @@ -201,6 +204,7 @@ "before": "send", "Being lazy": "Ili-k d ameɛdaz", "Beta": "Biṭa", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "Tasarut n umulteɣ Bing Search V7", "Bio": "Tameddurt", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Tasarut API n Bocha Search", "Bold": "Azuran", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Aserkem neɣ angal n yiqenṭaren ulmisen i tririt yettwaḥeṛsen. Azalen ibirusanen ad ttwakecfen gar 100 d 100 (asekcam). Lmut: ala", + "Brave": "", "Brave Search API Key": "Tasarut API n Brave Search", + "Builtin Tools": "", "Bullet List": "Tabdart s tlilac", "Button ID": "Asulay ID n tqeffalt", "Button Label": "Tabzimt n tqeffalt", @@ -256,8 +262,10 @@ "Check for updates": "Nadi ileqman", "Checking for updates...": "Anadi n yileqman...", "Choose a model before saving...": "Fren tamudemt uqbel ad tsellkeḍ...", + "Chunk Min Size Target": "", "Chunk Overlap": "", "Chunk Size": "Tiddi n iceqqfan", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Izwilen", "Citation": "Tanebdurt", "Citations": "Tinebdurin", @@ -293,7 +301,6 @@ "Code Block": "Iḥder n tengalt", "Code Editor": "", "Code execution": "Aselkem n tengalt", - "Code Execution": "Aselkem n tengalt", "Code Execution Engine": "Amsadday n uselkem n tengalt", "Code Execution Timeout": "Tanzagt n uselkem n tengalt, tɛedda", "Code formatted successfully": "Tangalt tettwamsel akken iwata", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Admin n unermis i WebUI", "Content": "Agbur", "Content Extraction Engine": "Amsedday n uselkem n ugbur", + "Content lengths (character counts only)": "", "Continue Response": "Kemmel tiririt", "Continue with {{provider}}": "Kemmel s {{provider}}", "Continue with Email": "Kemmel s yimayl", @@ -393,6 +401,7 @@ "Database": "Taffa n isefka", "Datalab Marker API": "API n Datalab Marker", "DD/MM/YYYY": "JJ/MM/AAAA", + "DDGS Backend": "", "December": "Duǧambeṛ", "Decrease UI Scale": "", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Kcem daxel n tmussniwin", "Do not install functions from sources you do not fully trust.": "Ur sebdad ara tisɣunin seg iɣbula ur tettamneḍ ara akken iwata.", "Do not install tools from sources you do not fully trust.": "Ur srusuy ara ifecka seg iɣbula ur tettamneḍ ara akken iwata.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "Tansa URL n uqeddac tuḥwaǧ.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Tasemlit", - "Documents": "Isemliyen", "does not make any external connections, and your data stays securely on your locally hosted server.": "ur teqqen ara ɣer tuqqniwin tizɣarayin, akka isefka-k⋅m ad qqimen d iɣellsanen ɣef uqeddac-ik⋅im adigan.", "Domain Filter List": "Tabdart n taɣulin ara yettwasizedgen", "don't fetch random pipelines from sources you don't trust.": "ur d-awi ara pipelines igacuranen seg yiɣbula ur tettamneḍ ara.", @@ -493,11 +502,14 @@ "Done": "Immed", "Download": "Azdam", "Download & Delete": "Zdem & Kkes", + "Download as JSON": "", "Download as SVG": "Zdem am SVG", "Download canceled": "Ittwasefsex usider", "Download Database": "Zdem-d tafa n isefka", + "Downloading stats...": "", "Draw": "Suneɣ", "Drop any files here to upload": "Ssers-d ifuyla da akken ad ten-tessaliḍ", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "e.g. '30s','10m'. Tiyunin n wakud ameɣtu d 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "amedya: \"json\" neɣ azenziɣ JSON", "e.g. 60": "amedya. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Sekcem tasarut API n Bocha Search", "Enter Brave Search API Key": "Sekcem-d tasarut n API Brave Search", "Enter certificate path": "Sekcem abrid n uselkin", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Sekcem ambiwel n yifendasen", "Enter Chunk Size": "Sekcem tiddi n iceqqfan", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Kcem ɣer tyugiwin \"token:bias_value\" i d-yezgan gar-asent (amedya: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Sekcem-d tansa URL yeffɣen n unadi ɣef Web", "Enter Firecrawl API Base URL": "Sekcem tansa URL n taffa n isefka API", "Enter Firecrawl API Key": "Sekcem API n Firecrawl Tasarut", + "Enter Firecrawl Timeout": "", "Enter folder name": "Sekcem isem n ukaram", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Sekcem tansa URL tazegzawt n Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "Sekcem-d asulay ID", "Enter Image Size (e.g. 512x512)": "Sekcem tugna Size (amedya 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Sekcem tasarut API n Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Sekcem-d tawila JSON (amedya, {\"disable_links\": true})", "Enter Jupyter Password": "Sekcem-d awal n uɛeddi n Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Sekcem-d tasarut API n Kagi Search", "Enter Key Behavior": "Kcem ɣer tsarut Behavior", "Enter language codes": "Sekcem-d tangalin n tutlayin", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Enter Mistral API Tasarut", "Enter Model ID": "Senkcem-d asulay n tmudemt", @@ -736,6 +753,7 @@ "Failed to generate title": "Ur yessaweḍ ara ad d-yawi azwel", "Failed to import models": "", "Failed to load chat preview": "Yecceḍ usali n teskant n udiwenni", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Ur yessaweḍ ara ad d-yessali agbur n yifuyla.", "Failed to move chat": "Tuccḍa deg unkaz n udiwenni", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Timahilin", "Features Permissions": "Tisirag n tmehilin", "February": "Fuṛaṛ", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Talqayt n tamawin", "Feedback History": "Azray n tamawin", - "Feedbacks": "Timuɣliwin", "Feel free to add specific details": "Ur ttkukru ara ad ternuḍ ttfaṣil ulmisen", "Female": "Tawtemt", "File": "Afaylu", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Tban-d tɣenǧawt n uskenjbir Ur yezmir yiwen ad yesseqdec inizjali d avatar. Ma nmuqel tugna n umaɣnu amezwer.", "Firecrawl API Base URL": "Tansa URL n taffa n isefka", "Firecrawl API Key": "Tasarut API n Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Tigawin tiruradin yettifliwen", "Focus Chat Input": "", "Folder": "Akaram", "Folder Background Image": "Tugna n ugilal n ukaram", "Folder deleted successfully": "Akaram-nni yettwakkes akken iwata", + "Folder Max File Count": "", "Folder Name": "Isem n ukaram", "Folder name cannot be empty.": "Isem n ukaram ur yezmir ara ad yili d ilem.", "Folder name updated successfully": "Isem n ukaram yettwaleqqem akken iwata", @@ -826,7 +846,6 @@ "General": "Amatu", "Generate": "Sirew", "Generate an image": "Sarew tugna", - "Generate Image": "Sirew-d tugna", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Asirew n tuttra n unadi", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Bdu s {{WEBUI_NAME}}", "Global": "Amatu", "Good Response": "Tiririt yelhan", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Tasarut API n Google PSE", "Google PSE Engine Id": "Asulay n umsadday n unadi PSE n Google", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Agraw", "Group Channel": "", "Group created successfully": "Agraw yennulfa-d akken iwata", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Asirew n yineftaɣen n tugniwin", "Image Prompt Generation Prompt": "Aneftaɣ n usirew n yineftaɣen n tugniwin", "Image Size": "", - "Images": "Tugniwin", "Import": "Kter", "Import Chats": "Asifeḍ n yidiwenniyen", "Import Config from JSON File": "Kter-d Config seg ufaylu JSON", @@ -927,6 +947,7 @@ "Integration": "Tamsideft", "Integrations": "Timsidaf", "Interface": "Agrudem", + "Interface Settings Access": "", "Invalid file content": "Agbur n ufaylu d arameɣtu", "Invalid file format.": "Amasal n ufaylu d arameɣtu.", "Invalid JSON file": "Afaylu JSON arameɣtu", @@ -940,6 +961,7 @@ "is typing...": "yettaru…", "Italic": "Uknan", "January": "Yennayer", + "Jina API Base URL": "", "Jina API Key": "Tasarut API n Jina", "join our Discord for help.": "nadi-d ɣef tallalt-nneɣ.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "Eǧǧ-it d ilem akken ad ternuḍ akk timudmiwin neɣ ad tferneḍ timudmiwin tulmisin", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Eǧǧ-it d ilem akken ad tesqedceḍ aneftaɣ-nni amezwaru, naɣ sekcem-d yiwen n uneftaɣ udmawan", "Leave model field empty to use the default model.": "Eǧǧ urti n tmudemt d ilem i useqdec n tmudemt-nni tamezwarut.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Sefrek ilɣa-inek·inem n umiḍan.", "March": "Meɣres", "Markdown": "Markdown", - "Markdown (Header)": "Ticreḍt (Aqerru)", + "Markdown Header Text Splitter": "", "Max Speakers": "Amḍan afellay n wid d-yemmseslayen", "Max Upload Count": "Amḍan afellay n uzdam", "Max Upload Size": "Teɣzi tafellayt n uzdam", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximum n 3 n tmudmin yezmer ad d-yettwasider seg-a ɣer da. Ttxil-k, ɛreḍ tikkelt niḍen ticki.", "May": "Mayyu", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Da ara d-banent teḥkayin ara yaweḍ yiwen ɣer LLMs.", "Memory": "Takatut", "Memory added successfully": "Asmekti yettwarna akken iwata", @@ -1051,6 +1077,7 @@ "Merge Responses": "Smezdi tiririyin", "Merged Response": "Tiririyin mmezdint", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "A win yufan, tazmilt n yizen ad tettwasireg i useqdec n tmahilt-a", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Izen ara d-tazneḍ mi ara d-tesnulfuḍ aseɣwen-ik ur yettwabḍu ara. Iseqdacen yesɛan tansa URL ad izmiren ad walin adiwenni-nni yettwabḍan.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Isem n tmudemt", "Model name already exists, please choose a different one": "Yella yakan yisem n tmudemt, ma ulac aɣilif fren wayeḍ yemwalafen", "Model Name is required.": "Isem n timudemt yettwasra.", + "Model names and usage frequency": "", "Model not selected": "Ur tettwafran ara tmudemt", "Model Params": "Iɣewwaren n timudemt", "Model Permissions": "Tisirag n timudemt", + "Model responses or outputs": "", "Model unloaded successfully": "Tamudemt ur d-uli ara akken iwata", "Model updated successfully": "Tamudemt tettwaleqqem akken iwata", "Model(s) do not support file upload": "Mudd(s) ur ssefrak ara afaylu usali n ufaylu", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Beṭṭu azayaz n tmudmiwin", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Tasarut API n Mojeek", "More": "Ugar", "More Concise": "Awezlan ugar", @@ -1129,7 +1159,7 @@ "No conversation to save": "Ulac adiwenni i usekles", "No distance available": "Ulac ameccaq yettwafen", "No expiration can pose security risks.": "", - "No feedbacks found": "Ulac awennit i yettwafen", + "No feedback found": "", "No file selected": "Ulac afaylu i yettwafernen", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Ulac timudmin yettwafernen", "No Notes": "Ulac tizmilin", "No notes found": "Ulac tizmilin yettwafen", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Ulac igmaḍ yettwafen", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Ala ifuyla n tuccar i yettusirgen", "Only select users and groups with permission can access": "Ala iseqdacen akked yegrawen yesɛan tisirag i izemren ad kecmen", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ayhuh! Yettban-d dakken URL-nni ur tṣeḥḥa ara. Ttxil-k, ssefqed snat n tikkal yernu ɛreḍ tikkelt niḍen.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "Ayhuh! Teḍra-d tuccḍa deg tririt-nni yezrin.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI yezmer ad yesseqdec ifecka i d-yettak yal aqeddac OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI yesseqdac faster-whisper sdaxel-is.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Ldi WebUI yesseqdac SpeechT5 akked CMU Arktik.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "asebter", "Paginate": "Smiḍen", "Parameters": "Isefranen", + "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.": "", "Password": "Awal n uɛeddi", "Passwords do not match.": "Awalen n uɛeddi ur mṣadan ara.", "Paste Large Text as File": "Senteḍ aḍris meqqren am ufaylu", @@ -1260,7 +1295,6 @@ "Pipe": "Aselda", "Pipeline deleted successfully": "Aselda yettwakkes akken iwata", "Pipeline downloaded successfully": "Aselda yettuzdem-d akken iwata", - "Pipelines": "Iseldayen", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines d unagraw n izegrar s uselkem n tengalt awurman —", "Pipelines Not Detected": "Ulac aselda i yettwafen", "Pipelines Valves": "", @@ -1498,6 +1532,7 @@ "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.": "Sbadu tiseddarin n uḥbas i useqdec. Mi ara d-temlil temɛawdit-a, LLM ad teḥbes asegrew n uḍris d tuɣalin. Timɛayin n uḥbas yeggten zemrent ad ttwasbeddent s usbadu n waṭas n yizamulen n uḥbas yemgaraden deg tmudemt.", "Setting": "", "Settings": "Iɣewwaren", + "Settings Permissions": "", "Settings saved successfully!": "Iɣewwaṛen ttwakelsen akken iwata!", "Share": "Bḍu", "Share Chat": "Bḍu asqerdec", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Tuccḍa n uɛqal n wawal: {{error}}", "Speech-to-Text": "Aɛqal n taɣect", "Speech-to-Text Engine": "Amsadday n uɛqal n taɣect", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Tazwara n ubadu", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Seḥbes", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Tagzemt n uḥbas", "Stream Chat Response": "Suddem tiririt n udiwenni", @@ -1571,7 +1608,14 @@ "Support": "Tallalt", "Support this plugin:": "Ɛiwen asiɣzef-a:", "Supported MIME Types": "Anawen MIME ttwasefraken", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Mtawi akaram", + "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": "Anagraw", "System Instructions": "Tanaḍin n unagraw", "System Prompt": "Aneftaɣ n unagraw", @@ -1616,6 +1660,7 @@ "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.": "Tehri s ipiksilen i tussda n tugniwin. Eǧǧ-it d ilem i war tussda.", "Theme": "Asentel", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Yettxemmim…", "This action cannot be undone. Do you wish to continue?": "Tigawt-a ur tettwakkes ara. Tebɣiḍ ad tkemmleḍ?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Abadu-a yettwasnulaf-d deg {{created} Ɣef}}. D ta i d tazwara maḍi n ubadu {{channelName}}.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Aselda n uɛebbi", "Upload Progress": "", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Tikli n uɛebbi: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "Tlaq tansa URL", @@ -1747,6 +1793,7 @@ "User Groups": "Agraw n iseqdacen", "User location successfully retrieved.": "", "User menu": "Umuɣ n useqdac", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooks n yiseqdacen", "Username": "Isem n useqdac", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI ad ssutreɣ i \"{url}}/chat/completions\"", "What are you trying to achieve?": "Sanda ay tettarmed ad tessiwḍed?", "What are you working on?": "Ɣef wacu ay la tettmahaled?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "D acu d amaynut deg", "What's on your mind?": "", "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": "anda yebɣu tiliḍ", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Ma tebɣiḍ ad d-tessugneḍ tuffɣa. Yal asebter ad yebḍu s ulugen igli d wuṭṭun n usebter. Imezwura ɣer False.", "Whisper (Local)": "Whisper (adigan)", + "Who can share to this group": "", "Why?": "Ayɣer?", "Widescreen Mode": "Askar n ugdil aččuran", "Width": "Tehri", + "Wikipedia": "", "Won": "Yerbaḥ", "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.": "", "Workspace": "Tamnaḍṭ n umahil", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "URL n tummant Yacy", "Yacy Password": "Awal n uɛeddi n Yacy", "Yacy Username": "Isem n useqdac Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Iḍelli", "Yesterday at {{LOCALIZED_TIME}}": "Iḍelli, ɣef {{LOCALIZED_TIME}}", "You": "Kečč·mm", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Tzemreḍ kan ad tqeṣṣreḍ s afellay n ufaylu(s) n {{maxCount}} ɣef tikelt.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "You cannot upload an empty file.": "Ur tezmireḍ ad tessaliḍ afaylu ilem.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Amiḍan-ik·im", "Your account status is currently pending activation.": "Addad-nnem n umiḍan atan yettṛaju armad.", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "Tutlayt n Youtube", "Youtube Proxy URL": "Tansa URL n upṛuksi Youtube" diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 9fd174864c..c5e8f45130 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "이 설정을 조정하면 모든 사용자에게 변경 사항이 일괄 적용됩니다.", "admin": "관리자", "Admin": "관리자", + "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.": "관리자는 항상 모든 도구에 접근할 수 있지만, 사용자는 워크스페이스에서 모델마다 도구를 할당받아야 합니다.", @@ -101,7 +102,6 @@ "Allow Continue Response": "계속 응답 허용", "Allow Delete Messages": "메시지 삭제 허용", "Allow File Upload": "파일 업로드 허용", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "채팅에서 여러 모델 허용", "Allow non-local voices": "외부 음성 허용", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "그리고 {{COUNT}}개 더", "and create a new shared link.": "새로운 공유 링크를 생성합니다.", "Android": "안드로이드", + "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 키", @@ -175,6 +176,7 @@ "Authenticate": "인증하다", "Authentication": "인증", "Auto": "자동", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "응답을 클립보드에 자동 복사", "Auto-playback response": "응답 자동 재생", "Autocomplete Generation": "자동완성 생성", @@ -183,6 +185,7 @@ "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.)": "", "Available list": "가능한 목록", "Available Tools": "사용 가능한 도구", "available users": "사용 가능 사용자", @@ -201,6 +204,7 @@ "before": "이전", "Being lazy": "게으름 피우기", "Beta": "베타", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 엔드포인트", "Bing Search V7 Subscription Key": "Bing Search V7 구독 키", "Bio": "소개", @@ -209,7 +213,9 @@ "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 Search API Key": "Brave Search API 키", + "Builtin Tools": "", "Bullet List": "글머리 기호 목록", "Button ID": "버튼 ID", "Button Label": "버튼 레이블", @@ -256,8 +262,10 @@ "Check for updates": "업데이트 확인", "Checking for updates...": "업데이트 확인중...", "Choose a model before saving...": "저장하기 전에 모델을 선택하세요...", + "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.": "", "Ciphers": "암호", "Citation": "인용", "Citations": "인용", @@ -293,7 +301,6 @@ "Code Block": "코드 블록", "Code Editor": "코드 편집기", "Code execution": "코드 실행", - "Code Execution": "코드 실행", "Code Execution Engine": "코드 실행 엔진", "Code Execution Timeout": "코드 실행 시간 초과", "Code formatted successfully": "코드 포맷팅이 성공적으로 완료되었습니다.", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "WebUI 접속을 위해서는 관리자에게 연락에 연락하십시오", "Content": "내용", "Content Extraction Engine": "콘텐츠 추출 엔진", + "Content lengths (character counts only)": "", "Continue Response": "응답 이어 받기", "Continue with {{provider}}": "{{provider}}로 계속", "Continue with Email": "이메일로 계속", @@ -393,6 +401,7 @@ "Database": "데이터베이스", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "YYYY/MM/DD", + "DDGS Backend": "", "December": "12월", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "Docling 서버 URL이 필요합니다.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "문서", - "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.": "신뢰하지 않는 출처에서 임의의 파이프라인을 가져오지 마세요.", @@ -493,11 +502,14 @@ "Done": "완료됨", "Download": "다운로드", "Download & Delete": "다운로드 및 삭제", + "Download as JSON": "", "Download as SVG": "SVG로 다운로드", "Download canceled": "다운로드 취소", "Download Database": "데이터베이스 다운로드", + "Downloading stats...": "", "Draw": "그리기", "Drop any files here to upload": "여기에 파일을 끌어다 놓아 업로드하세요", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "예: '30초','10분'. 올바른 시간 단위는 '초', '분', '시'입니다.", "e.g. \"json\" or a JSON schema": "예: \\\"json\\\" 또는 JSON 스키마", "e.g. 60": "예: 60", @@ -572,6 +584,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 Overlap": "청크 중첩 입력", "Enter Chunk Size": "청크 크기 입력", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "쉼표로 구분된 \\\"토큰:편향_값\\\" 쌍 입력 (예: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "외부 웹 검색 URL 입력", "Enter Firecrawl API Base URL": "Firecrawl API 기본 URL 입력", "Enter Firecrawl API Key": "Firecrawl API 키 입력", + "Enter Firecrawl Timeout": "", "Enter folder name": "폴더 이름 입력", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Github Raw URL 입력", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "색상 hex 입력 (예: #FF0000)", "Enter ID": "ID 입력", "Enter Image Size (e.g. 512x512)": "이미지 크기 입력(예: 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina API 키 입력", "Enter JSON config (e.g., {\"disable_links\": true})": "JSON 설정 입력 (예: {\"disable_links\": true})", "Enter Jupyter Password": "Jupyter 비밀번호 입력", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search API 키 입력", "Enter Key Behavior": "키 동작 입력", "Enter language codes": "언어 코드 입력", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Mistral API Base URL 입력", "Enter Mistral API Key": "Mistral API 키 입력", "Enter Model ID": "모델 ID 입력", @@ -736,6 +753,7 @@ "Failed to generate title": "제목 생성 실패", "Failed to import models": "모델 가져오기 실패", "Failed to load chat preview": "채팅 미리보기 로드 실패", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "파일 내용 로드 실패.", "Failed to move chat": "채팅 이동 실패", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "기능", "Features Permissions": "기능 권한", "February": "2월", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "피드백 상세내용", "Feedback History": "피드백 기록", - "Feedbacks": "피드백", "Feel free to add specific details": "자세한 내용을 자유롭게 추가하세요.", "Female": "여성", "File": "파일", @@ -776,11 +794,13 @@ "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": "", "Focus Chat Input": "채팅 입력창에 포커스", "Folder": "폴더", "Folder Background Image": "폴더 배경 이미지", "Folder deleted successfully": "성공적으로 폴더가 삭제되었습니다", + "Folder Max File Count": "", "Folder Name": "폴더 이름", "Folder name cannot be empty.": "폴더 이름을 작성해주세요", "Folder name updated successfully": "성공적으로 폴더 이름이 저장되었습니다", @@ -826,7 +846,6 @@ "General": "일반", "Generate": "생성", "Generate an image": "이미지 생성", - "Generate Image": "이미지 생성", "Generate Message Pair": "", "Generated Image": "생성된 이미지", "Generating search query": "검색 쿼리 생성", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}} 시작하기", "Global": "글로벌", "Good Response": "좋은 응답", + "Google": "", "Google Drive": "구글 드라이브", "Google PSE API Key": "Google PSE API 키", "Google PSE Engine Id": "Google PSE 엔진 ID", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "그룹", "Group Channel": "", "Group created successfully": "성공적으로 그룹을 생성했습니다", @@ -895,7 +916,6 @@ "Image Prompt Generation": "이미지 프롬프트 생성", "Image Prompt Generation Prompt": "이미지 프롬프트를 생성하기 위한 프롬프트", "Image Size": "이미지 크기", - "Images": "이미지", "Import": "가져오기", "Import Chats": "채팅 가져오기", "Import Config from JSON File": "JSON 파일에서 설정 가져오기", @@ -927,6 +947,7 @@ "Integration": "통합", "Integrations": "통합", "Interface": "인터페이스", + "Interface Settings Access": "", "Invalid file content": "잘못된 파일 내용", "Invalid file format.": "잘못된 파일 형식", "Invalid JSON file": "잘못된 JSON 파일", @@ -940,6 +961,7 @@ "is typing...": "입력 중...", "Italic": "기울임", "January": "1월", + "Jina API Base URL": "", "Jina API Key": "Jina API 키", "join our Discord for help.": "도움말을 보려면 Discord에 가입하세요.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "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 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.": "기본 모델을 사용하려면 모델 필드를 비워 두세요.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "계정 정보를 관리하세요.", "March": "3월", "Markdown": "마크다운", - "Markdown (Header)": "마크다운 (헤더)", + "Markdown Header Text Splitter": "", "Max Speakers": "최대 화자 수", "Max Upload Count": "업로드 최대 수", "Max Upload Size": "업로드 최대 사이즈", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "최대 3개의 모델을 동시에 다운로드할 수 있습니다. 나중에 다시 시도하세요.", "May": "5월", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "멤버 삭제에 성공했습니다", "Members": "멤버", "Members added successfully": "멤버 추가에 성공했습니다", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLM에서 접근할 수 있는 메모리는 여기에 표시됩니다.", "Memory": "메모리", "Memory added successfully": "성공적으로 메모리가 추가되었습니다", @@ -1051,6 +1077,7 @@ "Merge Responses": "응답들 결합하기", "Merged Response": "결합된 응답", "Message": "메시지", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "이 기능을 사용하려면 메시지 평가가 활성화되어야합니다", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "모델 이름", "Model name already exists, please choose a different one": "이 모델 이름은 이미 존재합니다. 다른 이름을 선택해주세요.", "Model Name is required.": "모델 이름이 필요합니다", + "Model names and usage frequency": "", "Model not selected": "모델이 선택되지 않았습니다.", "Model Params": "모델 매개변수", "Model Permissions": "모델 권한", + "Model responses or outputs": "", "Model unloaded successfully": "성공적으로 모델이 언로드되었습니다", "Model updated successfully": "성공적으로 모델이 업데이트되었습니다", "Model(s) do not support file upload": "모델이 파일 업로드를 지원하지 않습니다", @@ -1096,6 +1125,7 @@ "Models imported successfully": "모델을 성공적으로 가져왔습니다.", "Models Public Sharing": "모델 공개 공유", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API 키", "More": "더보기", "More Concise": "더 간결하게", @@ -1129,7 +1159,7 @@ "No conversation to save": "저장할 대화가 없습니다", "No distance available": "거리 불가능", "No expiration can pose security risks.": "만료 기한이 없으면 보안 위험이 발생할 수 있습니다.", - "No feedbacks found": "피드백을 찾을 수 없습니다", + "No feedback found": "", "No file selected": "파일이 선택되지 않았습니다", "No files in this knowledge base.": "", "No functions found": "함수를 찾을 수 없습니다", @@ -1144,6 +1174,7 @@ "No models selected": "모델이 선택되지 않았습니다", "No Notes": "노트가 없습니다", "No notes found": "노트를 찾을 수 없습니다", + "No one": "", "No pinned messages": "고정된 메시지가 없습니다", "No prompts found": "프롬프트를 찾을 수 없습니다", "No results": "결과가 없습니다", @@ -1195,6 +1226,7 @@ "Only invited users can access": "초대된 사용자만 접근할 수 있습니다.", "Only markdown files are allowed": "마크다운 파일만 허용됩니다", "Only select users and groups with permission can access": "권한이 있는 사용자와 그룹만 접근 가능합니다.", + "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.": "이런! 이전 응답에 에러가 있었던 것 같습니다.", @@ -1211,6 +1243,7 @@ "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 (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", @@ -1235,6 +1268,8 @@ "page": "페이지", "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.": "", "Password": "비밀번호", "Passwords do not match.": "비밀번호가 일치하지 않습니다.", "Paste Large Text as File": "큰 텍스트를 파일로 붙여넣기", @@ -1260,7 +1295,6 @@ "Pipe": "파이프", "Pipeline deleted successfully": "성공적으로 파이프라인이 삭제되었습니다.", "Pipeline downloaded successfully": "성공적으로 파이프라인이 설치되었습니다.", - "Pipelines": "파이프라인", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines는 임의 코드 실행이 가능한 플러그인 시스템입니다 —", "Pipelines Not Detected": "파이프라인이 발견되지 않았습니다.", "Pipelines Valves": "파이프라인 밸브", @@ -1497,6 +1531,7 @@ "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 saved successfully!": "설정이 성공적으로 저장되었습니다!", "Share": "공유", "Share Chat": "채팅 공유", @@ -1540,6 +1575,7 @@ "Speech recognition error: {{error}}": "음성 인식 오류: {{error}}", "Speech-to-Text": "음성-텍스트 변환", "Speech-to-Text Engine": "음성-텍스트 변환 엔진", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "새 대화 시작", "Start of the channel": "채널 시작", "Start Tag": "시작 태그", @@ -1550,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "정지", + "Stop Download": "", "Stop Generating": "생성 중지", "Stop Sequence": "중지 시퀀스", "Stream Chat Response": "스트림 채팅 응답", @@ -1570,7 +1607,14 @@ "Support": "지원", "Support this plugin:": "플러그인 지원", "Supported MIME Types": "지원하는 MIME 타입", + "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.": "", "System": "시스템", "System Instructions": "시스템 지침", "System Prompt": "시스템 프롬프트", @@ -1615,6 +1659,7 @@ "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.": "", "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}} 채널이 처음 만들어졌습니다. 대화를 시작해보세요.", @@ -1729,6 +1774,7 @@ "Upload Pipeline": "업로드 파이프라인", "Upload Progress": "업로드 진행 상황", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "파일 업로드중...", "URL": "URL", "URL is required": "URL이 필요합니다.", @@ -1746,6 +1792,7 @@ "User Groups": "사용자 그룹", "User location successfully retrieved.": "성공적으로 사용자의 위치를 불러왔습니다", "User menu": "사용자 메뉴", + "User ratings (thumbs up/down)": "", "User Webhooks": "사용자 웹훅", "Username": "사용자 이름", "users": "사용자", @@ -1795,15 +1842,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI가 \"{{url}}/chat/completions\"로 요청을 보냅니다", "What are you trying to achieve?": "무엇을 성취하고 싶으신가요?", "What are you working on?": "어떤 작업을 하고 계신가요?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "새로운 기능:", "What's on your mind?": "무슨 생각을 하고 계신가요?", "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": "", "Why?": "이유는?", "Widescreen Mode": "와이드스크린 모드", "Width": "", + "Wikipedia": "", "Won": "승리", "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": "워크스페이스", @@ -1815,6 +1866,8 @@ "Yacy Instance URL": "Yacy 인스턴스 URL", "Yacy Password": "Yacy 비밀번호", "Yacy Username": "Yacy 사용자 이름", + "Yahoo": "", + "Yandex": "", "Yesterday": "어제", "Yesterday at {{LOCALIZED_TIME}}": "어제 {{LOCALIZED_TIME}}", "You": "당신", @@ -1822,6 +1875,9 @@ "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 save this prompt.": "", "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.": "", @@ -1833,6 +1889,8 @@ "Your Account": "계정", "Your account status is currently pending activation.": "현재 계정은 아직 활성화되지 않았습니다.", "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.": "", "YouTube": "유튜브", "Youtube Language": "Youtube 언어", "Youtube Proxy URL": "Youtube 프록시 URL" diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json index 224af8a35f..3cdf2316b9 100644 --- a/src/lib/i18n/locales/lt-LT/translation.json +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Šių nustatymų pakeitimas bus pritakytas visiems naudotojams.", "admin": "Administratorius", "Admin": "Administratorius", + "Admin Contact Email": "", "Admin Panel": "Administratorių panelė", "Admin Settings": "Administratorių nustatymai", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratoriai visada turi visus įrankius. Naudotojai turi tuėti prieigą prie dokumentų per modelių nuostatas", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Leisti nelokalius balsus", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "sukurti naują dalinimosi nuorodą", "Android": "", + "Anyone": "", "API Base URL": "API basės nuoroda", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API raktas", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatiškai nukopijuoti atsakymą", "Auto-playback response": "Automatinis atsakymo skaitymas", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 bazės nuoroda", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 bazės nuoroda reikalinga.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "galimi naudotojai", @@ -201,6 +204,7 @@ "before": "prieš", "Being lazy": "Būvimas tingiu", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave Search API raktas", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Patikrinti atnaujinimus", "Checking for updates...": "Ieškoma atnaujinimų...", "Choose a model before saving...": "Pasirinkite modelį prieš išsaugant...", + "Chunk Min Size Target": "", "Chunk Overlap": "Blokų persidengimas", "Chunk Size": "Blokų dydis", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Citata", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "Kodas suformatuotas sėkmingai", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Susisiekite su administratoriumi dėl prieigos", "Content": "Turinys", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Tęsti atsakymą", "Continue with {{provider}}": "Tęsti su {{tiekėju}}", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Duomenų bazė", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Gruodis", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "", "Do not install functions from sources you do not fully trust.": "Neinstaliuokite funkcijų iš nepatikimų šaltinių", "Do not install tools from sources you do not fully trust.": "Neinstaliuokite įrankių iš nepatikimų šaltinių", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentacija", - "Documents": "Dokumentai", "does not make any external connections, and your data stays securely on your locally hosted server.": "neturi jokių išorinių ryšių ir duomenys lieka serveryje.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Neatsisiųskite atsitiktinių pipelines iš nepatikimų šaltinių.", @@ -493,11 +502,14 @@ "Done": "Atlikta", "Download": "Parsisiųsti", "Download & Delete": "Atsisiųsti ir ištrinti", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Parsisiuntimas atšauktas", "Download Database": "Parsisiųsti duomenų bazę", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "pvz. '30s', '10m'. Laiko vienetai yra 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Įveskite Bravo Search API raktą", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Įveskite blokų persidengimą", "Enter Chunk Size": "Įveskite blokų dydį", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Įveskite GitHub Raw nuorodą", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Įveskite paveiksliuko dydį (pvz. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Įveskite kalbos kodus", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Vasaris", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "Galite pridėti specifinių detalių", "Female": "", "File": "Rinkmena", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Nepavyko nsutatyti profilio nuotraukos", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Bendri", "Generate": "", "Generate an image": "", - "Generate Image": "Generuoti paveikslėlį", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Generuoti paieškos užklausą", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "Globalu", "Good Response": "Geras atsakymas", + "Google": "", "Google Drive": "", "Google PSE API Key": "Google PSE API raktas", "Google PSE Engine Id": "Google PSE variklio ID", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grupė", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Vaizdai", "Import": "", "Import Chats": "Importuoti pokalbius", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Sąsaja", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Sausis", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "prisijunkite prie mūsų Discord.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Kovas", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Daugiausiai trys modeliai gali būti parsisiunčiami vienu metu.", "May": "gegužė", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Atminitis prieinama kalbos modelio bus rodoma čia.", "Memory": "Atmintis", "Memory added successfully": "Atmintis pridėta sėkmingai", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Sujungtas atsakymas", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Žinutės, kurias siunčiate po nuorodos sukūrimo nebus matomos nuorodos turėtojams. Naudotojai su nuoroda matys žinutes iki nuorodos sukūrimo.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Modelis nepasirinktas", "Model Params": "Modelio parametrai", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Modelis atnaujintas sėkmingai", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Daugiau", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "Nėra pasirinktų dokumentų", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Rezultatų nerasta", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Regis nuoroda nevalidi. Prašau patikrtinkite ir pabandykite iš naujo.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Tortue Chat versija per sena. Reikalinga (v{{REQUIRED_VERSION}}) versija.", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Slaptažodis", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Procesas ištrintas sėkmingai", "Pipeline downloaded successfully": "Procesas atsisiųstas sėkmingai", - "Pipelines": "Procesai", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines yra papildinių sistema, leidžianti vykdyti bet kokį kodą —", "Pipelines Not Detected": "Procesai neaptikti", "Pipelines Valves": "Procesų įeitys", @@ -1500,6 +1534,7 @@ "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.": "", "Setting": "", "Settings": "Nustatymai", + "Settings Permissions": "", "Settings saved successfully!": "Parametrai sėkmingai išsaugoti!", "Share": "Dalintis", "Share Chat": "Dalintis pokalbiu", @@ -1543,6 +1578,7 @@ "Speech recognition error: {{error}}": "Balso atpažinimo problema: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Balso atpažinimo modelis", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Kanalo pradžia", "Start Tag": "", @@ -1553,6 +1589,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Baigt sekvenciją", "Stream Chat Response": "", @@ -1573,7 +1610,14 @@ "Support": "Palaikyti", "Support this plugin:": "Palaikykite šitą modulį", "Supported MIME Types": "", + "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.": "", "System": "Sistema", "System Instructions": "", "System Prompt": "Sistemos užklausa", @@ -1618,6 +1662,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Mąsto...", "This action cannot be undone. Do you wish to continue?": "Šis veiksmas negali būti atšauktas. Ar norite tęsti?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1732,6 +1777,7 @@ "Upload Pipeline": "Atnaujinti procesą", "Upload Progress": "Įkėlimo progresas", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1749,6 +1795,7 @@ "User Groups": "", "User location successfully retrieved.": "Naudotojo vieta sėkmingai gauta", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1798,15 +1845,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Kas naujo", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (lokalus)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "Plataus ekrano rėžimas", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "Nuostatos", @@ -1818,6 +1869,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Vakar", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Jūs", @@ -1825,6 +1878,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Galite pagerinti modelių darbą suteikdami jiems atminties funkcionalumą.", "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 save this prompt.": "", "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.": "", @@ -1836,6 +1892,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Jūsų paskyra laukia administratoriaus patvirtinimo.", "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.": "Jūsų finansinis prisidėjimas tiesiogiai keliaus modulio kūrėjui.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/ms-MY/translation.json b/src/lib/i18n/locales/ms-MY/translation.json index 508e3c5996..36b22ac497 100644 --- a/src/lib/i18n/locales/ms-MY/translation.json +++ b/src/lib/i18n/locales/ms-MY/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Melaraskan tetapan ini akan menggunakan perubahan secara universal kepada semua pengguna.", "admin": "pentadbir", "Admin": "Pentadbir", + "Admin Contact Email": "", "Admin Panel": "Panel Pentadbir", "Admin Settings": "Tetapan Pentadbir", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Pentadbir mempunyai akses kepada semua alat pada setiap masa; pengguna memerlukan alat yang ditetapkan mengikut model dalam ruang kerja.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Benarkan suara bukan tempatan ", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "dan cipta pautan kongsi baharu", "Android": "", + "Anyone": "", "API Base URL": "URL Asas API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Kunci API", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Salin Response secara Automatik ke Papan Klip", "Auto-playback response": "Main semula respons secara automatik", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "URL Asas AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "URL Asas AUTOMATIC1111 diperlukan.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "pengguna tersedia", @@ -201,6 +204,7 @@ "before": "sebelum,", "Being lazy": "Menjadi Malas", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Kunci API Carian Brave", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Semak kemas kini", "Checking for updates...": "Kemas kini sedang disemak", "Choose a model before saving...": "Pilih model sebelum menyimpan", + "Chunk Min Size Target": "", "Chunk Overlap": "Tindihan 'Çhunk'", "Chunk Size": "Saiz 'Chunk'", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Petikan", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "Kod berjaya diformatkan", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Hubungi admin untuk akses WebUI", "Content": "Kandungan", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Teruskan Respons", "Continue with {{provider}}": "Teruskan dengan {{provider}}", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Pangkalan Data", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Disember", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "", "Do not install functions from sources you do not fully trust.": "Jangan pasang fungsi daripada sumber yang anda tidak percayai sepenuhnya.", "Do not install tools from sources you do not fully trust.": "Jangan pasang alat daripada sumber yang anda tidak percaya sepenuhnya.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentasi", - "Documents": "Dokumen", "does not make any external connections, and your data stays securely on your locally hosted server.": "tidak membuat sebarang sambungan luaran, dan data anda kekal selamat pada pelayan yang dihoskan ditempat anda", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Jangan ambil pipeline rawak daripada sumber yang anda tidak percayai.", @@ -493,11 +502,14 @@ "Done": "Selesai", "Download": "Muat Turun", "Download & Delete": "Muat turun & Padam", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Muat Turun dibatalkan", "Download Database": "Muat turun Pangkalan Data", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "cth '30s','10m'. Unit masa yang sah ialah 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Masukkan Kekunci API carian Brave", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Masukkan Tindihan 'Chunk'", "Enter Chunk Size": "Masukkan Saiz 'Chunk'", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Masukkan URL 'Github Raw'", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Masukkan Saiz Imej (cth 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Masukkan kod bahasa", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Febuari", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "Jangan ragu untuk menambah butiran khusus", "Female": "", "File": "Fail", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Peniruan cap jari dikesan, tidak dapat menggunakan nama pendek sebagai avatar. Lalai kepada imej profail asal", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Umum", "Generate": "", "Generate an image": "", - "Generate Image": "Jana Imej", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Jana pertanyaan carian", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "Global", "Good Response": "Respons Baik", + "Google": "", "Google Drive": "", "Google PSE API Key": "Kunci API Google PSE", "Google PSE Engine Id": "ID Enjin Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Kumpulan", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Imej", "Import": "", "Import Chats": "Import Perbualan", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Antaramuka", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Januari", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "sertai Discord kami untuk mendapatkan bantuan.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Mac", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksimum 3 model boleh dimuat turun serentak. Sila cuba sebentar lagi.", "May": "Mei", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Memori yang boleh diakses oleh LLM akan ditunjukkan di sini.", "Memory": "Memori", "Memory added successfully": "Memori berjaya ditambah", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Respons Digabungkan", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Mesej yang anda hantar selepas membuat pautan anda tidak akan dikongsi. Pengguna dengan URL akan dapat melihat perbualan yang dikongsi.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model tidak dipilih", "Model Params": "Model Params", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Model berjaya dikemas kini", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Lagi", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "Tiada fail dipilih", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Tiada keputusan dijumpai", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Maaf, didapati URL tidak sah. Sila semak semula dan cuba lagi.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) adalah lebih rendah daripada versi yang diperlukan iaitu (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Kata Laluan", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "'Pipeline' berjaya dipadam", "Pipeline downloaded successfully": "'Pipeline' berjaya dimuat turun", - "Pipelines": "'Pipeline'", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines ialah sistem pemalam dengan pelaksanaan kod sewenang‑wenangnya —", "Pipelines Not Detected": "'Pipeline' tidak ditemui", "Pipelines Valves": "'Pipeline Valves'", @@ -1497,6 +1531,7 @@ "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.": "", "Setting": "", "Settings": "Tetapan", + "Settings Permissions": "", "Settings saved successfully!": "Tetapan berjaya disimpan!", "Share": "Kongsi", "Share Chat": "Kongsi Perbualan", @@ -1540,6 +1575,7 @@ "Speech recognition error: {{error}}": "Ralat pengecaman pertuturan: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Enjin Ucapan-ke-Teks", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Permulaan saluran", "Start Tag": "", @@ -1550,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Jujukan Henti", "Stream Chat Response": "", @@ -1570,7 +1607,14 @@ "Support": "Sokongan", "Support this plugin:": "Sokong plugin ini", "Supported MIME Types": "", + "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.": "", "System": "Sistem", "System Instructions": "", "System Prompt": "Gesaan Sistem", @@ -1615,6 +1659,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Berfikir...", "This action cannot be undone. Do you wish to continue?": "Tindakan ini tidak boleh diubah semula kepada asal. Adakah anda ingin teruskan", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1729,6 +1774,7 @@ "Upload Pipeline": "Muatnaik 'Pipeline'", "Upload Progress": "Kemajuan Muatnaik", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1746,6 +1792,7 @@ "User Groups": "", "User location successfully retrieved.": "Lokasi pengguna berjaya diambil.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1795,15 +1842,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Apakah yang terbaru dalam", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (Local)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "Mod Skrin Lebar", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "Ruangan Kerja", @@ -1815,6 +1866,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Semalam", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Anda", @@ -1822,6 +1875,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Anda boleh memperibadikan interaksi anda dengan LLM dengan menambahkan memori melalui butang 'Urus' di bawah, menjadikannya lebih membantu dan disesuaikan dengan anda.", "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 save this prompt.": "", "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.": "", @@ -1833,6 +1889,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Status akaun anda ialah sedang menunggu pengaktifan.", "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.": "Seluruh sumbangan anda akan dihantar terus kepada pembangun 'plugin'; Open WebUI tidak mengambil sebarang peratusan keuntungan daripadanya. Walau bagaimanapun, platform pembiayaan yang dipilih mungkin mempunyai caj tersendiri.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/nb-NO/translation.json b/src/lib/i18n/locales/nb-NO/translation.json index 309b20c073..ba54f4f516 100644 --- a/src/lib/i18n/locales/nb-NO/translation.json +++ b/src/lib/i18n/locales/nb-NO/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Endring av disse innstillingene vil gjelde for alle brukere på tvers av systemet.", "admin": "administrator", "Admin": "Administrator", + "Admin Contact Email": "", "Admin Panel": "Administratorpanel", "Admin Settings": "Administratorinnstillinger", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratorer har alltid tilgang til alle verktøy. Brukere må få tildelt verktøy per modell i arbeidsområdet.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Tillatt opplasting av filer", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Tillat ikke-lokale stemmer", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "og {{COUNT}} til", "and create a new shared link.": "og opprett en ny delt lenke.", "Android": "", + "Anyone": "", "API Base URL": "Absolutt API-URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API-nøkkel", @@ -175,6 +176,7 @@ "Authenticate": "Godkjenn", "Authentication": "Godkjenning", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Kopier svar automatisk til utklippstavlen", "Auto-playback response": "Spill av svar automatisk", "Autocomplete Generation": "Generering av autofullføring", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "API-Autentiseringsstreng for AUTOMATIC1111", "AUTOMATIC1111 Base URL": "Absolutt URL for AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Absolutt URL for AUTOMATIC1111 kreves.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Tilgjengelig liste", "Available Tools": "", "available users": "tilgjengelige brukere", @@ -201,6 +204,7 @@ "before": "før", "Being lazy": "Er lat", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Endepunkt for Bing Search V7", "Bing Search V7 Subscription Key": "Abonnementsnøkkel for Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "API-nøkkel for Bocha Search", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "API-nøkkel for Brave Search", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Sjekk for oppdateringer", "Checking for updates...": "Sjekker for oppdateringer ...", "Choose a model before saving...": "Velg en modell før du lagrer ...", + "Chunk Min Size Target": "", "Chunk Overlap": "Chunk-overlapp", "Chunk Size": "Chunk-størrelse", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Chiffer", "Citation": "Kildehenvisning", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Kodekjøring", - "Code Execution": "Kodekjøring", "Code Execution Engine": "Motor for kodekjøring", "Code Execution Timeout": "Tidsavbrudd for kodekjøring", "Code formatted successfully": "Koden er formatert", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Kontakt administrator for å få tilgang til WebUI", "Content": "Innhold", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Fortsett svar", "Continue with {{provider}}": "Fortsett med {{provider}}", "Continue with Email": "Fortsett med e-post", @@ -393,6 +401,7 @@ "Database": "Database", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "desember", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Bli kjent med kunnskap", "Do not install functions from sources you do not fully trust.": "Ikke installer funksjoner fra kilder du ikke stoler på.", "Do not install tools from sources you do not fully trust.": "Ikke installer verktøy fra kilder du ikke stoler på.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentasjon", - "Documents": "Dokumenter", "does not make any external connections, and your data stays securely on your locally hosted server.": "ikke ingen tilkobling til eksterne tjenester. Dataene dine forblir sikkert på den lokale serveren.", "Domain Filter List": "Liste over domenefiltre", "don't fetch random pipelines from sources you don't trust.": "Ikke hent tilfeldige pipelines fra kilder du ikke stoler på.", @@ -493,11 +502,14 @@ "Done": "Ferdig", "Download": "Last ned", "Download & Delete": "Last ned og slett", + "Download as JSON": "", "Download as SVG": "Last ned som SVG", "Download canceled": "Nedlasting avbrutt", "Download Database": "Last ned database", + "Downloading stats...": "", "Draw": "Tegne", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "f.eks. '30s','10m'. Gyldige tidsenheter er 's', 'm', 't'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "f.eks. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Aktiver API-nøkkel for Bocha Search", "Enter Brave Search API Key": "Angi API-nøkkel for Brave Search", "Enter certificate path": "Angi sertifikatets bane", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Angi Chunk-overlapp", "Enter Chunk Size": "Angi Chunk-størrelse", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Angi Github Raw-URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Angi bildestørrelse (f.eks. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Angi API-nøkkel for Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Angi passord for Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Angi API-nøkkel for Kagi Search", "Enter Key Behavior": "", "Enter language codes": "Angi språkkoder", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Angi modellens ID", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Funksjoner", "Features Permissions": "Tillatelser for funksjoner", "February": "februar", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Tilbakemeldingslogg", - "Feedbacks": "Tilbakemeldinger", "Feel free to add specific details": "Legg gjerne til bestemte detaljer", "Female": "", "File": "Fil", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingeravtrykk-spoofing oppdaget: kan ikke bruke initialer som avatar. Bruker standard profilbilde.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Mappe slettet", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Mappenavn kan ikke være tomt.", "Folder name updated successfully": "Mappenavn oppdatert", @@ -826,7 +846,6 @@ "General": "Generelt", "Generate": "", "Generate an image": "Genrer et bilde", - "Generate Image": "Generer bilde", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Genererer søkespørring", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Kom i gang med {{WEBUI_NAME}}", "Global": "Globalt", "Good Response": "Godt svar", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "API-nøkkel for Google PSE", "Google PSE Engine Id": "Motor-ID for Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Gruppe", "Group Channel": "", "Group created successfully": "Gruppe opprettet", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Generering av ledetekster for bilder", "Image Prompt Generation Prompt": "Ledetekst for generering av bilde", "Image Size": "", - "Images": "Bilder", "Import": "", "Import Chats": "Importer chatter", "Import Config from JSON File": "Importer konfigurasjon fra en JSON-fil", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Grensesnitt", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Ugyldig filformat.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "Skriver...", "Italic": "", "January": "januar", + "Jina API Base URL": "", "Jina API Key": "API-nøkkel for Jina", "join our Discord for help.": "bli med i Discord-fellesskapet vårt for å få hjelp.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "La stå tomt for å inkludere alle modeller", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "La stå tomt for å bruke standard ledetekst, eller angi en tilpasset ledetekst", "Leave model field empty to use the default model.": "La modellfeltet stå tomt for å bruke standard modell.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "mars", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Maks antall opplastinger", "Max Upload Size": "Maks størrelse på opplasting", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksimalt tre modeller kan lastes ned samtidig. Prøv igjen senere.", "May": "mai", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Språkmodellers tilgjengelige minner vises her.", "Memory": "Minne", "Memory added successfully": "Minne lagt til", @@ -1051,6 +1077,7 @@ "Merge Responses": "Flette svar", "Merged Response": "Sammenslått svar", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Vurdering av meldinger må være aktivert for å ta i bruk denne funksjonen", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Meldinger du sender etter at du har opprettet lenken, blir ikke delt. Brukere med URL-en vil kunne se den delte chatten.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Modell", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Modell ikke valgt", "Model Params": "Modellparametere", "Model Permissions": "Modelltillatelser", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Modell oppdatert", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "API-nøekkel for Mojeek Search", "More": "Mer", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Ingen avstand tilgjengelig", "No expiration can pose security risks.": "", - "No feedbacks found": "Finner ingen tilbakemeldinger", + "No feedback found": "", "No file selected": "Ingen fil valgt", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Ingen modeller er valgt", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Finner ingen resultater", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Bare utvalgte brukere og grupper med tillatelse kan få tilgang", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oi! Det ser ut som URL-en er ugyldig. Dobbeltsjekk, og prøv på nytt.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Oi! Det er fortsatt filer som lastes opp. Vent til opplastingen er ferdig.", "Oops! There was an error in the previous response.": "Oi! Det er en feil i det forrige svaret.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI bruker faster-whisper internt.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI bruker SpeechT5 og CMU Arctic-høytalerinnbygginger", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI-versjonen (v{{OPEN_WEBUI_VERSION}}) er lavere enn den påkrevde versjonen (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI-API", @@ -1235,6 +1268,8 @@ "page": "side", "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.": "", "Password": "Passord", "Passwords do not match.": "", "Paste Large Text as File": "Lim inn mye tekst som fil", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline slettet", "Pipeline downloaded successfully": "Pipeline lastet ned", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines er et programtilleggssystem med vilkårlig kodekjøring —", "Pipelines Not Detected": "Ingen pipelines oppdaget", "Pipelines Valves": "Pipeline-ventiler", @@ -1498,6 +1532,7 @@ "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.": "Angir hvilke stoppsekvenser som skal brukes. Når dette mønsteret forekommer, stopper LLM genereringen av tekst og returnerer. Du kan angi flere stoppmønstre ved å spesifisere flere separate stoppparametere i en modellfil.", "Setting": "", "Settings": "Innstillinger", + "Settings Permissions": "", "Settings saved successfully!": "Innstillinger lagret!", "Share": "Del", "Share Chat": "Del chat", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Feil ved talegjenkjenning: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Motor for Tale-til-tekst", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Starten av kanalen", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Stopp", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Stoppsekvens", "Stream Chat Response": "Strømme chat-svar", @@ -1571,7 +1608,14 @@ "Support": "Bidra", "Support this plugin:": "Bidra til denne utvidelsen:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synkroniseringsmappe", + "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", "System Instructions": "Systeminstruksjoner", "System Prompt": "Systemledetekst", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Tenker ...", "This action cannot be undone. Do you wish to continue?": "Denne handlingen kan ikke angres. Vil du fortsette?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Last opp pipeline", "Upload Progress": "Opplastingsfremdrift", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Brukerens lokasjon hentet", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Brukernavn", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI vil rette forespørsler til \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Hva prøver du å oppnå?", "What are you working on?": "Hva jobber du på nå?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Hva er nytt i", "What's on your mind?": "", "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.": "Hvis denne modusen er aktivert, svarer modellen på alle chattemeldinger i sanntid, og genererer et svar så snart brukeren sender en melding. Denne modusen er nyttig for live chat-applikasjoner, men kan påvirke ytelsen på tregere maskinvare.", "wherever you are": "uansett hvor du er", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", "Whisper (Local)": "Whisper (Lokal)", + "Who can share to this group": "", "Why?": "Hvorfor?", "Widescreen Mode": "Bredskjermmodus", "Width": "", + "Wikipedia": "", "Won": "Vant", "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.": "", "Workspace": "Arbeidsområde", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "I går", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Du", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Du kan bare chatte med maksimalt {{maxCount}} fil(er) om gangen.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Du kan tilpasse interaksjonene dine med språkmodeller ved å legge til minner gjennom Administrer-knappen nedenfor, slik at de blir mer til nyttige og tilpasset deg.", "You cannot upload an empty file.": "Du kan ikke laste opp en tom fil.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Status på kontoen din er for øyeblikket ventende på aktivering.", "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.": "Hele beløpet går uavkortet til utvikleren av tillegget. Open WebUI mottar ikke deler av beløpet. Den valgte betalingsplattformen kan ha gebyrer.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index ea479ef234..c4ffad00a1 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -77,6 +77,7 @@ "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 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.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Bestandenupload toestaan", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Niet-lokale stemmen toestaan", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "en {{COUNT}} meer", "and create a new shared link.": "en maak een nieuwe gedeelde link.", "Android": "", + "Anyone": "", "API Base URL": "API Base URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API-sleutel", @@ -175,6 +176,7 @@ "Authenticate": "Authenticeer", "Authentication": "Authenticatie", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Antwoord automatisch kopiëren naar klembord", "Auto-playback response": "Automatisch afspelen van antwoord", "Autocomplete Generation": "Automatische aanvullingsgeneratie", @@ -183,6 +185,7 @@ "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.)": "", "Available list": "Beschikbare lijst", "Available Tools": "", "available users": "beschikbare gebruikers", @@ -201,6 +204,7 @@ "before": "voor", "Being lazy": "Lui zijn", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 Endpoint", "Bing Search V7 Subscription Key": "Bing Search V7 Subscription Key", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search API-sleutel", "Bold": "", "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 Search API Key": "Brave Search API-sleutel", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "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 Overlap": "Chunkoverlap", "Chunk Size": "Chunkgrootte", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Versleutelingen", "Citation": "Citaat", "Citations": "Citaten", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Code uitvoeren", - "Code Execution": "Code-uitvoer", "Code Execution Engine": "Code-uitvoer engine", "Code Execution Timeout": "Code-uitvoer time-out", "Code formatted successfully": "Code succesvol geformateerd", @@ -336,6 +343,7 @@ "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)": "", "Continue Response": "Doorgaan met antwoord", "Continue with {{provider}}": "Ga verder met {{provider}}", "Continue with Email": "Ga door met E-mail", @@ -393,6 +401,7 @@ "Database": "Database", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "December", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Duik in 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?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "Docling server-URL benodigd", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Documentatie", - "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.", @@ -493,11 +502,14 @@ "Done": "Voltooid", "Download": "Download", "Download & Delete": "Downloaden en verwijderen", + "Download as JSON": "", "Download as SVG": "Download als SVG", "Download canceled": "Download geannuleerd", "Download Database": "Download database", + "Downloading stats...": "", "Draw": "Teken", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "bijv. '30s', '10m'. Geldige tijdseenheden zijn 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "bijv. \"json\" of een JSON-schema", "e.g. 60": "bijv. 60", @@ -572,6 +584,7 @@ "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 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)", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Voer de Github Raw-URL in", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Voeg afbeelding formaat toe (Bijv. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Voer Jina API-sleutel in", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Voer Jupyter-wachtwoord in", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Voer Kagi Search API-sleutel in", "Enter Key Behavior": "Voer sleutelgedrag in", "Enter language codes": "Voeg taalcodes toe", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Voer model-ID in", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Functies", "Features Permissions": "Functietoestemmingen", "February": "Februari", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Feedback geschiedenis", - "Feedbacks": "Feedback", "Feel free to add specific details": "Voeg specifieke details toe", "Female": "", "File": "Bestand", @@ -776,11 +794,13 @@ "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 deleted successfully": "Map succesvol verwijderd", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Mapnaam kan niet leeg zijn", "Folder name updated successfully": "Mapnaam succesvol aangepast", @@ -826,7 +846,6 @@ "General": "Algemeen", "Generate": "", "Generate an image": "Genereer een afbeelding", - "Generate Image": "Genereer afbeelding", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Zoekopdracht genereren", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Begin met {{WEBUI_NAME}}", "Global": "Globaal", "Good Response": "Goed antwoord", + "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": "Groep", "Group Channel": "", "Group created successfully": "Groep succesvol aangemaakt", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Afbeeldingspromptgeneratie", "Image Prompt Generation Prompt": "Afbeeldingspromptgeneratie prompt", "Image Size": "", - "Images": "Afbeeldingen", "Import": "", "Import Chats": "Importeer Chats", "Import Config from JSON File": "Importeer configuratie vanuit JSON-bestand", @@ -927,6 +947,7 @@ "Integration": "Integratie", "Integrations": "", "Interface": "Interface", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Ongeldig bestandsformaat", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "is aan het schrijven...", "Italic": "", "January": "Januari", + "Jina API Base URL": "", "Jina API Key": "Jina API-sleutel", "join our Discord for help.": "join onze Discord voor hulp.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "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 model (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.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Maart", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Maximale Uploadhoeveelheid", "Max Upload Size": "Maximale Uploadgrootte", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder 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": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Geheugen toegankelijk voor LLMs wordt hier getoond.", "Memory": "Geheugen", "Memory added successfully": "Geheugen succesvol toegevoegd", @@ -1051,6 +1077,7 @@ "Merge Responses": "Voeg antwoorden samen", "Merged Response": "Samengevoegd antwoord", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Berichtbeoordeling moet ingeschakeld zijn om deze functie te gebruiken", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "Modelnaam", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model niet geselecteerd", "Model Params": "Modelparams", "Model Permissions": "Modeltoestemmingen", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Model succesvol bijgewerkt", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Modellen publiek delen", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API-sleutel", "More": "Meer", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Geen afstand beschikbaar", "No expiration can pose security risks.": "", - "No feedbacks found": "Geen feedback gevonden", + "No feedback found": "", "No file selected": "Geen bestand geselecteerd", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Geen modellen geselecteerd", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Geen resultaten gevonden", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Alleen geselecteerde gebruikers en groepen met toestemming hebben toegang", + "Only sync new/updated chats": "", "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.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "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 (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", @@ -1235,6 +1268,8 @@ "page": "pagina", "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.": "", "Password": "Wachtwoord", "Passwords do not match.": "", "Paste Large Text as File": "Plak grote tekst als bestand", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pijpleiding succesvol verwijderd", "Pipeline downloaded successfully": "Pijpleiding succesvol gedownload", - "Pipelines": "Pijpleidingen", "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", @@ -1498,6 +1532,7 @@ "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": "", "Settings": "Instellingen", + "Settings Permissions": "", "Settings saved successfully!": "Instellingen succesvol opgeslagen!", "Share": "Delen", "Share Chat": "Deel chat", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Spraakherkenning fout: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Spraak-naar-tekst Engine", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Begin van het kanaal", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Stop", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Stopsequentie", "Stream Chat Response": "Stream chat-antwoord", @@ -1571,7 +1608,14 @@ "Support": "Ondersteuning", "Support this plugin:": "ondersteun deze plugin", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "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.": "", "System": "Systeem", "System Instructions": "Systeem instructies", "System Prompt": "Systeem prompt", @@ -1616,6 +1660,7 @@ "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.": "", "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?", "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}}.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Upload Pijpleiding", "Upload Progress": "Upload Voortgang", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Gebruikerslocatie succesvol opgehaald", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "Gebruiker-webhooks", "Username": "Gebruikersnaam", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI zal verzoeken doen aan \"{{url}}/chat/completions\"", "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's New in": "Wat is nieuw in", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (Lokaal)", + "Who can share to this group": "", "Why?": "Waarom?", "Widescreen Mode": "Breedschermmodus", "Width": "", + "Wikipedia": "", "Won": "Gewonnen", "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", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Gisteren", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Jij", @@ -1823,6 +1876,9 @@ "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Je accountstatus wacht nu op activatie", "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.": "", "YouTube": "Youtube", "Youtube Language": "Youtube-taal", "Youtube Proxy URL": "Youtube-proxy-URL" diff --git a/src/lib/i18n/locales/pa-IN/translation.json b/src/lib/i18n/locales/pa-IN/translation.json index 2d56f565a3..e7406474cd 100644 --- a/src/lib/i18n/locales/pa-IN/translation.json +++ b/src/lib/i18n/locales/pa-IN/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "ਇਹ ਸੈਟਿੰਗਾਂ ਨੂੰ ਠੀਕ ਕਰਨ ਨਾਲ ਸਾਰੇ ਉਪਭੋਗਤਾਵਾਂ ਲਈ ਬਦਲਾਅ ਲਾਗੂ ਹੋਣਗੇ।", "admin": "ਪ੍ਰਬੰਧਕ", "Admin": "", + "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.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "ਅਤੇ ਇੱਕ ਨਵਾਂ ਸਾਂਝਾ ਲਿੰਕ ਬਣਾਓ।", "Android": "", + "Anyone": "", "API Base URL": "API ਬੇਸ URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API ਕੁੰਜੀ", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "ਜਵਾਬ ਆਟੋ ਕਾਪੀ ਕਲਿੱਪਬੋਰਡ 'ਤੇ", "Auto-playback response": "ਆਟੋ-ਪਲੇਬੈਕ ਜਵਾਬ", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "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.)": "", "Available list": "", "Available Tools": "", "available users": "ਉਪਲਬਧ ਯੂਜ਼ਰ", @@ -201,6 +204,7 @@ "before": "ਪਹਿਲਾਂ", "Being lazy": "ਆਲਸੀ ਹੋਣਾ", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "ਬਹਾਦਰ ਖੋਜ API ਕੁੰਜੀ", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "ਅੱਪਡੇਟ ਲਈ ਜਾਂਚ ਕਰੋ", "Checking for updates...": "ਅੱਪਡੇਟ ਲਈ ਜਾਂਚ ਰਿਹਾ ਹੈ...", "Choose a model before saving...": "ਸੰਭਾਲਣ ਤੋਂ ਪਹਿਲਾਂ ਇੱਕ ਮਾਡਲ ਚੁਣੋ...", + "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.": "", "Ciphers": "", "Citation": "ਹਵਾਲਾ", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "ਸਮੱਗਰੀ", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "ਜਵਾਬ ਜਾਰੀ ਰੱਖੋ", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "ਡਾਟਾਬੇਸ", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "ਦਸੰਬਰ", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "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.": "ਅਣਵਿਸ਼ਵਾਸਯੋਗ ਸਰੋਤਾਂ ਤੋਂ ਰੈਂਡਮ ਪਾਈਪਲਾਈਨ ਨਾ ਲਓ।", @@ -493,11 +502,14 @@ "Done": "", "Download": "ਡਾਊਨਲੋਡ", "Download & Delete": "ਡਾਊਨਲੋਡ ਅਤੇ ਮਿਟਾਓ", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "ਡਾਊਨਲੋਡ ਰੱਦ ਕੀਤਾ ਗਿਆ", "Download Database": "ਡਾਟਾਬੇਸ ਡਾਊਨਲੋਡ ਕਰੋ", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "ਉਦਾਹਰਣ ਲਈ '30ਸ','10ਮਿ'. ਸਹੀ ਸਮਾਂ ਇਕਾਈਆਂ ਹਨ 'ਸ', 'ਮ', 'ਘੰ'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "ਬਹਾਦਰ ਖੋਜ API ਕੁੰਜੀ ਦਾਖਲ ਕਰੋ", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "ਚੰਕ ਓਵਰਲੈਪ ਦਰਜ ਕਰੋ", "Enter Chunk Size": "ਚੰਕ ਆਕਾਰ ਦਰਜ ਕਰੋ", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Github ਕੱਚਾ URL ਦਾਖਲ ਕਰੋ", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "ਚਿੱਤਰ ਆਕਾਰ ਦਰਜ ਕਰੋ (ਉਦਾਹਰਣ ਲਈ 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "ਭਾਸ਼ਾ ਕੋਡ ਦਰਜ ਕਰੋ", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "ਫਰਵਰੀ", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "ਖੁੱਲ੍ਹੇ ਦਿਲ ਨਾਲ ਖਾਸ ਵੇਰਵੇ ਸ਼ਾਮਲ ਕਰੋ", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "ਫਿੰਗਰਪ੍ਰਿੰਟ ਸਪੂਫਿੰਗ ਪਾਈ ਗਈ: ਅਵਤਾਰ ਵਜੋਂ ਸ਼ੁਰੂਆਤੀ ਅੱਖਰ ਵਰਤਣ ਵਿੱਚ ਅਸਮਰੱਥ। ਮੂਲ ਪ੍ਰੋਫਾਈਲ ਚਿੱਤਰ 'ਤੇ ਡਿਫਾਲਟ।", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "ਆਮ", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "ਖੋਜ ਪੁੱਛਗਿੱਛ ਤਿਆਰ ਕਰਨਾ", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "ਵਧੀਆ ਜਵਾਬ", + "Google": "", "Google Drive": "", "Google PSE API Key": "Google PSE API ਕੁੰਜੀ", "Google PSE Engine Id": "ਗੂਗਲ PSE ਇੰਜਣ ID", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "ਗਰੁੱਪ", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "ਚਿੱਤਰ", "Import": "", "Import Chats": "ਗੱਲਾਂ ਆਯਾਤ ਕਰੋ", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "ਇੰਟਰਫੇਸ", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "ਜਨਵਰੀ", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "ਮਦਦ ਲਈ ਸਾਡੇ ਡਿਸਕੋਰਡ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਵੋ।", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "ਮਾਰਚ", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "ਇੱਕ ਸਮੇਂ ਵਿੱਚ ਵੱਧ ਤੋਂ ਵੱਧ 3 ਮਾਡਲ ਡਾਊਨਲੋਡ ਕੀਤੇ ਜਾ ਸਕਦੇ ਹਨ। ਕਿਰਪਾ ਕਰਕੇ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।", "May": "ਮਈ", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLMs ਲਈ ਸਮਰੱਥ ਕਾਰਨ ਇੱਕ ਸੂਚਨਾ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ ਹੈ।", "Memory": "ਮੀਮਰ", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "ਮਿਲਾਇਆ ਗਿਆ ਜਵਾਬ", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "ਮਾਡਲ ਚੁਣਿਆ ਨਹੀਂ ਗਿਆ", "Model Params": "ਮਾਡਲ ਪਰਮਜ਼", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "ਹੋਰ", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "ਕੋਈ ਨਤੀਜੇ ਨਹੀਂ ਮਿਲੇ", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "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.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "ਓਪਨਏਆਈ", "OpenAI API": "ਓਪਨਏਆਈ API", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "ਪਾਸਵਰਡ", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "ਪਾਈਪਲਾਈਨਾਂ", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines ਇੱਕ ਪਲੱਗਇਨ ਸਿਸਟਮ ਹੈ ਜਿਸ ਵਿੱਚ ਮਨਚਾਹਾ ਕੋਡ ਚੱਲ ਸਕਦਾ ਹੈ —", "Pipelines Not Detected": "", "Pipelines Valves": "ਪਾਈਪਲਾਈਨਾਂ ਵਾਲਵ", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "ਸੈਟਿੰਗਾਂ", + "Settings Permissions": "", "Settings saved successfully!": "ਸੈਟਿੰਗਾਂ ਸਫਲਤਾਪੂਰਵਕ ਸੰਭਾਲੀਆਂ ਗਈਆਂ!", "Share": "ਸਾਂਝਾ ਕਰੋ", "Share Chat": "ਗੱਲਬਾਤ ਸਾਂਝੀ ਕਰੋ", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "ਬੋਲ ਪਛਾਣ ਗਲਤੀ: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "ਬੋਲ-ਤੋਂ-ਪਾਠ ਇੰਜਣ", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "ਚੈਨਲ ਦੀ ਸ਼ੁਰੂਆਤ", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "ਰੋਕੋ ਕ੍ਰਮ", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "ਸਿਸਟਮ", "System Instructions": "", "System Prompt": "ਸਿਸਟਮ ਪ੍ਰੰਪਟ", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "ਥੀਮ", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "ਅਪਲੋਡ ਪ੍ਰਗਤੀ", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "ਨਵਾਂ ਕੀ ਹੈ", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "ਕਾਰਜਸਥਲ", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "ਕੱਲ੍ਹ", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "ਤੁਸੀਂ", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "ਯੂਟਿਊਬ", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index 21a909c893..04b6c52003 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Zmiana tych ustawień wpłynie na wszystkich użytkowników.", "admin": "administrator", "Admin": "Administrator", + "Admin Contact Email": "", "Admin Panel": "Panel administracyjny", "Admin Settings": "Ustawienia administratora", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratorzy mają zawsze dostęp do wszystkich narzędzi; użytkownicy muszą mieć przypisane narzędzia do modelu w obszarze roboczym.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Zezwól na kontynuację odpowiedzi", "Allow Delete Messages": "Zezwól na usuwanie wiadomości", "Allow File Upload": "Zezwól na przesyłanie plików", - "Allow Group Sharing": "Zezwól na udostępnianie grupowe", "Allow Multiple Models in Chat": "Zezwól na wiele modeli w czacie", "Allow non-local voices": "Zezwól na głosy nielokalne", "Allow Rate Response": "Zezwól na ocenianie odpowiedzi", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "i {{COUNT}} więcej", "and create a new shared link.": "i utwórz nowy link udostępniania.", "Android": "Android", + "Anyone": "", "API Base URL": "Bazowy adres URL API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "Bazowy adres URL API dla usługi Datalab Marker. Domyślnie: https://www.datalab.to/api/v1/marker", "API Key": "Klucz API", @@ -175,6 +176,7 @@ "Authenticate": "Uwierzytelnij", "Authentication": "Uwierzytelnianie", "Auto": "Auto", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatycznie kopiuj odpowiedź do schowka", "Auto-playback response": "Automatyczne odtwarzanie odpowiedzi", "Autocomplete Generation": "Generowanie autouzupełniania", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Ciąg autoryzacji API AUTOMATIC1111", "AUTOMATIC1111 Base URL": "Bazowy adres URL AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Bazowy adres URL AUTOMATIC1111 jest wymagany.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Dostępna lista", "Available Tools": "Dostępne narzędzia", "available users": "dostępni użytkownicy", @@ -201,6 +204,7 @@ "before": "przed", "Being lazy": "Bezczynny", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Punkt końcowy Bing Search V7", "Bing Search V7 Subscription Key": "Klucz subskrypcji Bing Search V7", "Bio": "Bio", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Klucz API Bocha Search", "Bold": "Pogrubienie", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Wzmacnianie lub karanie tokenów. Wartości bias (obciążenia) są ograniczone do zakresu -100 do 100. (Domyślnie: brak)", + "Brave": "", "Brave Search API Key": "Klucz API Brave Search", + "Builtin Tools": "", "Bullet List": "Lista punktowana", "Button ID": "ID Przycisku", "Button Label": "Etykieta przycisku", @@ -256,8 +262,10 @@ "Check for updates": "Sprawdź dostępność aktualizacji", "Checking for updates...": "Sprawdzanie aktualizacji...", "Choose a model before saving...": "Wybierz model przed zapisaniem...", + "Chunk Min Size Target": "", "Chunk Overlap": "Chunk Overlap", "Chunk Size": "Chunk Size", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Szyfry", "Citation": "Cytat", "Citations": "Cytaty", @@ -293,7 +301,6 @@ "Code Block": "Blok kodu", "Code Editor": "Edytor kodu", "Code execution": "Wykonywanie kodu", - "Code Execution": "Wykonywanie kodu", "Code Execution Engine": "Silnik wykonywania kodu", "Code Execution Timeout": "Limit czasu wykonywania kodu", "Code formatted successfully": "Sformatowano kod pomyślnie", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Skontaktuj się z administratorem, aby uzyskać dostęp.", "Content": "Treść", "Content Extraction Engine": "Silnik ekstrakcji treści", + "Content lengths (character counts only)": "", "Continue Response": "Kontynuuj odpowiedź", "Continue with {{provider}}": "Kontynuuj przez {{provider}}", "Continue with Email": "Kontynuuj przez Email", @@ -393,6 +401,7 @@ "Database": "Baza danych", "Datalab Marker API": "API Datalab Marker", "DD/MM/YYYY": "DD/MM/YYYY", + "DDGS Backend": "", "December": "Grudzień", "Decrease UI Scale": "Zmniejsz skalę UI", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "Dive into knowledge": "Zanurz się w wiedzy", "Do not install functions from sources you do not fully trust.": "Nie instaluj funkcji z niezaufanych źródeł.", "Do not install tools from sources you do not fully trust.": "Nie instaluj narzędzi z niezaufanych źródeł.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "Parametry Docling", "Docling Server URL required.": "Wymagany URL serwera Docling.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Wymagany endpoint Document Intelligence.", "Document Intelligence Model": "Model Document Intelligence", "Documentation": "Dokumentacja", - "Documents": "Dokumenty", "does not make any external connections, and your data stays securely on your locally hosted server.": "nie nawiązuje połączeń zewnętrznych, a Twoje dane zostają lokalnie.", "Domain Filter List": "Lista filtrowania domen", "don't fetch random pipelines from sources you don't trust.": "nie pobieraj pipeline'ów z niezaufanych źródeł.", @@ -493,11 +502,14 @@ "Done": "Gotowe", "Download": "Pobierz", "Download & Delete": "Pobierz i usuń", + "Download as JSON": "", "Download as SVG": "Pobierz jako SVG", "Download canceled": "Pobieranie anulowane", "Download Database": "Pobierz bazę danych", + "Downloading stats...": "", "Draw": "Rysuj", "Drop any files here to upload": "Upuść pliki tutaj, aby przesłać", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "np. '30s','10m'. Jednostki: 's' (sek), 'm' (min), 'h' (godz).", "e.g. \"json\" or a JSON schema": "np. \"json\" lub schemat JSON", "e.g. 60": "np. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Wprowadź klucz API Bocha Search", "Enter Brave Search API Key": "Wprowadź klucz API Brave Search", "Enter certificate path": "Wprowadź ścieżkę certyfikatu", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Wprowadź Chunk Overlap", "Enter Chunk Size": "Wprowadź Chunk Size", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Wprowadź pary \"token:bias\" po przecinku (np. 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Wprowadź URL External Web Search", "Enter Firecrawl API Base URL": "Wprowadź Base URL Firecrawl API", "Enter Firecrawl API Key": "Wprowadź klucz API Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Wprowadź nazwę folderu", "Enter function name filter list (e.g. func1, !func2)": "Wprowadź listę filtrów funkcji (np. func1, !func2)", "Enter Github Raw URL": "Wprowadź Github Raw URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Wprowadź kolor hex (np. #FF0000)", "Enter ID": "Wprowadź ID", "Enter Image Size (e.g. 512x512)": "Wprowadź rozmiar obrazu (np. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Wprowadź klucz API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Wprowadź konfigurację JSON (np. {\"disable_links\": true})", "Enter Jupyter Password": "Wprowadź hasło Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Wprowadź klucz API Kagi Search", "Enter Key Behavior": "Zachowanie klawisza Enter", "Enter language codes": "Wprowadź kody języków", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Wprowadź Base URL Mistral API", "Enter Mistral API Key": "Wprowadź klucz API Mistral", "Enter Model ID": "Wprowadź ID modelu", @@ -736,6 +753,7 @@ "Failed to generate title": "Nie udało się wygenerować tytułu", "Failed to import models": "Nie udało się zaimportować modeli", "Failed to load chat preview": "Nie udało się załadować podglądu czatu", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Nie udało się załadować zawartości pliku.", "Failed to move chat": "Nie udało się przenieść czatu", "Failed to process URL: {{url}}": "Nie udało się przetworzyć URL: {{url}}", @@ -752,10 +770,10 @@ "Features": "Funkcje", "Features Permissions": "Uprawnienia funkcji", "February": "Luty", + "Feedback": "", "Feedback deleted successfully": "Opinia usunięta pomyślnie", "Feedback Details": "Szczegóły opinii", "Feedback History": "Historia opinii", - "Feedbacks": "Opinie", "Feel free to add specific details": "Możesz dodać szczegóły", "Female": "Kobieta", "File": "Plik", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Wykryto spoofing (Fingerprint): Nie można użyć inicjałów jako awatara. Używam domyślnego obrazka.", "Firecrawl API Base URL": "Base URL Firecrawl API", "Firecrawl API Key": "Klucz API Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Pływające szybkie akcje", "Focus Chat Input": "Skupienie na polu czatu", "Folder": "Folder", "Folder Background Image": "Tło folderu", "Folder deleted successfully": "Folder usunięty pomyślnie", + "Folder Max File Count": "", "Folder Name": "Nazwa folderu", "Folder name cannot be empty.": "Nazwa folderu nie może być pusta.", "Folder name updated successfully": "Nazwa folderu zaktualizowana pomyślnie", @@ -826,7 +846,6 @@ "General": "Ogólne", "Generate": "Generuj", "Generate an image": "Wygeneruj obraz", - "Generate Image": "Generuj obraz", "Generate Message Pair": "Generuj parę wiadomości", "Generated Image": "Wygenerowany obraz", "Generating search query": "Generowanie zapytania wyszukiwania", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Rozpocznij z {{WEBUI_NAME}}", "Global": "Globalne", "Good Response": "Dobra odpowiedź", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Klucz API Google PSE", "Google PSE Engine Id": "ID silnika Google PSE", "Gravatar": "Gravatar", "Grid": "Siatka", + "Grokipedia": "", "Group": "Grupa", "Group Channel": "Kanał grupowy", "Group created successfully": "Grupa utworzona pomyślnie", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Generowanie promptu dla obrazu", "Image Prompt Generation Prompt": "Prompt generujący prompt dla obrazu", "Image Size": "Rozmiar obrazu", - "Images": "Obrazy", "Import": "Importuj", "Import Chats": "Importuj czaty", "Import Config from JSON File": "Importuj konfigurację z JSON", @@ -927,6 +947,7 @@ "Integration": "Integracja", "Integrations": "Integracje", "Interface": "Interfejs", + "Interface Settings Access": "", "Invalid file content": "Nieprawidłowa zawartość pliku", "Invalid file format.": "Nieprawidłowy format pliku.", "Invalid JSON file": "Nieprawidłowy plik JSON", @@ -940,6 +961,7 @@ "is typing...": "pisze...", "Italic": "Kursywa", "January": "Styczeń", + "Jina API Base URL": "", "Jina API Key": "Klucz API Jina", "join our Discord for help.": "dołącz do Discorda po pomoc.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Zostaw puste, aby dołączyć wszystkie modele z \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Zostaw puste, aby dołączyć wszystkie modele z \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Zostaw puste, aby uwzględnić wszystkie, lub wybierz konkretne", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Zostaw puste, aby użyć domyślnego modelu (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Zostaw puste dla domyślnego, lub wpisz własny", "Leave model field empty to use the default model.": "Zostaw puste, aby użyć modelu domyślnego.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Zarządzaj informacjami o koncie.", "March": "Marzec", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (Nagłówek)", + "Markdown Header Text Splitter": "", "Max Speakers": "Maks. mówców", "Max Upload Count": "Maks. liczba plików", "Max Upload Size": "Maks. rozmiar pliku", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maksymalnie 3 modele mogą być pobierane jednocześnie. Spróbuj później.", "May": "Maj", "MBR": "MBR", @@ -1042,6 +1067,7 @@ "Member removed successfully": "Członek usunięty pomyślnie", "Members": "Członkowie", "Members added successfully": "Członkowie dodani pomyślnie", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Wspomnienia dostępne dla LLM pojawią się tutaj.", "Memory": "Pamięć", "Memory added successfully": "Wspomnienie dodane pomyślnie", @@ -1051,6 +1077,7 @@ "Merge Responses": "Połącz odpowiedzi", "Merged Response": "Połączona odpowiedź", "Message": "Wiadomość", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Ocenianie wiadomości musi być włączone, aby użyć tej funkcji", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Wiadomości wysłane po utworzeniu linku nie będą udostępniane. Użytkownicy z linkiem zobaczą udostępniony czat.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Nazwa modelu", "Model name already exists, please choose a different one": "Nazwa modelu już istnieje, wybierz inną", "Model Name is required.": "Nazwa modelu jest wymagana.", + "Model names and usage frequency": "", "Model not selected": "Nie wybrano modelu", "Model Params": "Parametry modelu", "Model Permissions": "Uprawnienia modelu", + "Model responses or outputs": "", "Model unloaded successfully": "Model odładowany pomyślnie", "Model updated successfully": "Model zaktualizowany pomyślnie", "Model(s) do not support file upload": "Model(e) nie obsługują przesyłania plików", @@ -1096,6 +1125,7 @@ "Models imported successfully": "Modele zaimportowane pomyślnie", "Models Public Sharing": "Publiczne udostępnianie modeli", "Models Sharing": "Udostępnianie modeli", + "Mojeek": "", "Mojeek Search API Key": "Klucz API Mojeek Search", "More": "Więcej", "More Concise": "Bardziej zwięzły", @@ -1129,7 +1159,7 @@ "No conversation to save": "Brak rozmowy do zapisania", "No distance available": "Brak dostępnego dystansu", "No expiration can pose security risks.": "Brak wygaśnięcia może stanowić ryzyko bezpieczeństwa.", - "No feedbacks found": "Nie znaleziono opinii", + "No feedback found": "", "No file selected": "Nie wybrano pliku", "No files in this knowledge base.": "Brak plików w tej bazie wiedzy.", "No functions found": "Nie znaleziono funkcji", @@ -1144,6 +1174,7 @@ "No models selected": "Nie wybrano modeli", "No Notes": "Brak notatek", "No notes found": "Nie znaleziono notatek", + "No one": "", "No pinned messages": "Brak przypiętych wiadomości", "No prompts found": "Nie znaleziono promptów", "No results": "Brak wyników", @@ -1195,6 +1226,7 @@ "Only invited users can access": "Tylko zaproszeni użytkownic mają dostęp", "Only markdown files are allowed": "Tylko pliki markdown są dozwolone", "Only select users and groups with permission can access": "Tylko wybrani użytkownicy z uprawnieniami mają dostęp", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! URL wygląda na nieprawidłowy. Sprawdź i spróbuj ponownie.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ups! Pliki wciąż się przesyłają. Poczekaj na zakończenie.", "Oops! There was an error in the previous response.": "Ups! Wystąpił błąd w poprzedniej odpowiedzi.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI może używać narzędzi z dowolnego serwera OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI używa wewnętrznie faster-whisper.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI używa SpeechT5 i embeddingów CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Wersja Open WebUI (v{{OPEN_WEBUI_VERSION}}) jest niższa niż wymagana (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "strona", "Paginate": "Stronicowanie", "Parameters": "Parametry", + "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.": "", "Password": "Hasło", "Passwords do not match.": "Hasła nie pasują do siebie.", "Paste Large Text as File": "Wklej duży tekst jako plik", @@ -1260,7 +1295,6 @@ "Pipe": "Pipe", "Pipeline deleted successfully": "Pipeline usunięty pomyślnie", "Pipeline downloaded successfully": "Pipeline pobrany pomyślnie", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines to system wtyczek z wykonywaniem dowolnego kodu —", "Pipelines Not Detected": "Nie wykryto Pipeline'ów", "Pipelines Valves": "Pipelines Valves", @@ -1500,6 +1534,7 @@ "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.": "Ustawia sekwencje stop. Gdy wystąpią, LLM przerywa generowanie.", "Setting": "Ustawienie", "Settings": "Ustawienia", + "Settings Permissions": "", "Settings saved successfully!": "Ustawienia zapisane pomyślnie!", "Share": "Udostępnij", "Share Chat": "Udostępnij czat", @@ -1543,6 +1578,7 @@ "Speech recognition error: {{error}}": "Błąd rozpoznawania mowy: {{error}}", "Speech-to-Text": "Speech-to-Text", "Speech-to-Text Engine": "Silnik Speech-to-Text", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Rozpocznij nową rozmowę", "Start of the channel": "Początek kanału", "Start Tag": "Tag startowy", @@ -1553,6 +1589,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Kroki (Steps)", "Stop": "Przerwij", + "Stop Download": "", "Stop Generating": "Przerwij generowanie", "Stop Sequence": "Sekwencja stop", "Stream Chat Response": "Strumieniuj odpowiedź czatu", @@ -1573,7 +1610,14 @@ "Support": "Wsparcie", "Support this plugin:": "Wesprzyj ten plugin:", "Supported MIME Types": "Obsługiwane typy MIME", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Katalog synchronizacji", + "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", "System Instructions": "Instrukcje systemowe", "System Prompt": "Prompt systemowy", @@ -1618,6 +1662,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "Waga BM25 w wyszukiwaniu hybrydowym. 0 = semantyczne, 1 = leksykalne. Domyślnie 0.5", "The width in pixels to compress images to. Leave empty for no compression.": "Szerokość (px) do kompresji obrazów. Zostaw puste dla braku kompresji.", "Theme": "Motyw", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Myślę...", "This action cannot be undone. Do you wish to continue?": "Tej akcji nie można cofnąć. Kontynuować?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Ten kanał utworzono {{createdAt}}. To początek kanału {{channelName}}.", @@ -1732,6 +1777,7 @@ "Upload Pipeline": "Prześlij Pipeline", "Upload Progress": "Postęp przesyłania", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Postęp: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "Przesyłanie pliku...", "URL": "URL", "URL is required": "URL jest wymagany", @@ -1749,6 +1795,7 @@ "User Groups": "Grupy użytkowników", "User location successfully retrieved.": "Lokalizacja użytkownika pobrana pomyślnie.", "User menu": "Menu użytkownika", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooki użytkownika", "Username": "Nazwa użytkownika", "users": "użytkownicy", @@ -1798,15 +1845,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI będzie wysyłać żądania do \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Co chcesz osiągnąć?", "What are you working on?": "Nad czym pracujesz?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Co nowego w", "What's on your mind?": "O czym myślisz?", "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.": "Gdy włączone, model odpowiada w czasie rzeczywistym.", "wherever you are": "gdziekolwiek jesteś", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Czy stronicować wyjście. Domyślnie Fałsz.", "Whisper (Local)": "Whisper (Lokalny)", + "Who can share to this group": "", "Why?": "Dlaczego?", "Widescreen Mode": "Tryb szerokoekranowy", "Width": "Szerokość", + "Wikipedia": "", "Won": "Wygrano", "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.": "Działa razem z top-k. Wyższa wartość = większa różnorodność.", "Workspace": "Obszar roboczy", @@ -1818,6 +1869,8 @@ "Yacy Instance URL": "URL instancji Yacy", "Yacy Password": "Hasło Yacy", "Yacy Username": "Nazwa użytkownika Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Wczoraj", "Yesterday at {{LOCALIZED_TIME}}": "Wczoraj o {{LOCALIZED_TIME}}", "You": "Ty", @@ -1825,6 +1878,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Możesz rozmawiać z maksymalnie {{maxCount}} plikami naraz.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Możesz personalizować interakcje dodając wspomnienia przyciskiem 'Zarządzaj'.", "You cannot upload an empty file.": "Nie możesz przesłać pustego pliku.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "Nie masz uprawnień do wysyłania wiadomości w tym kanale.", "You do not have permission to send messages in this thread.": "Nie masz uprawnień do wysyłania wiadomości w tym wątku.", "You do not have permission to upload files to this knowledge base.": "Nie masz uprawnień do przesyłania plików do tej bazy wiedzy.", @@ -1836,6 +1892,8 @@ "Your Account": "Twoje konto", "Your account status is currently pending activation.": "Twoje konto oczekuje na aktywację.", "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.": "Cała wpłata trafia do twórcy pluginu; Open WebUI nie pobiera prowizji.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "Język YouTube", "Youtube Proxy URL": "URL Proxy YouTube" diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index 8d98876535..f509e38bec 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ajustar essas configurações aplicará mudanças para todos os usuários.", "admin": "admin", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Painel do Admin", "Admin Settings": "Configurações do Admin", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Os administradores têm acesso a todas as ferramentas o tempo todo; os usuários precisam de ferramentas atribuídas, por modelo, no workspace.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Permitir Resposta Contínua", "Allow Delete Messages": "Permitir Exclusão de Mensagens", "Allow File Upload": "Permitir Envio de arquivos", - "Allow Group Sharing": "Permitir compartilhamento em grupo", "Allow Multiple Models in Chat": "Permitir Vários Modelos no Chat", "Allow non-local voices": "Permitir vozes não locais", "Allow Rate Response": "Permitir Avaliar Resposta", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "e mais {{COUNT}}", "and create a new shared link.": "e criar um novo link compartilhado.", "Android": "Android", + "Anyone": "", "API Base URL": "URL Base da API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "URL base da API para o serviço Datalab Marker. O padrão é: https://www.datalab.to/api/v1/marker", "API Key": "Chave API", @@ -175,6 +176,7 @@ "Authenticate": "Autenticar", "Authentication": "Autenticação", "Auto": "Auto", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Cópia Automática da Resposta para a Área de Transferência", "Auto-playback response": "Resposta de reprodução automática", "Autocomplete Generation": "Geração de preenchimento automático", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "String de Autenticação da API AUTOMATIC1111", "AUTOMATIC1111 Base URL": "URL Base AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "URL Base AUTOMATIC1111 é necessária.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Lista disponível", "Available Tools": "Ferramentas disponíveis", "available users": "usuários disponíveis", @@ -201,6 +204,7 @@ "before": "antes", "Being lazy": "Sendo preguiçoso", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Endpoint do Bing Search V7", "Bing Search V7 Subscription Key": "Chave de assinatura do Bing Search V7", "Bio": "Sobre você", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Chave da API de pesquisa Bocha", "Bold": "Negrito", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Aumentar ou penalizar tokens específicos para respostas restritas. Os valores de viés serão fixados entre -100 e 100 (inclusive). (Padrão: nenhum)", + "Brave": "", "Brave Search API Key": "Chave API do Brave Search", + "Builtin Tools": "", "Bullet List": "Lista com marcadores", "Button ID": "ID do botão", "Button Label": "Rótulo do botão", @@ -256,8 +262,10 @@ "Check for updates": "Verificar atualizações", "Checking for updates...": "Verificando atualizações...", "Choose a model before saving...": "Escolha um modelo antes de salvar...", + "Chunk Min Size Target": "", "Chunk Overlap": "Sobreposição de Chunk", "Chunk Size": "Tamanho do Chunk", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Cifras", "Citation": "Citação", "Citations": "Citações", @@ -293,7 +301,6 @@ "Code Block": "Bloco de código", "Code Editor": "Editor de código", "Code execution": "Execução de código", - "Code Execution": "Execução de código", "Code Execution Engine": "Mecanismo de execução de código", "Code Execution Timeout": "Tempo limite de execução do código", "Code formatted successfully": "Código formatado com sucesso", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contate o Administrador para verificar seu acesso", "Content": "Conteúdo", "Content Extraction Engine": "Mecanismo de Extração de Conteúdo", + "Content lengths (character counts only)": "", "Continue Response": "Continuar Resposta", "Continue with {{provider}}": "Continuar com {{provider}}", "Continue with Email": "Continuar com Email", @@ -393,6 +401,7 @@ "Database": "Banco de Dados", "Datalab Marker API": "API do Marcador do Datalab", "DD/MM/YYYY": "DD/MM/AAAA", + "DDGS Backend": "", "December": "Dezembro", "Decrease UI Scale": "Diminuir a escala da interface do usuário", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Explorar base de conhecimento", "Do not install functions from sources you do not fully trust.": "Não instale funções de origens nas quais você não confia totalmente.", "Do not install tools from sources you do not fully trust.": "Não instale ferramentas de origens nas quais você não confia totalmente.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "Parâmetros Docling", "Docling Server URL required.": "URL do servidor Docling necessária.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "É necessário o endpoint do Document Intelligence.", "Document Intelligence Model": "Modelo de Inteligência de Documentos", "Documentation": "Documentação", - "Documents": "Documentos", "does not make any external connections, and your data stays securely on your locally hosted server.": "não faz nenhuma conexão externa, e seus dados permanecem seguros no seu servidor local.", "Domain Filter List": "Lista de filtros de domínio", "don't fetch random pipelines from sources you don't trust.": "Não busque pipelines aleatórios de fontes não confiáveis.", @@ -493,11 +502,14 @@ "Done": "Concluído", "Download": "Baixar", "Download & Delete": "Baixar e excluir", + "Download as JSON": "", "Download as SVG": "Baixar como SVG", "Download canceled": "Download cancelado", "Download Database": "Download do Banco de Dados", + "Downloading stats...": "", "Draw": "Empate", "Drop any files here to upload": "Solte qualquer arquivo aqui para fazer upload", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "por exemplo, '30s', '10m'. Unidades de tempo válidas são 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "por exemplo, \"json\" ou um esquema JSON", "e.g. 60": "por exemplo, 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Insira a chave da API de pesquisa do Bocha", "Enter Brave Search API Key": "Insira a chave da API de pesquisa do Brave", "Enter certificate path": "Digite o caminho do certificado", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Digite a Sobreposição de Chunk", "Enter Chunk Size": "Digite o Tamanho do Chunk", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Insira pares \"token:bias_value\" separados por vírgulas (exemplo: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Insira a URL de pesquisa na Web externa", "Enter Firecrawl API Base URL": "Insira a URL base da API do Firecrawl", "Enter Firecrawl API Key": "Insira a chave da API do Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Digite o nome da pasta", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Digite a URL bruta do Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Digite a cor hexadecimal (por exemplo, #FF0000)", "Enter ID": "Digite o ID", "Enter Image Size (e.g. 512x512)": "Digite o Tamanho da Imagem (por exemplo, 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Digite a Chave API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Insira a configuração JSON (por exemplo, {\"disable_links\": true})", "Enter Jupyter Password": "Digite a senha do Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Insira a chave da API de pesquisa do Kagi", "Enter Key Behavior": "Comportamento da tecla Enter", "Enter language codes": "Digite os códigos de idioma", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "Insira a URL base da API Mistral", "Enter Mistral API Key": "Insira a chave da API Mistral", "Enter Model ID": "Digite o ID do modelo", @@ -736,6 +753,7 @@ "Failed to generate title": "Falha ao gerar título", "Failed to import models": "Falha ao importar modelos", "Failed to load chat preview": "Falha ao carregar a pré-visualização do chat", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Falha ao carregar o conteúdo do arquivo.", "Failed to move chat": "Falha ao mover o chat", "Failed to process URL: {{url}}": "Falha ao processar URL: {{url}}", @@ -752,10 +770,10 @@ "Features": "Funcionalidades", "Features Permissions": "Permissões das Funcionalidades", "February": "Fevereiro", + "Feedback": "", "Feedback deleted successfully": "O feedback foi excluído com sucesso.", "Feedback Details": "Detalhes do comentário", "Feedback History": "Histórico de comentários", - "Feedbacks": "Comentários", "Feel free to add specific details": "Sinta-se à vontade para adicionar detalhes específicos", "Female": "Feminino", "File": "Arquivo", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Falsificação de impressão digital detectada: Não foi possível usar as iniciais como avatar. Usando a imagem de perfil padrão.", "Firecrawl API Base URL": "URL base da API do Firecrawl", "Firecrawl API Key": "Chave de API do Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Ações rápidas flutuantes", "Focus Chat Input": "Foco na janela do Chat", "Folder": "Pasta", "Folder Background Image": "Imagem de fundo da pasta", "Folder deleted successfully": "Pasta excluída com sucesso", + "Folder Max File Count": "", "Folder Name": "Nome da Pasta", "Folder name cannot be empty.": "Nome da pasta não pode estar vazio.", "Folder name updated successfully": "Nome da pasta atualizado com sucesso", @@ -826,7 +846,6 @@ "General": "Geral", "Generate": "Gerar", "Generate an image": "Gerar uma imagem", - "Generate Image": "Gerar Imagem", "Generate Message Pair": "Gerar par de mensagens", "Generated Image": "Imagem gerada", "Generating search query": "Gerando consulta de pesquisa", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Iniciar com {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Boa Resposta", + "Google": "", "Google Drive": "", "Google PSE API Key": "Chave API do Google PSE", "Google PSE Engine Id": "ID do Motor do Google PSE", "Gravatar": "", "Grid": "Grade", + "Grokipedia": "", "Group": "Grupo", "Group Channel": "Canal do grupo", "Group created successfully": "Grupo criado com sucesso", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Geração de prompt de imagem", "Image Prompt Generation Prompt": "Prompt de geração de prompt de imagem", "Image Size": "Tamanho da imagem", - "Images": "Imagens", "Import": "Importar", "Import Chats": "Importar Chats", "Import Config from JSON File": "Importar Configurações de JSON", @@ -927,6 +947,7 @@ "Integration": "Integração", "Integrations": "Integrações", "Interface": "Interface", + "Interface Settings Access": "", "Invalid file content": "Conteúdo de arquivo inválido", "Invalid file format.": "Formato de arquivo inválido.", "Invalid JSON file": "Arquivo JSON inválido", @@ -940,6 +961,7 @@ "is typing...": "está digitando...", "Italic": "Itálico", "January": "Janeiro", + "Jina API Base URL": "", "Jina API Key": "Chave de API Jina", "join our Discord for help.": "junte-se ao nosso Discord para ajudar.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Deixe em branco para incluir todos os modelos do ponto final \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Deixe em branco para incluir todos os modelos do ponto final \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Deixe vazio para incluir todos os modelos ou selecione modelos especificos", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "Deixe em branco para usar o modelo padrão (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Deixe vazio para usar o prompt padrão, ou insira um prompt personalizado", "Leave model field empty to use the default model.": "Deixe o campo do modelo vazio para usar o modelo padrão.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Gerencie as informações da sua conta.", "March": "Março", "Markdown": "", - "Markdown (Header)": "Markdown (Cabeçalho)", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Quantidade máxima de anexos", "Max Upload Size": "Tamanho máximo do arquivo", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Máximo de 3 modelos podem ser baixados simultaneamente. Por favor, tente novamente mais tarde.", "May": "Maio", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "Membro removido com sucesso", "Members": "Membros", "Members added successfully": "Membros adicionados com sucesso", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Memórias acessíveis por LLMs serão mostradas aqui.", "Memory": "Memória", "Memory added successfully": "Memória adicionada com sucesso", @@ -1051,6 +1077,7 @@ "Merge Responses": "Mesclar respostas", "Merged Response": "Resposta Mesclada", "Message": "Mensagem", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Mensagem de avaliação deve estar habilitada para usar esta função", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Mensagens enviadas após criar seu link não serão compartilhadas. Usuários com o URL poderão visualizar o chat compartilhado.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Nome do Modelo", "Model name already exists, please choose a different one": "O nome do modelo já existe, escolha um diferente", "Model Name is required.": "O nome do modelo é obrigatório.", + "Model names and usage frequency": "", "Model not selected": "Modelo não selecionado", "Model Params": "Parâmetros do Modelo", "Model Permissions": "Permissões do Modelo", + "Model responses or outputs": "", "Model unloaded successfully": "Modelo descarregado com sucesso", "Model updated successfully": "Modelo atualizado com sucesso", "Model(s) do not support file upload": "Modelo(s) não suportam upload de arquivo", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Compartilhamento Público de Modelos", "Models Sharing": "Compartilhamento de Modelos", + "Mojeek": "", "Mojeek Search API Key": "Chave de API Mojeel Search", "More": "Mais", "More Concise": "Mais conciso", @@ -1129,7 +1159,7 @@ "No conversation to save": "Nenhuma conversa para salvar", "No distance available": "Sem distância disponível", "No expiration can pose security risks.": "Nenhuma expiração pode representar riscos de segurança.", - "No feedbacks found": "Comentários não encontrados", + "No feedback found": "", "No file selected": "Nenhum arquivo selecionado", "No files in this knowledge base.": "Não existem arquivos nesta base de conhecimento.", "No functions found": "Nenhuma função encontrada", @@ -1144,6 +1174,7 @@ "No models selected": "Nenhum modelo selecionado", "No Notes": "Sem Notas", "No notes found": "Notas não encontradas", + "No one": "", "No pinned messages": "Nenhuma mensagem fixada", "No prompts found": "Nenhum prompt encontrado", "No results": "Nenhum resultado encontrado", @@ -1195,6 +1226,7 @@ "Only invited users can access": "Somente usuários convidados podem acessar.", "Only markdown files are allowed": "Somente arquivos markdown são permitidos", "Only select users and groups with permission can access": "Somente usuários e grupos selecionados com permissão podem acessar.", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ops! Parece que a URL é inválida. Por favor, verifique novamente e tente de novo.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ops! Existem arquivos a serem carregados. Por favor, aguarde que o carregamento tenha concluído.", "Oops! There was an error in the previous response.": "Ops! Houve um erro na resposta anterior.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "O Open WebUI pode usar ferramentas fornecidas por qualquer servidor OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI usa faster-whisper internamente.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "A Open WebUI usa os embeddings de voz do SpeechT5 e do CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "A versão do Open WebUI (v{{OPEN_WEBUI_VERSION}}) é inferior à versão necessária (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "página", "Paginate": "Paginar", "Parameters": "Parâmetros", + "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.": "", "Password": "Senha", "Passwords do not match.": "As senhas não coincidem.", "Paste Large Text as File": "Cole Textos Longos como Arquivo", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline excluído com sucesso", "Pipeline downloaded successfully": "Pipeline baixado com sucesso", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines é um sistema de plugins com execução arbitrária de código —", "Pipelines Not Detected": "Pipelines Não Detectados", "Pipelines Valves": "Configurações de Pipelines", @@ -1499,6 +1533,7 @@ "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.": "Define as sequências de parada a serem usadas. Quando esse padrão for encontrado, o modelo de linguagem (LLM) parará de gerar texto e retornará. Vários padrões de parada podem ser definidos especificando parâmetros de parada separados em um arquivo de modelo.", "Setting": "Configuração", "Settings": "Configurações", + "Settings Permissions": "", "Settings saved successfully!": "Configurações salvas com sucesso!", "Share": "Compartilhar", "Share Chat": "Compartilhar Chat", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Erro de reconhecimento de fala: {{error}}", "Speech-to-Text": "Fala-para-Texto", "Speech-to-Text Engine": "Motor de Transcrição de Fala", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Iniciar uma nova conversa", "Start of the channel": "Início do canal", "Start Tag": "Tag inicial", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Passos", "Stop": "Parar", + "Stop Download": "", "Stop Generating": "Pare de gerar", "Stop Sequence": "Sequência de Parada", "Stream Chat Response": "Stream Resposta do Chat", @@ -1572,7 +1609,14 @@ "Support": "Suporte", "Support this plugin:": "Apoie este plugin:", "Supported MIME Types": "Tipos MIME suportados", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sincronizar Diretório", + "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": "Sistema", "System Instructions": "Instruções do sistema", "System Prompt": "Prompt do Sistema", @@ -1617,6 +1661,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "O Peso da Busca Híbrida BM25. 0 a mais semântico, 1 a mais lexical. Padrão 0,5", "The width in pixels to compress images to. Leave empty for no compression.": "A largura em pixels para compactar as imagens. Deixe em branco para não compactar.", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Pensando...", "This action cannot be undone. Do you wish to continue?": "Esta ação não pode ser desfeita. Você deseja continuar?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Este canal foi criado em {{createdAt}}. Este é o início do canal {{channelName}}.", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Fazer upload de Pipeline", "Upload Progress": "Progresso do Upload", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Progresso do upload: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "Enviando arquivo...", "URL": "", "URL is required": "URL é obrigratória", @@ -1748,6 +1794,7 @@ "User Groups": "Grupos de usuários", "User location successfully retrieved.": "Localização do usuário recuperada com sucesso.", "User menu": "Menu do usuário", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooks do usuário", "Username": "Nome do Usuário", "users": "usuários", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "A WebUI fará requisições para \"{{url}}/chat/completions\".", "What are you trying to achieve?": "O que está tentando alcançar?", "What are you working on?": "No que está trabalhando?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "O que há de novo em", "What's on your mind?": "O que você têm em mente?", "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.", "Whisper (Local)": "Whisper (Local)", + "Who can share to this group": "", "Why?": "Por que?", "Widescreen Mode": "Modo Tela Cheia", "Width": "Largura", + "Wikipedia": "", "Won": "Ganhou", "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.": "Funciona em conjunto com o top-k. Um valor mais alto (por exemplo, 0,95) resultará em um texto mais diverso, enquanto um valor mais baixo (por exemplo, 0,5) gerará um texto mais focado e conservador.", "Workspace": "Espaço de Trabalho", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Ontem", "Yesterday at {{LOCALIZED_TIME}}": "Ontem às {{LOCALIZED_TIME}}", "You": "Você", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Você só pode conversar com no máximo {{maxCount}} arquivo(s) de cada vez.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Você pode personalizar suas interações com LLMs adicionando memórias através do botão 'Gerenciar' abaixo, tornando-as mais úteis e adaptadas a você.", "You cannot upload an empty file.": "Você não pode carregar um arquivo vazio.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "Você não tem permissão para enviar mensagens neste canal.", "You do not have permission to send messages in this thread.": "Você não tem permissão para enviar mensagens neste tópico.", "You do not have permission to upload files to this knowledge base.": "Você não tem permissão para enviar arquivos para esta base de conhecimento.", @@ -1835,6 +1891,8 @@ "Your Account": "Sua conta", "Your account status is currently pending activation.": "O status da sua conta está atualmente aguardando ativação.", "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.": "Toda a sua contribuição irá diretamente para o desenvolvedor do plugin; o Open WebUI não retém nenhuma porcentagem. No entanto, a plataforma de financiamento escolhida pode ter suas próprias taxas.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index d450b5da65..947c47f4b2 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ajustar essas configurações aplicará alterações universalmente a todos os utilizadores.", "admin": "administrador", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Painel do Administrador", "Admin Settings": "Configurações do Administrador", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Permitir vozes não locais", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "e criar um novo link partilhado.", "Android": "", + "Anyone": "", "API Base URL": "URL Base da API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Chave da API", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Cópia Automática da Resposta para a Área de Transferência", "Auto-playback response": "Reprodução automática da resposta", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "URL Base do AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "O URL Base do AUTOMATIC1111 é obrigatório.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "utilizadores disponíveis", @@ -201,6 +204,7 @@ "before": "antes", "Being lazy": "Ser preguiçoso", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Chave da API de Pesquisa Brave", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Verificar atualizações", "Checking for updates...": "Verificando atualizações...", "Choose a model before saving...": "Escolha um modelo antes de guardar...", + "Chunk Min Size Target": "", "Chunk Overlap": "Sobreposição de Fragmento", "Chunk Size": "Tamanho do Fragmento", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Citação", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contatar Admin para acesso ao WebUI", "Content": "Conteúdo", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Continuar resposta", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Base de dados", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Dezembro", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Documentação", - "Documents": "Documentos", "does not make any external connections, and your data stays securely on your locally hosted server.": "não faz conexões externas e os seus dados permanecem seguros no seu servidor alojado localmente.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Não obtenha pipelines aleatórias de fontes não confiáveis.", @@ -493,11 +502,14 @@ "Done": "", "Download": "Descarregar", "Download & Delete": "Transferir e eliminar", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Download cancelado", "Download Database": "Descarregar Base de Dados", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "por exemplo, '30s', '10m'. Unidades de tempo válidas são 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Escreva a chave da API do Brave Search", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Escreva a Sobreposição de Fragmento", "Enter Chunk Size": "Escreva o Tamanho do Fragmento", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Escreva o URL cru do Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Escreva o Tamanho da Imagem (por exemplo, 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Escreva os códigos de idioma", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Fevereiro", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "Sinta-se à vontade para adicionar detalhes específicos", "Female": "", "File": "", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Detectada falsificação da impressão digital: Não é possível usar iniciais como avatar. A usar a imagem de perfil padrão.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Geral", "Generate": "", "Generate an image": "", - "Generate Image": "Gerar imagem", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "A gerar a consulta da pesquisa", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "Boa Resposta", + "Google": "", "Google Drive": "", "Google PSE API Key": "Chave da API PSE do Google", "Google PSE Engine Id": "ID do mecanismo PSE do Google", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grupo", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Imagens", "Import": "", "Import Chats": "Importar Conversas", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Interface", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Janeiro", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "junte-se ao nosso Discord para obter ajuda.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Março", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "O máximo de 3 modelos podem ser descarregados simultaneamente. Tente novamente mais tarde.", "May": "Maio", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Memórias acessíveis por LLMs serão mostradas aqui.", "Memory": "Memória", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Resposta Fundida", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Mensagens que você enviar após criar o seu link não serão partilhadas. Os utilizadores com o URL poderão visualizar a conversa partilhada.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Modelo não selecionado", "Model Params": "Params Modelo", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Mais", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Não foram encontrados resultados", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Epá! Parece que o URL é inválido. Verifique novamente e tente outra vez.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "", "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.": "", "Password": "Senha", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "Condutas", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines é um sistema de plugins com execução arbitrária de código —", "Pipelines Not Detected": "", "Pipelines Valves": "Válvulas de Condutas", @@ -1499,6 +1533,7 @@ "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.": "", "Setting": "", "Settings": "Configurações", + "Settings Permissions": "", "Settings saved successfully!": "Configurações guardadas com sucesso!", "Share": "Partilhar", "Share Chat": "Partilhar Conversa", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Erro de reconhecimento de fala: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Motor de Fala para Texto", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Início do canal", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Sequência de Paragem", "Stream Chat Response": "", @@ -1572,7 +1609,14 @@ "Support": "", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "Sistema", "System Instructions": "", "System Prompt": "Prompt do Sistema", @@ -1617,6 +1661,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "A pensar...", "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.": "", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Carregar Pipeline", "Upload Progress": "Progresso do Carregamento", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "O que há de novo em", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (Local)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "Modo Widescreen", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "Espaço de Trabalho", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Ontem", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Você", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Você pode personalizar as suas interações com LLMs adicionando memórias através do botão 'Gerir' abaixo, tornando-as mais úteis e personalizadas para você.", "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 save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "O status da sua conta está atualmente com a ativação pendente.", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/ro-RO/translation.json b/src/lib/i18n/locales/ro-RO/translation.json index 54774bb451..8b5e0efa99 100644 --- a/src/lib/i18n/locales/ro-RO/translation.json +++ b/src/lib/i18n/locales/ro-RO/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ajustarea acestor setări va aplica modificările universal pentru toți utilizatorii.", "admin": "administrator", "Admin": "Administrator", + "Admin Contact Email": "", "Admin Panel": "Panoul de administrare", "Admin Settings": "Setări pentru administrator", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratorii au acces la toate instrumentele în orice moment; utilizatorii au nevoie de instrumente asignate pe model în spațiul de lucru.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Permite încărcarea fișierelor", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Permite modele multiple în chat", "Allow non-local voices": "Permite voci non-locale", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "și {{COUNT}} mai multe", "and create a new shared link.": "și creează un nou link partajat.", "Android": "Android", + "Anyone": "", "API Base URL": "URL Bază API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Cheie API", @@ -175,6 +176,7 @@ "Authenticate": "Autentifică", "Authentication": "Autentificare", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Copiere Automată a Răspunsului în Clipboard", "Auto-playback response": "Redare automată a răspunsului", "Autocomplete Generation": "Generare automată a completării", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Șir de Autentificare API AUTOMATIC1111", "AUTOMATIC1111 Base URL": "URL Bază AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Este necesar URL-ul Bază AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Listă disponibilă", "Available Tools": "Instrumente disponibile", "available users": "utilizatori disponibili", @@ -201,6 +204,7 @@ "before": "înainte", "Being lazy": "Fiind leneș", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Cheie API Brave Search", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Verifică actualizări", "Checking for updates...": "Se verifică actualizările...", "Choose a model before saving...": "Alege un model înainte de a salva...", + "Chunk Min Size Target": "", "Chunk Overlap": "Suprapunere Bloc", "Chunk Size": "Dimensiune Bloc", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Cifruri", "Citation": "Citație", "Citations": "Citații", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Executarea codului", - "Code Execution": "", "Code Execution Engine": "Motor de executare cod", "Code Execution Timeout": "Timp limită pentru executarea codului", "Code formatted successfully": "Cod formatat cu succes", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Contactează administratorul pentru acces WebUI", "Content": "Conținut", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Continuă Răspunsul", "Continue with {{provider}}": "Continuă cu {{provider}}", "Continue with Email": "Continuă cu email", @@ -393,6 +401,7 @@ "Database": "Bază de Date", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Decembrie", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "", "Do not install functions from sources you do not fully trust.": "Nu instalați funcții din surse în care nu aveți încredere completă.", "Do not install tools from sources you do not fully trust.": "Nu instalați instrumente din surse în care nu aveți încredere completă.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Documentație", - "Documents": "Documente", "does not make any external connections, and your data stays securely on your locally hosted server.": "nu face nicio conexiune externă, iar datele tale rămân în siguranță pe serverul găzduit local.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Nu prelua pipelines aleatoare din surse în care nu ai încredere.", @@ -493,11 +502,14 @@ "Done": "Gata", "Download": "Descarcă", "Download & Delete": "Descărcare și ștergere", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Descărcare anulată", "Download Database": "Descarcă Baza de Date", + "Downloading stats...": "", "Draw": "Desenează", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "de ex. '30s', '10m'. Unitățile de timp valide sunt 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Introduceți Cheia API Brave Search", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Introduceți Suprapunerea Blocului", "Enter Chunk Size": "Introduceți Dimensiunea Blocului", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Introduceți URL-ul Raw de pe Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Introduceți Dimensiunea Imaginii (de ex. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Introduceți codurile limbilor", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Introdu codul modelului", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Februarie", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Istoricul feedback-ului", - "Feedbacks": "", "Feel free to add specific details": "Adăugați detalii specifice fără nicio ezitare", "Female": "", "File": "Fișier", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Detectată falsificarea amprentelor: Nu se pot folosi inițialele ca avatar. Se utilizează imaginea de profil implicită.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Folder șters cu succes", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Numele folderului nu poate fi gol.", "Folder name updated successfully": "Numele folderului a fost actualizat cu succes", @@ -826,7 +846,6 @@ "General": "General", "Generate": "", "Generate an image": "", - "Generate Image": "Generează Imagine", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Se generează interogarea de căutare", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "Global", "Good Response": "Răspuns Bun", + "Google": "", "Google Drive": "", "Google PSE API Key": "Cheie API Google PSE", "Google PSE Engine Id": "ID Motor Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grup", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Imagini", "Import": "", "Import Chats": "Importă Conversațiile", "Import Config from JSON File": "Importarea configurației dintr-un fișier JSON", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Interfață", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Format de fișier invalid.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Ianuarie", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "alătură-te Discord-ului nostru pentru ajutor.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "Lăsați gol pentru a include toate modelele sau selectați modele specifice", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Lăsați gol pentru a utiliza promptul implicit sau introduceți un prompt personalizat", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Martie", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Număr maxim de încărcări", "Max Upload Size": "Dimensiune Maximă de Încărcare", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maxim 3 modele pot fi descărcate simultan. Vă rugăm să încercați din nou mai târziu.", "May": "Mai", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Memoriile accesibile de LLM-uri vor fi afișate aici.", "Memory": "Memorie", "Memory added successfully": "Memoria a fost adăugată cu succes", @@ -1051,6 +1077,7 @@ "Merge Responses": "Combină răspunsurile", "Merged Response": "Răspuns Combinat", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Evaluarea mesajelor ar trebui să fie activată pentru a utiliza această funcționalitate.", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Mesajele pe care le trimiteți după crearea link-ului dvs. nu vor fi partajate. Utilizatorii cu URL-ul vor putea vizualiza conversația partajată.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Nume model", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Modelul nu a fost selectat", "Model Params": "Parametri Model", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Modelul a fost actualizat cu succes", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Mai multe", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Nicio distanță disponibilă", "No expiration can pose security risks.": "", - "No feedbacks found": "Niciun feedback găsit", + "No feedback found": "", "No file selected": "Nu a fost selectat niciun fișier", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Nu au fost găsite rezultate", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Oops! Se pare că URL-ul este invalid. Vă rugăm să verificați din nou și să încercați din nou.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ups! Încă mai există fișiere care se încarcă. Vă rugăm să așteptați până se finalizează încărcarea.", "Oops! There was an error in the previous response.": "Ups! A apărut o eroare în răspunsul anterior.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI folosește faster-whisper intern.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Versiunea Open WebUI (v{{OPEN_WEBUI_VERSION}}) este mai mică decât versiunea necesară (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "pagina", "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.": "", "Password": "Parolă", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Conducta a fost ștearsă cu succes", "Pipeline downloaded successfully": "Conducta a fost descărcată cu succes", - "Pipelines": "Conducte", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines este un sistem de pluginuri cu execuție arbitrară de cod —", "Pipelines Not Detected": "Conducte Nedetectate", "Pipelines Valves": "Valvele Conductelor", @@ -1499,6 +1533,7 @@ "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.": "", "Setting": "", "Settings": "Setări", + "Settings Permissions": "", "Settings saved successfully!": "Setările au fost salvate cu succes!", "Share": "Partajează", "Share Chat": "Partajează Conversația", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Eroare de recunoaștere vocală: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Motor de Conversie a Vocii în Text", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Începutul canalului", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Oprire", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Oprește Secvența", "Stream Chat Response": "Răspuns Stream Chat", @@ -1572,7 +1609,14 @@ "Support": "Suport", "Support this plugin:": "Susține acest plugin:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sincronizează directorul", + "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": "Sistem", "System Instructions": "Instrucțiuni pentru sistem", "System Prompt": "Prompt de Sistem", @@ -1617,6 +1661,7 @@ "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.": "", "Theme": "Temă", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Gândește...", "This action cannot be undone. Do you wish to continue?": "Această acțiune nu poate fi anulată. Doriți să continuați?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Încarcă Conducta", "Upload Progress": "Progres Încărcare", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "Localizarea utilizatorului a fost preluată cu succes.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Ce e Nou în", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (Local)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "Mod Ecran Larg", "Width": "", + "Wikipedia": "", "Won": "Câștigat", "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.": "", "Workspace": "Spațiu de Lucru", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Ieri", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Tu", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Puteți discuta cu un număr maxim de {{maxCount}} fișier(e) simultan.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Puteți personaliza interacțiunile dvs. cu LLM-urile adăugând amintiri prin butonul 'Gestionează' de mai jos, făcându-le mai utile și adaptate la dvs.", "You cannot upload an empty file.": "Nu poți încărca un fișier gol.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Statusul contului dvs. este în așteptare pentru activare.", "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.": "Întreaga dvs. contribuție va merge direct la dezvoltatorul plugin-ului; Open WebUI nu ia niciun procent. Cu toate acestea, platforma de finanțare aleasă ar putea avea propriile taxe.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index b54b582e2f..4bc36df2b9 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Изменения в этих настройках будут применены для всех пользователей.", "admin": "админ", "Admin": "Админ", + "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.": "Администраторы всегда имеют доступ ко всем инструментам; пользователям нужны инструменты, назначенные для каждой модели в рабочем пространстве.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Разрешить продолжение ответа", "Allow Delete Messages": "Разрешить удаление сообщений", "Allow File Upload": "Разрешить загрузку файлов", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Разрешить использование нескольких моделей в чате", "Allow non-local voices": "Разрешить не локальные голоса", "Allow Rate Response": "Разрешить оценку ответа", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "и еще {{COUNT}}", "and create a new shared link.": "и создайте новую общую ссылку.", "Android": "Android", + "Anyone": "", "API Base URL": "Базовый адрес API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "Базовый URL API для сервиса Datalab Marker. По умолчанию: https://www.datalab.to/api/v1/marker", "API Key": "Ключ API", @@ -175,6 +176,7 @@ "Authenticate": "Аутентификация", "Authentication": "Аутентификация", "Auto": "Автоматически", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Автоматическое копирование ответа в буфер обмена", "Auto-playback response": "Автоматическое воспроизведение ответа", "Autocomplete Generation": "Генерация автозаполнения", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "строка авторизации API AUTOMATIC1111", "AUTOMATIC1111 Base URL": "Базовый URL адрес AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Необходим базовый адрес URL AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Список доступных", "Available Tools": "Доступные инструменты", "available users": "доступные пользователи", @@ -201,6 +204,7 @@ "before": "до", "Being lazy": "Лениво", "Beta": "Бета", + "Bing": "", "Bing Search V7 Endpoint": "Энд-поинт поиска Bing V7", "Bing Search V7 Subscription Key": "Ключ API Bing Search V7", "Bio": "О себе", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Ключ API поиска Bocha", "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 Search API Key": "Ключ API поиска Brave", + "Builtin Tools": "", "Bullet List": "Маркированный список", "Button ID": "ID кнопки", "Button Label": "Подпись кнопки", @@ -256,8 +262,10 @@ "Check for updates": "Проверить обновления", "Checking for updates...": "Проверка обновлений...", "Choose a model before saving...": "Выберите модель перед сохранением...", + "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.": "", "Ciphers": "Шифры", "Citation": "Цитирование", "Citations": "Цитаты", @@ -293,7 +301,6 @@ "Code Block": "Блок кода", "Code Editor": "", "Code execution": "Исполнение кода", - "Code Execution": "Исполнение кода", "Code Execution Engine": "Механизм исполнения кода", "Code Execution Timeout": "Время ожидания исполнения кода", "Code formatted successfully": "Код успешно отформатирован", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Обратитесь к администратору для получения доступа к WebUI", "Content": "Содержание", "Content Extraction Engine": "Механизм извлечения контента", + "Content lengths (character counts only)": "", "Continue Response": "Продолжить ответ", "Continue with {{provider}}": "Продолжить с {{provider}}", "Continue with Email": "Продолжить с Email", @@ -393,6 +401,7 @@ "Database": "База данных", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "ДД/ММ/ГГГГ", + "DDGS Backend": "", "December": "Декабрь", "Decrease UI Scale": "", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "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", "Docling Parameters": "", "Docling Server URL required.": "Необходим URL сервера Docling", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "Требуется конечная точка Document Intelligence.", "Document Intelligence Model": "", "Documentation": "Документация", - "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.": "Не получайте случайные pipelines из источников, которым вы не доверяете.", @@ -493,11 +502,14 @@ "Done": "Готово", "Download": "Загрузить", "Download & Delete": "Скачать и удалить", + "Download as JSON": "", "Download as SVG": "Загрузить как SVG", "Download canceled": "Загрузка отменена", "Download Database": "Загрузить базу данных", + "Downloading stats...": "", "Draw": "Рисовать", "Drop any files here to upload": "Переместите сюда любые файлы для загрузки", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "например, '30s','10m'. Допустимые единицы времени: 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "например, \"json\" или схему JSON", "e.g. 60": "например, 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Введите APi ключ поиска Bocha", "Enter Brave Search API Key": "Введите ключ API поиска Brave", "Enter certificate path": "Введите путь к сертификату", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Введите перекрытие фрагмента", "Enter Chunk Size": "Введите размер фрагмента", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Введите пары \"token:bias_value\", разделенные запятыми (пример: 5432:100, 413:-100).", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Введите URL-адрес внешнего веб-поиска", "Enter Firecrawl API Base URL": "Введите базовый URL-адрес Firecrawl API", "Enter Firecrawl API Key": "Введите ключ API для Firecrawl", + "Enter Firecrawl Timeout": "", "Enter folder name": "Введите имя папки", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Введите необработанный URL-адрес Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Введите hex-цвет (напр. #FF0000)", "Enter ID": "Введите ID", "Enter Image Size (e.g. 512x512)": "Введите размер изображения (например, 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Введите ключ API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "Введите JSON конфигурацию (напр., {\"disable_links\": true})", "Enter Jupyter Password": "Введите пароль Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Введите ключ API поиска Kagi", "Enter Key Behavior": "Введите ключ поведения", "Enter language codes": "Введите коды языков", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Введите ключ API для Mistral", "Enter Model ID": "Введите ID модели", @@ -736,6 +753,7 @@ "Failed to generate title": "Не удалось сгенерировать заголовок", "Failed to import models": "", "Failed to load chat preview": "Не удалось загрузить предпросмотр чата", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Не удалось загрузить содержимое файла.", "Failed to move chat": "Не удалось переместить чат", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Функции", "Features Permissions": "Разрешения для функций", "February": "Февраль", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Детали отзыва", "Feedback History": "История отзывов", - "Feedbacks": "Отзывы", "Feel free to add specific details": "Не стесняйтесь добавлять конкретные детали", "Female": "Женский", "File": "Файл", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Определение подделки отпечатка: Невозможно использовать инициалы в качестве аватара. По умолчанию используется изображение профиля по умолчанию.", "Firecrawl API Base URL": "Базовый URL-адрес Firecrawl API", "Firecrawl API Key": "Ключ API Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Плавающие быстрые действия", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "Фоновое изображение папки", "Folder deleted successfully": "Папка успешно удалена", + "Folder Max File Count": "", "Folder Name": "Название папки", "Folder name cannot be empty.": "Название папки не может быть пустым.", "Folder name updated successfully": "Название папки успешно обновлено", @@ -826,7 +846,6 @@ "General": "Общее", "Generate": "Сгенерировать", "Generate an image": "Сгенерировать изображение", - "Generate Image": "Сгенерировать изображение", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Генерация поискового запроса", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Давайте начнём с {{WEBUI_NAME}}", "Global": "Глобально", "Good Response": "Хороший ответ", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Ключ API Google PSE", "Google PSE Engine Id": "Id движка Google PSE", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Группа", "Group Channel": "", "Group created successfully": "Группа успешно создана", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Генерация промпта к изображению", "Image Prompt Generation Prompt": "Промпт для создание промпта изображения", "Image Size": "", - "Images": "Изображения", "Import": "Импорт", "Import Chats": "Импортировать чаты", "Import Config from JSON File": "Импорт конфигурации из JSON-файла", @@ -927,6 +947,7 @@ "Integration": "Интеграция", "Integrations": "Интеграции", "Interface": "Интерфейс", + "Interface Settings Access": "", "Invalid file content": "Недопустимое содержимое файла", "Invalid file format.": "Неверный формат файла.", "Invalid JSON file": "Недопустимый файл JSON", @@ -940,6 +961,7 @@ "is typing...": "печатает...", "Italic": "Курсив", "January": "Январь", + "Jina API Base URL": "", "Jina API Key": "Ключ API для Jina", "join our Discord for help.": "присоединяйтесь к нашему Discord для помощи.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "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 model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Оставьте пустым, чтобы использовать промпт по умолчанию, или введите пользовательский промпт", "Leave model field empty to use the default model.": "Оставьте поле model пустым, чтобы использовать модель по умолчанию.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Управляйте информацией о своей учетной записи.", "March": "Март", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (Заголовок)", + "Markdown Header Text Splitter": "", "Max Speakers": "Максимальное количество динамиков", "Max Upload Count": "Максимальное количество загрузок", "Max Upload Size": "Максимальный размер загрузок", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимальное количество моделей для загрузки одновременно - 3. Пожалуйста, попробуйте позже.", "May": "Май", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Воспоминания, доступные LLMs, будут отображаться здесь.", "Memory": "Воспоминания", "Memory added successfully": "Воспоминание успешно добавлено", @@ -1051,6 +1077,7 @@ "Merge Responses": "Объединить ответы", "Merged Response": "Объединенный ответ", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Чтобы использовать эту функцию, необходимо включить оценку сообщения.", "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", @@ -1083,9 +1110,11 @@ "Model Name": "Название Модели", "Model name already exists, please choose a different one": "Имя модели уже существует, пожалуйста, выберите другое", "Model Name is required.": "Требуется имя модели.", + "Model names and usage frequency": "", "Model not selected": "Модель не выбрана", "Model Params": "Параметры модели", "Model Permissions": "Разрешения Модели", + "Model responses or outputs": "", "Model unloaded successfully": "Модель выгружена успешно", "Model updated successfully": "Модель успешно обновлена", "Model(s) do not support file upload": "Модель (или модели) не поддерживают загрузку файлов", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Публичный обмен моделями", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Ключ API для поиска Mojeek", "More": "Больше", "More Concise": "Более кратко", @@ -1129,7 +1159,7 @@ "No conversation to save": "Нет разговора для сохранения", "No distance available": "Никаких доступных растояний", "No expiration can pose security risks.": "", - "No feedbacks found": "Никаких обратных связей не найдено", + "No feedback found": "", "No file selected": "Файлы не выбраны", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Модели не выбраны", "No Notes": "Нет заметок", "No notes found": "Заметки не найдены", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Результатов не найдено", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Разрешены только файлы markdown", "Only select users and groups with permission can access": "Доступ имеют только избранные пользователи и группы, имеющие разрешение.", + "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.": "Упс! В предыдущем ответе была ошибка.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI может использовать инструменты, предоставляемые любым сервером OpenAPI.", "Open WebUI uses faster-whisper internally.": "Open WebUI использует более быстрый внутренний интерфейс whisper.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "В Open WebUI используются встраиваемые движки генерации речи SpeechT5 и CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Версия Open WebUI (v{{OPEN_WEBUI_VERSION}}) ниже требуемой версии (v{{REQUIRED_VERSION}})", "OpenAI": "Open AI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "страница", "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.": "", "Password": "Пароль", "Passwords do not match.": "Пароли не совпадают.", "Paste Large Text as File": "Вставить большой текст как файл", @@ -1260,7 +1295,6 @@ "Pipe": "Канал", "Pipeline deleted successfully": "Конвейер успешно удален", "Pipeline downloaded successfully": "Конвейер успешно загружен", - "Pipelines": "Конвейеры", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines — это система плагинов с произвольным выполнением кода —", "Pipelines Not Detected": "Конвейеры не обнаружены", "Pipelines Valves": "Вентили конвейеров", @@ -1500,6 +1534,7 @@ "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 saved successfully!": "Настройки успешно сохранены!", "Share": "Поделиться", "Share Chat": "Поделиться чатом", @@ -1543,6 +1578,7 @@ "Speech recognition error: {{error}}": "Ошибка распознавания речи: {{error}}", "Speech-to-Text": "Речь в текст", "Speech-to-Text Engine": "Система распознавания речи", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Начало канала", "Start Tag": "Начальный тег", @@ -1553,6 +1589,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Остановить", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Последовательность останова", "Stream Chat Response": "Потоковый вывод ответа", @@ -1573,7 +1610,14 @@ "Support": "Поддержать", "Support this plugin:": "Поддержите этот плагин", "Supported MIME Types": "Поддерживаемые MIME типы", + "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.": "", "System": "Система", "System Instructions": "Системные инструкции", "System Prompt": "Системный промпт", @@ -1618,6 +1662,7 @@ "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.": "Ширина в пикселях для сжатия изображений. Оставьте пустым для отключения сжатия.", "Theme": "Тема", + "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}}.", @@ -1732,6 +1777,7 @@ "Upload Pipeline": "Загрузить конвейер", "Upload Progress": "Прогресс загрузки", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Прогресс загрузки: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "Требуется URL", @@ -1749,6 +1795,7 @@ "User Groups": "Группы пользователей", "User location successfully retrieved.": "Местоположение пользователя успешно получено.", "User menu": "Меню пользователя", + "User ratings (thumbs up/down)": "", "User Webhooks": "Пользовательские веб-хуки", "Username": "Имя пользователя", "users": "", @@ -1798,15 +1845,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI будет отправлять запросы к \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Чего вы пытаетесь достичь?", "What are you working on?": "Над чем вы работаете?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Что нового в", "What's on your mind?": "", "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.": "Следует ли разбивать выходные данные на страницы. Каждая страница будет разделена горизонтальной линией и номером страницы. По умолчанию установлено значение Выкл.", "Whisper (Local)": "Whisper (Локально)", + "Who can share to this group": "", "Why?": "Почему?", "Widescreen Mode": "Широкоэкранный режим", "Width": "Ширина", + "Wikipedia": "", "Won": "Победа", "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": "Рабочее пространство", @@ -1818,6 +1869,8 @@ "Yacy Instance URL": "URL-адрес экземпляра Yacy", "Yacy Password": "Пароль Yacy", "Yacy Username": "Имя пользователя Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "Вчера", "Yesterday at {{LOCALIZED_TIME}}": "Вчера в {{LOCALIZED_TIME}}", "You": "Вы", @@ -1825,6 +1878,9 @@ "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.": "Вы можете персонализировать свое взаимодействие с LLMs, добавив воспоминания с помощью кнопки \"Управлять\" ниже, что сделает их более полезными и адаптированными для вас.", "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 save this prompt.": "", "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.": "", @@ -1836,6 +1892,8 @@ "Your Account": "Ваш аккаунт", "Your account status is currently pending activation.": "В настоящее время ваша учетная запись ожидает активации.", "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.": "", "YouTube": "YouTube", "Youtube Language": "Язык YouTube", "Youtube Proxy URL": "URL прокси для YouTube" diff --git a/src/lib/i18n/locales/sk-SK/translation.json b/src/lib/i18n/locales/sk-SK/translation.json index 9f41a2c485..53370c6b29 100644 --- a/src/lib/i18n/locales/sk-SK/translation.json +++ b/src/lib/i18n/locales/sk-SK/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Úprava týchto nastavení sa prejaví univerzálne u všetkých užívateľov.", "admin": "admin", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Admin panel", "Admin Settings": "Nastavenia admina", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administrátori majú prístup ku všetkým nástrojom kedykoľvek; užívatelia potrebujú mať nástroje priradené podľa modelu v workspace.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Povoliť nahrávanie súborov", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Povoliť ne-lokálne hlasy", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "a {{COUNT}} ďalšie/í", "and create a new shared link.": "a vytvoriť nový zdieľaný odkaz.", "Android": "", + "Anyone": "", "API Base URL": "Základná URL adresa API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API kľúč", @@ -175,6 +176,7 @@ "Authenticate": "Autentifikovať", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatické kopírovanie odpovede do schránky", "Auto-playback response": "Automatická odpoveď pri prehrávaní", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "Základná URL pre AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Vyžaduje sa základná URL pre AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Dostupný zoznam", "Available Tools": "", "available users": "dostupní používatelia", @@ -201,6 +204,7 @@ "before": "pred", "Being lazy": "", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "API kľúč pre Brave Search", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Skontrolovať aktualizácie", "Checking for updates...": "Kontrola aktualizácií...", "Choose a model before saving...": "Vyberte model pred uložením...", + "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.": "", "Ciphers": "", "Citation": "Odkaz", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Vykonávanie kódu", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "Kód bol úspešne naformátovaný.", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Kontaktujte administrátora pre prístup k webovému rozhraniu.", "Content": "Obsah", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Pokračovať v odpovedi", "Continue with {{provider}}": "Pokračovať s {{provider}}", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Databáza", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "December", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "", "Do not install functions from sources you do not fully trust.": "Neinštalujte funkcie zo zdrojov, ktorým plne nedôverujete.", "Do not install tools from sources you do not fully trust.": "Neinštalujte nástroje zo zdrojov, ktorým plne nedôverujete.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentácia", - "Documents": "Dokumenty", "does not make any external connections, and your data stays securely on your locally hosted server.": "nevytvára žiadne externé pripojenia a vaše dáta zostávajú bezpečne na vašom lokálnom serveri.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Nestahujte náhodné pipelines zo zdrojov, ktorým nedôverujete.", @@ -493,11 +502,14 @@ "Done": "Hotovo.", "Download": "Stiahnuť", "Download & Delete": "Stiahnuť a odstrániť", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Sťahovanie zrušené", "Download Database": "Stiahnuť databázu", + "Downloading stats...": "", "Draw": "Nakresliť", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "napr. '30s','10m'. Platné časové jednotky sú 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Zadajte API kľúč pre Brave Search", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Zadajte prekryv časti", "Enter Chunk Size": "Zadajte veľkosť časti", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Zadajte URL adresu Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Zadajte veľkosť obrázka (napr. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Zadajte kódy jazykov", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Zadajte ID modelu", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Február", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "História spätnej väzby", - "Feedbacks": "", "Feel free to add specific details": "Neváhajte pridať konkrétne detaily.", "Female": "", "File": "Súbor", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Zistené falšovanie odtlačkov prstov: Nie je možné použiť iniciály ako avatar. Používa sa predvolený profilový obrázok.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Priečinok bol úspešne vymazaný", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Názov priečinka nesmie byť prázdny.", "Folder name updated successfully": "Názov priečinka bol úspešne aktualizovaný.", @@ -826,7 +846,6 @@ "General": "Všeobecné", "Generate": "", "Generate an image": "", - "Generate Image": "Vygenerovať obrázok", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Generovanie vyhľadávacieho dotazu", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "Globálne", "Good Response": "Dobrá odozva", + "Google": "", "Google Drive": "", "Google PSE API Key": "Kľúč API pre Google PSE (Programmatically Search Engine)", "Google PSE Engine Id": "Google PSE Engine Id (Identifikátor vyhľadávacieho modulu Google PSE)", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Skupina", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Obrázky", "Import": "", "Import Chats": "Importovať konverzácie", "Import Config from JSON File": "Importovanie konfigurácie z JSON súboru", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Rozhranie", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Neplatný formát súboru.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Január", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "pripojte sa k nášmu Discordu pre pomoc.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "Nechajte prázdne pre zahrnutie všetkých modelov alebo vyberte konkrétne modely.", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Nechajte prázdne pre použitie predvoleného podnetu, alebo zadajte vlastný podnet.", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Marec", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Maximálny počet nahraní", "Max Upload Size": "Maximálna veľkosť nahrávania", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Maximálne 3 modely môžu byť stiahnuté súčasne. Prosím skúste to znova neskôr.", "May": "Máj", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Spomienky prístupné LLM budú zobrazené tu.", "Memory": "Pamäť", "Memory added successfully": "Pamäť bola úspešne pridaná.", @@ -1051,6 +1077,7 @@ "Merge Responses": "Zlúčiť odpovede", "Merged Response": "Zlúčená odpoveď", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Hodnotenie správ musí byť povolené, aby bolo možné túto funkciu používať.", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Správy, ktoré odošlete po vytvorení odkazu, nebudú zdieľané. Používatelia s URL budú môcť zobraziť zdieľaný chat.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Názov modelu", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model nebol vybraný", "Model Params": "Parametre modelu", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Model bol úspešne aktualizovaný", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Viac", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Nie je dostupná žiadna vzdialenosť", "No expiration can pose security risks.": "", - "No feedbacks found": "Žiadna spätná väzba nenájdená", + "No feedback found": "", "No file selected": "Nebola vybratá žiadna súbor", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Neboli nájdené žiadne výsledky", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Jejda! Vyzerá to, že URL adresa je neplatná. Prosím, skontrolujte ju a skúste to znova.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Jejda! Niektoré súbory sa stále nahrávajú. Prosím, počkajte, kým sa nahrávanie dokončí.", "Oops! There was an error in the previous response.": "Jejda! V predchádzajúcej odpovedi došlo k chybe.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI interne používa faster-whisper.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Verzia Open WebUI (v{{OPEN_WEBUI_VERSION}}) je nižšia ako požadovaná verzia (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI je výskumná organizácia zameraná na umelú inteligenciu, ktorá je známa vývojom pokročilých jazykových modelov, ako je napríklad GPT. Tieto modely sa využívajú v rôznych aplikáciách, vrátane konverzačných agentov a jazykových nástrojov.", "OpenAI API": "OpenAI API je rozhranie aplikačného programovania, ktoré umožňuje vývojárom integrovať pokročilé jazykové modely do svojich aplikácií.", @@ -1235,6 +1268,8 @@ "page": "stránka", "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.": "", "Password": "Heslo", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline bola úspešne odstránená", "Pipeline downloaded successfully": "Kanál bol úspešne stiahnutý", - "Pipelines": "", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines je systém zásuvných modulov s ľubovoľným spúšťaním kódu —", "Pipelines Not Detected": "Prenosové kanály neboli detekované", "Pipelines Valves": "", @@ -1500,6 +1534,7 @@ "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.": "", "Setting": "", "Settings": "Nastavenia", + "Settings Permissions": "", "Settings saved successfully!": "Nastavenia boli úspešne uložené!", "Share": "Zdieľať", "Share Chat": "Zdieľať chat", @@ -1543,6 +1578,7 @@ "Speech recognition error: {{error}}": "Chyba rozpoznávania reči: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Motor prevodu reči na text", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Začiatok kanála", "Start Tag": "", @@ -1553,6 +1589,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Zastaviť", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Sekvencia zastavenia", "Stream Chat Response": "Odozva chatu Stream", @@ -1573,7 +1610,14 @@ "Support": "Podpora", "Support this plugin:": "Podporte tento plugin:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synchronizovať adresár", + "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": "Systém", "System Instructions": "", "System Prompt": "Systémový prompt", @@ -1618,6 +1662,7 @@ "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.": "", "Theme": "Téma", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Premýšľam...", "This action cannot be undone. Do you wish to continue?": "Túto akciu nie je možné vrátiť späť. Prajete si pokračovať?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1732,6 +1777,7 @@ "Upload Pipeline": "Nahrať pipeline", "Upload Progress": "Priebeh nahrávania", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1749,6 +1795,7 @@ "User Groups": "", "User location successfully retrieved.": "Umiestnenie používateľa bolo úspešne získané.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Používateľské meno", "users": "", @@ -1798,15 +1845,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Čo je nové v", "What's on your mind?": "", "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": "kdekoľvek ste", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", "Whisper (Local)": "Whisper (Lokálne)", + "Who can share to this group": "", "Why?": "Prečo?", "Widescreen Mode": "Režim širokouhlého zobrazenia", "Width": "", + "Wikipedia": "", "Won": "Vyhral", "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.": "", "Workspace": "", @@ -1818,6 +1869,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Včera", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Vy", @@ -1825,6 +1878,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Môžete komunikovať len s maximálne {{maxCount}} súbor(ami) naraz.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Môžete personalizovať svoje interakcie s LLM pridaním spomienok prostredníctvom tlačidla 'Spravovať' nižšie, čo ich urobí pre vás užitočnejšími a lepšie prispôsobenými.", "You cannot upload an empty file.": "Nemôžete nahrať prázdny súbor.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1836,6 +1892,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Stav vášho účtu je aktuálne čakajúci na aktiváciu.", "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.": "Celý váš príspevok pôjde priamo vývojárovi pluginu; Open WebUI si neberie žiadne percento. Zvolená platforma na financovanie však môže mať vlastné poplatky.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/sr-RS/translation.json b/src/lib/i18n/locales/sr-RS/translation.json index 2e35a2d6d7..7990df1775 100644 --- a/src/lib/i18n/locales/sr-RS/translation.json +++ b/src/lib/i18n/locales/sr-RS/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Прилагођавање ових подешавања ће применити промене на све кориснике.", "admin": "админ", "Admin": "Админ", + "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.": "Админи имају приступ свим алатима у сваком тренутку, корисницима је потребно доделити алате по моделу у радном простору", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Дозволи отпремање датотека", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Дозволи нелокалне гласове", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "и још {{COUNT}}", "and create a new shared link.": "и направи нову дељену везу.", "Android": "", + "Anyone": "", "API Base URL": "Основна адреса API-ја", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API кључ", @@ -175,6 +176,7 @@ "Authenticate": "Идентификација", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Самостално копирање одговора у оставу", "Auto-playback response": "Самостално пуштање одговора", "Autocomplete Generation": "Стварање самодовршавања", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Automatic1111 Api ниска идентификације", "AUTOMATIC1111 Base URL": "Основна адреса за AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Потребна је основна адреса за AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Списак доступног", "Available Tools": "", "available users": "доступни корисници", @@ -201,6 +204,7 @@ "before": "пре", "Being lazy": "Бити лењ", "Beta": "Бета", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Апи кључ за храбру претрагу", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Потражи ажурирања", "Checking for updates...": "Траже се ажурирања...", "Choose a model before saving...": "Изабери модел пре чувања...", + "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.": "", "Ciphers": "Шифре", "Citation": "Цитат", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Извршавање кода", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "Код форматиран успешно", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Пишите админима за приступ на WebUI", "Content": "Садржај", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Настави одговор", "Continue with {{provider}}": "Настави са {{provider}}", "Continue with Email": "Настави са е-адресом", @@ -393,6 +401,7 @@ "Database": "База података", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Децембар", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Документација", - "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.": "Не преузимајте насумичне pipelines са извора којима не верујете.", @@ -493,11 +502,14 @@ "Done": "Готово", "Download": "Преузми", "Download & Delete": "Преузми и избриши", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "Преузимање отказано", "Download Database": "Преузми базу података", + "Downloading stats...": "", "Draw": "Нацртај", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "нпр. '30s', '10m'. Важеће временске јединице су 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Унесите БРАВЕ Сеарцх АПИ кључ", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Унесите преклапање делова", "Enter Chunk Size": "Унесите величину дела", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Унесите Гитхуб Раw УРЛ адресу", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Унесите величину слике (нпр. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "Унесите кодове језика", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Фебруар", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Историјат повратних података", - "Feedbacks": "Повратни подаци", "Feel free to add specific details": "Слободно додајте специфичне детаље", "Female": "", "File": "Датотека", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Откривено лажно представљање отиска прста: Немогуће је користити иницијале као аватар. Прелазак на подразумевану профилну слику.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Опште", "Generate": "", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Генерисање упита претраге", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "Добар одговор", + "Google": "", "Google Drive": "", "Google PSE API Key": "Гоогле ПСЕ АПИ кључ", "Google PSE Engine Id": "Гоогле ПСЕ ИД мотора", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Група", "Group Channel": "", "Group created successfully": "Група направљена успешно", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Слике", "Import": "", "Import Chats": "Увези ћаскања", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Изглед", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Јануар", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "придружите се нашем Дискорду за помоћ.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Март", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Највише 3 модела могу бити преузета истовремено. Покушајте поново касније.", "May": "Мај", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Памћења које ће бити појављена од овог LLM-а ће бити приказана овде.", "Memory": "Сећања", "Memory added successfully": "Сећање успешно додато", @@ -1051,6 +1077,7 @@ "Merge Responses": "Спој одговоре", "Merged Response": "Спојени одговор", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Модел није изабран", "Model Params": "Модел Парамс", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Више", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Нема резултата", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Упс! Изгледа да је адреса неважећа. Молимо вас да проверите и покушате поново.", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "страница", "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.": "", "Password": "Лозинка", "Passwords do not match.": "", "Paste Large Text as File": "Убаци велики текст као датотеку", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Цевовод успешно обрисан", "Pipeline downloaded successfully": "Цевовод успешно преузет", - "Pipelines": "Цевоводи", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines је систем прикључака са произвољним извршавањем кода —", "Pipelines Not Detected": "Цевоводи нису уочени", "Pipelines Valves": "Вентили за цевоводе", @@ -1499,6 +1533,7 @@ "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.": "", "Setting": "", "Settings": "Подешавања", + "Settings Permissions": "", "Settings saved successfully!": "Подешавања успешно сачувана!", "Share": "Подели", "Share Chat": "Подели ћаскање", @@ -1542,6 +1577,7 @@ "Speech recognition error: {{error}}": "Грешка у препознавању говора: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Мотор за говор у текст", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Почетак канала", "Start Tag": "", @@ -1552,6 +1588,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Заустави", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Секвенца заустављања", "Stream Chat Response": "", @@ -1572,7 +1609,14 @@ "Support": "Подршка", "Support this plugin:": "Подржите овај прикључак", "Supported MIME Types": "", + "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.": "", "System": "Систем", "System Instructions": "Системске инструкције", "System Prompt": "Системски упит", @@ -1617,6 +1661,7 @@ "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.": "", "Theme": "Тема", + "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.": "", @@ -1731,6 +1776,7 @@ "Upload Pipeline": "Цевовод отпремања", "Upload Progress": "Напредак отпремања", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "УРЛ", "URL is required": "", @@ -1748,6 +1794,7 @@ "User Groups": "", "User location successfully retrieved.": "Корисничка локација успешно добављена.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Корисничко име", "users": "", @@ -1797,15 +1844,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Шта је ново у", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "Зашто?", "Widescreen Mode": "Режим широког екрана", "Width": "", + "Wikipedia": "", "Won": "Победа", "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.": "", "Workspace": "Радни простор", @@ -1817,6 +1868,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Јуче", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Ти", @@ -1824,6 +1877,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Можете учинити разговор са ВЈМ-овима приснијим додавањем сећања користећи „Управљај“ думе испод и тиме их учинити приснијим и кориснијим.", "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 save this prompt.": "", "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.": "", @@ -1835,6 +1891,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Јутјуб", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index 4ec02d32e9..c8a8312633 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Justering av dessa inställningar kommer att tillämpa ändringar universellt för alla användare.", "admin": "administratör", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Administrationspanel", "Admin Settings": "Administratörsinställningar", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratörer har tillgång till alla verktyg hela tiden, medan användare behöver verktyg som tilldelas per modell i arbetsytan.", @@ -101,7 +102,6 @@ "Allow Continue Response": "Tillåt funktionen Fortsätt svara", "Allow Delete Messages": "Tillåt radering av meddelanden", "Allow File Upload": "Tillåt filuppladdning", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Tillåt flera modeller i chatt", "Allow non-local voices": "Tillåt icke-lokala röster", "Allow Rate Response": "Tillåt betygsättning av svar", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "och {{COUNT}} fler", "and create a new shared link.": "och skapa en ny delad länk.", "Android": "Android", + "Anyone": "", "API Base URL": "API-bas-URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API-nyckel", @@ -175,6 +176,7 @@ "Authenticate": "Autentisera", "Authentication": "Autentisering", "Auto": "Auto", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Automatisk kopiering av svar till urklipp", "Auto-playback response": "Automatisk uppspelning av svar", "Autocomplete Generation": "Automatisk komplettering av generering", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 bas-URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 bas-URL krävs.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Tillgänglig lista", "Available Tools": "Tillgängliga verktyg", "available users": "tillgängliga användare", @@ -201,6 +204,7 @@ "before": "före", "Being lazy": "Är lat", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 Endpoint", "Bing Search V7 Subscription Key": "Bing Search V7 Prenumerationsnyckel", "Bio": "Personlig information om dig", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search API-nyckel", "Bold": "Fet", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Öka eller straffa specifika tokens för begränsade svar. Biasvärden kommer att klämmas fast mellan -100 och 100 (inklusive). (Standard: ingen)", + "Brave": "", "Brave Search API Key": "API-nyckel för Brave Search", + "Builtin Tools": "", "Bullet List": "Punktlista", "Button ID": "", "Button Label": "Knappetikett", @@ -256,8 +262,10 @@ "Check for updates": "Sök efter uppdateringar", "Checking for updates...": "Söker efter uppdateringar...", "Choose a model before saving...": "Välj en modell innan du sparar...", + "Chunk Min Size Target": "", "Chunk Overlap": "Överlappning", "Chunk Size": "Chunk-storlek", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Chiffer", "Citation": "Citat", "Citations": "Citeringar", @@ -293,7 +301,6 @@ "Code Block": "Kodblock", "Code Editor": "", "Code execution": "Kodkörning", - "Code Execution": "Kodkörning", "Code Execution Engine": "Motor för kodkörning", "Code Execution Timeout": "Timeout för kodkörning", "Code formatted successfully": "Koden formaterades framgångsrikt", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Kontakta administratören för att få åtkomst till WebUI", "Content": "Innehåll", "Content Extraction Engine": "Motor för innehållsextrahering", + "Content lengths (character counts only)": "", "Continue Response": "Fortsätt svar", "Continue with {{provider}}": "Fortsätt med {{provider}}", "Continue with Email": "Fortsätt med e-post", @@ -393,6 +401,7 @@ "Database": "Databas", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "december", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Dyk in i kunskap", "Do not install functions from sources you do not fully trust.": "Installera inte funktioner från källor du inte litar på.", "Do not install tools from sources you do not fully trust.": "Installera inte verktyg från källor du inte litar på.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "Docling Server URL krävs.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dokumentation", - "Documents": "Dokument", "does not make any external connections, and your data stays securely on your locally hosted server.": "gör inga externa anslutningar, och dina data förblir säkra på din lokalt värdade server.", "Domain Filter List": "Domänfilterlista", "don't fetch random pipelines from sources you don't trust.": "Hämta inte slumpmässiga pipelines från källor du inte litar på.", @@ -493,11 +502,14 @@ "Done": "Klar", "Download": "Ladda ner", "Download & Delete": "Ladda ned och ta bort", + "Download as JSON": "", "Download as SVG": "Ladda ner som SVG", "Download canceled": "Nedladdning avbruten", "Download Database": "Ladda ner databas", + "Downloading stats...": "", "Draw": "Rita", "Drop any files here to upload": "Släpp alla filer här för att ladda upp", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "t.ex. '30s', '10m'. Giltiga tidsenheter är 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "t.ex. \"json\" eller ett JSON-schema", "e.g. 60": "t.ex. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Ange Bocha Search API-nyckel", "Enter Brave Search API Key": "Ange API-nyckel för Brave Search", "Enter certificate path": "Ange certifikatväg", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Ange chunköverlappning", "Enter Chunk Size": "Ange chunkstorlek", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Ange komma-separerade \"token:bias_value\"-par (exempel: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Ange URL för extern webbsökning", "Enter Firecrawl API Base URL": "Ange Firecrawl API Base URL", "Enter Firecrawl API Key": "Ange Firecrawl API-nyckel", + "Enter Firecrawl Timeout": "", "Enter folder name": "Ange mappnamn", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Ange Github Raw URL", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "Ange ID", "Enter Image Size (e.g. 512x512)": "Ange bildstorlek (t.ex. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Ange Jina API-nyckel", "Enter JSON config (e.g., {\"disable_links\": true})": "Ange JSON-konfiguration (t.ex. {\"disable_links\": true})", "Enter Jupyter Password": "Ange Jupyter-lösenord", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Ange Kagi Search API-nyckel", "Enter Key Behavior": "Ange nyckelbeteende", "Enter language codes": "Skriv språkkoder", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Ange Mistral API-nyckel", "Enter Model ID": "Ange modell-ID", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Misslyckades med att läsa in filinnehåll.", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Funktioner", "Features Permissions": "Funktionsbehörigheter", "February": "februari", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "Feedbackdetaljer", "Feedback History": "Feedbackhistorik", - "Feedbacks": "Återkopplingar", "Feel free to add specific details": "Tveka inte att lägga till specifika detaljer", "Female": "", "File": "Fil", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingeravtrycksmanipulering upptäckt: Kan inte använda initialer som avatar. Återställning till standardprofilbild.", "Firecrawl API Base URL": "Firecrawl API Base URL", "Firecrawl API Key": "Firecrawl API-nyckel", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "Flytande snabbåtgärder", "Focus Chat Input": "", "Folder": "Mapp", "Folder Background Image": "Bakgrundsbild till mappen", "Folder deleted successfully": "Mappen har tagits bort", + "Folder Max File Count": "", "Folder Name": "Mappnamn", "Folder name cannot be empty.": "Mappnamnet får inte vara tomt.", "Folder name updated successfully": "Mappnamnet har uppdaterats", @@ -826,7 +846,6 @@ "General": "Allmän", "Generate": "Generera", "Generate an image": "Generera en bild", - "Generate Image": "Generera bild", "Generate Message Pair": "", "Generated Image": "Genererad bild", "Generating search query": "Genererar sökfråga", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Kom igång med {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Bra svar", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API-nyckel", "Google PSE Engine Id": "Google PSE Engine Id", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "Grupp", "Group Channel": "", "Group created successfully": "Gruppen har skapats", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Generering av bildprompt", "Image Prompt Generation Prompt": "Prompt för generering av bildprompt", "Image Size": "", - "Images": "Bilder", "Import": "Importera", "Import Chats": "Importera chattar", "Import Config from JSON File": "Importera konfiguration från JSON-fil", @@ -927,6 +947,7 @@ "Integration": "Integration", "Integrations": "Integrationer", "Interface": "Gränssnitt", + "Interface Settings Access": "", "Invalid file content": "Ogiltigt filinnehåll", "Invalid file format.": "Ogiltigt filformat.", "Invalid JSON file": "Ogiltig JSON-fil", @@ -940,6 +961,7 @@ "is typing...": "skriver...", "Italic": "Kursiv", "January": "januari", + "Jina API Base URL": "", "Jina API Key": "Jina API-nyckel", "join our Discord for help.": "gå med i vår Discord för hjälp.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Lämna tomt för att inkludera alla modeller från \"{{url}}/api/tags\"-slutpunkten", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Lämna tomt för att inkludera alla modeller från \"{{url}}/models\"-slutpunkten", "Leave empty to include all models or select specific models": "Lämna tomt för att inkludera alla modeller eller välj specifika modeller", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Lämna tomt för att använda standardprompten, eller ange en anpassad prompt", "Leave model field empty to use the default model.": "Lämna modellfältet tomt för att använda standardmodellen.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "Hantera din kontoinformation.", "March": "mars", "Markdown": "Markdown", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "Max antal talare", "Max Upload Count": "Max antal uppladdningar", "Max Upload Size": "Max uppladdningsstorlek", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Högst 3 modeller kan laddas ner samtidigt. Vänligen försök igen senare.", "May": "maj", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Minnen som är tillgängliga för AI visas här.", "Memory": "Minne", "Memory added successfully": "Minnet har lagts till", @@ -1051,6 +1077,7 @@ "Merge Responses": "Sammanslå svar (med AI)", "Merged Response": "Sammansslaget svar", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Meddelandebetyg måste vara aktiverat för att använda den här funktionen", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Meddelanden du skickar efter att du har skapat din länk kommer inte att delas. Användare med länken kommer att kunna se allt innehåll i den delade chatten.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Modellnamn", "Model name already exists, please choose a different one": "Modellnamnet finns redan, välj ett annat namn", "Model Name is required.": "Modellnamn krävs.", + "Model names and usage frequency": "", "Model not selected": "Modell inte vald", "Model Params": "Modellparametrar", "Model Permissions": "Modellbehörigheter", + "Model responses or outputs": "", "Model unloaded successfully": "Modellen har avlastats", "Model updated successfully": "Modellen har uppdaterats", "Model(s) do not support file upload": "Modellen/modellerna stöder inte filuppladdning", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Offentlig delning av modeller", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Sök API-nyckel", "More": "Mer", "More Concise": "Mer kortfattat", @@ -1129,7 +1159,7 @@ "No conversation to save": "Ingen konversation att spara", "No distance available": "Inget avstånd tillgängligt", "No expiration can pose security risks.": "Ingen utgångstid kan orsaka säkerhetsrisker.", - "No feedbacks found": "Ingen feedback hittades", + "No feedback found": "", "No file selected": "Ingen fil vald", "No files in this knowledge base.": "", "No functions found": "Inga funktioner hittades", @@ -1144,6 +1174,7 @@ "No models selected": "Inga modeller valda", "No Notes": "Inga anteckningar", "No notes found": "Inga anteckningar hittades", + "No one": "", "No pinned messages": "", "No prompts found": "Inga promptar hittades", "No results": "Inga resultat hittades", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Endast markdown-filer är tillåtna", "Only select users and groups with permission can access": "Endast valda användare och grupper med behörighet kan komma åt", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Hoppsan! Det ser ut som om URL:en är ogiltig. Dubbelkolla gärna och försök igen.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Hoppsan! Det finns fortfarande filer som laddas upp. Vänta tills uppladdningen är klar.", "Oops! There was an error in the previous response.": "Hoppsan! Det uppstod ett fel i föregående svar.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI kan använda verktyg från alla OpenAPI-servrar.", "Open WebUI uses faster-whisper internally.": "Open WebUI använder faster-whisper internt.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI använder SpeechT5 och CMU Arctic högtalarinbäddningar.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI-versionen (v{{OPEN_WEBUI_VERSION}}) är lägre än den version som krävs (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "sida", "Paginate": "Sidnumrera", "Parameters": "Parametrar", + "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.": "", "Password": "Lösenord", "Passwords do not match.": "Lösenorden matchar inte.", "Paste Large Text as File": "Klistra in stor text som fil", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Rörledningen har tagits bort", "Pipeline downloaded successfully": "Rörledningen har laddats ner", - "Pipelines": "Rörledningar", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines är ett insticksmodulsystem med godtycklig kodkörning —", "Pipelines Not Detected": "Inga rörledningar hittades", "Pipelines Valves": "Ventiler för rörledningar", @@ -1498,6 +1532,7 @@ "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.": "Anger de stoppsekvenser som ska användas. När detta mönster påträffas kommer LLM att sluta generera text och returnera. Flera stoppsekvenser kan ställas in genom att ange flera separata stoppparametrar i en modelfil.", "Setting": "", "Settings": "Inställningar", + "Settings Permissions": "", "Settings saved successfully!": "Inställningar sparades framgångsrikt!", "Share": "Dela", "Share Chat": "Dela chatt", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Fel vid taligenkänning: {{error}}", "Speech-to-Text": "Tal-till-text", "Speech-to-Text Engine": "Tal-till-text-motor", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "Starta en ny konversation", "Start of the channel": "Början av kanalen", "Start Tag": "Starta en tagg", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Stopp", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Stoppsekvens", "Stream Chat Response": "Strömma chattsvar", @@ -1571,7 +1608,14 @@ "Support": "Stöd", "Support this plugin:": "Stöd denna plugin", "Supported MIME Types": "MIME-typer som stöds", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Synkronisera katalog", + "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", "System Instructions": "Systeminstruktioner", "System Prompt": "Systemprompt", @@ -1616,6 +1660,7 @@ "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.": "Bredden i pixlar för att komprimera bilder till. Lämna tomt för ingen komprimering.", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Tänker...", "This action cannot be undone. Do you wish to continue?": "Denna åtgärd kan inte ångras. Vill du fortsätta?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Den här kanalen skapades den {{createdAt}}. Detta är den allra första början av kanalen {{channelName}}.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Ladda upp rörledning", "Upload Progress": "Uppladdningsframsteg", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Uppladdningsstatus: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "URL krävs", @@ -1747,6 +1793,7 @@ "User Groups": "Användargrupper", "User location successfully retrieved.": "Användarens plats har hämtats", "User menu": "Användarmenyn", + "User ratings (thumbs up/down)": "", "User Webhooks": "Användar-webhooks", "Username": "Användarnamn", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI kommer att göra förfrågningar till \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Vad försöker du uppnå?", "What are you working on?": "Var arbetar du med?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Vad är nytt i", "What's on your mind?": "", "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.": "När det här läget är aktiverat svarar modellen på varje chattmeddelande i realtid och genererar ett svar så snart användaren skickar ett meddelande. Det här läget är användbart för livechattar, men kan påverka prestandan på långsammare maskinvara.", "wherever you are": "var du än befinner dig", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Om utdata ska sidnumreras. Varje sida kommer att separeras av en horisontell linje och sidnummer. Standardvärdet är False.", "Whisper (Local)": "Whisper (lokal)", + "Who can share to this group": "", "Why?": "Varför?", "Widescreen Mode": "Bredbildsläge", "Width": "Bredd", + "Wikipedia": "", "Won": "Vann", "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.": "Fungerar tillsammans med top-k. Ett högre värde (t.ex. 0,95) leder till mer varierande text, medan ett lägre värde (t.ex. 0,5) genererar mer fokuserad och konservativ text.", "Workspace": "Arbetsyta", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy-instans-URL", "Yacy Password": "Yacy-lösenord", "Yacy Username": "Yacy-användarnamn", + "Yahoo": "", + "Yandex": "", "Yesterday": "Igår", "Yesterday at {{LOCALIZED_TIME}}": "Igår kl {{LOCALIZED_TIME}}", "You": "Dig", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Du kan endast chatta med maximalt {{maxCount}} fil(er) på samma gång", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Du kan anpassa dina interaktioner med AI genom att lägga till minnen via knappen 'Hantera' nedan, så konversationerna blir mer anpassade för dig.", "You cannot upload an empty file.": "Du kan inte ladda upp en tom fil.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "You do not have permission to send messages in this channel.": "Du har inte behörighet att skicka meddelanden i denna kanal.", "You do not have permission to send messages in this thread.": "Du har inte behörighet att skicka meddelanden i denna tråd.", "You do not have permission to upload files to this knowledge base.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Ditt konto", "Your account status is currently pending activation.": "Ditt konto väntar på att bli aktiverat", "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.": "Hela ditt bidrag går direkt till pluginutvecklaren; Open WebUI tar ingen procentandel. Däremot kan den valda finansieringsplattformen ha egna avgifter.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube-språk", "Youtube Proxy URL": "Youtube Proxy-URL" diff --git a/src/lib/i18n/locales/th-TH/translation.json b/src/lib/i18n/locales/th-TH/translation.json index 5aad4769b7..0230317e34 100644 --- a/src/lib/i18n/locales/th-TH/translation.json +++ b/src/lib/i18n/locales/th-TH/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "การปรับการตั้งค่าเหล่านี้จะมีผลกับผู้ใช้ทุกคนทั่วทั้งระบบ", "admin": "ผู้ดูแลระบบ", "Admin": "ผู้ดูแลระบบ", + "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.": "ผู้ดูแลระบบสามารถเข้าถึงเครื่องมือทั้งหมดได้ตลอดเวลา ส่วนผู้ใช้ต้องได้รับการกำหนดเครื่องมือต่อโมเดลในแต่ละพื้นที่ทำงาน", @@ -101,7 +102,6 @@ "Allow Continue Response": "อนุญาตให้ตอบกลับต่อเนื่อง", "Allow Delete Messages": "อนุญาตให้ลบข้อความ", "Allow File Upload": "อนุญาตให้อัปโหลดไฟล์", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "อนุญาตการใช้หลายโมเดลในการแชท", "Allow non-local voices": "อนุญาตเสียงที่ไม่ใช่แบบ Local", "Allow Rate Response": "อนุญาตให้ให้คะแนนคำตอบ", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "และอีก {{COUNT}} รายการ", "and create a new shared link.": "และสร้างลิงก์ที่แชร์ใหม่", "Android": "Android", + "Anyone": "", "API Base URL": "URL พื้นฐานของ API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "URL พื้นฐานของ API สำหรับบริการ Datalab Marker ค่าเริ่มต้น: https://www.datalab.to/api/v1/marker", "API Key": "คีย์ API", @@ -175,6 +176,7 @@ "Authenticate": "ยืนยันตัวตน", "Authentication": "การยืนยันตัวตน", "Auto": "อัตโนมัติ", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "คัดลอกคำตอบไปยังคลิปบอร์ดโดยอัตโนมัติ", "Auto-playback response": "การเล่นคำตอบอัตโนมัติ", "Autocomplete Generation": "การเติมข้อความอัตโนมัติ", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "สตริงการตรวจสอบสิทธิ์ API ของ AUTOMATIC1111", "AUTOMATIC1111 Base URL": "URL พื้นฐานของ AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "จำเป็นต้องระบุ Base URL ของ AUTOMATIC1111", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "รายการที่มีอยู่", "Available Tools": "เครื่องมือที่มีให้ใช้", "available users": "ผู้ใช้ที่มีอยู่", @@ -201,6 +204,7 @@ "before": "ก่อน", "Being lazy": "ขี้เกียจ", "Beta": "เบต้า", + "Bing": "", "Bing Search V7 Endpoint": "Endpoint ของ Bing Search V7", "Bing Search V7 Subscription Key": "Subscription Key ของ Bing Search V7", "Bio": "ประวัติส่วนตัว", @@ -209,7 +213,9 @@ "Bocha Search API Key": "API Key ของ Bocha Search", "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 Search API Key": "คีย์ API ของ Brave Search", + "Builtin Tools": "", "Bullet List": "รายการหัวข้อย่อย", "Button ID": "ID ของปุ่ม", "Button Label": "ป้ายชื่อปุ่ม", @@ -256,8 +262,10 @@ "Check for updates": "ตรวจสอบการอัปเดต", "Checking for updates...": "กำลังตรวจสอบการอัปเดต...", "Choose a model before saving...": "เลือกโมเดลก่อนบันทึก...", + "Chunk Min Size Target": "", "Chunk Overlap": "ส่วนซ้อนทับของ Chunk", "Chunk Size": "ขนาด Chunk", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "รหัสลับ", "Citation": "การอ้างอิง", "Citations": "การอ้างอิง", @@ -293,7 +301,6 @@ "Code Block": "บล็อกโค้ด", "Code Editor": "ตัวแก้ไขโค้ด", "Code execution": "รันโค้ด", - "Code Execution": "การรันโค้ด", "Code Execution Engine": "เอนจินรันโค้ด", "Code Execution Timeout": "หมดเวลาในการรันโค้ด", "Code formatted successfully": "จัดรูปแบบโค้ดสำเร็จแล้ว", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "ติดต่อผู้ดูแลระบบเพื่อขอสิทธิ์เข้าใช้ WebUI", "Content": "เนื้อหา", "Content Extraction Engine": "เอนจินดึงเนื้อหา", + "Content lengths (character counts only)": "", "Continue Response": "ตอบต่อ", "Continue with {{provider}}": "ดำเนินการต่อด้วย {{provider}}", "Continue with Email": "ดำเนินการต่อด้วยอีเมล", @@ -393,6 +401,7 @@ "Database": "ฐานข้อมูล", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "DD/MM/YYYY", + "DDGS Backend": "", "December": "ธันวาคม", "Decrease UI Scale": "", "Deepgram": "Deepgram", @@ -474,6 +483,7 @@ "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", "Docling Parameters": "", "Docling Server URL required.": "ต้องระบุ Docling Server URL", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "ต้องระบุ Endpoint ของ Document Intelligence", "Document Intelligence Model": "", "Documentation": "เอกสารประกอบ", - "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.": "อย่าดึง Pipeline แบบสุ่มจากแหล่งที่ไม่น่าเชื่อถือ", @@ -493,11 +502,14 @@ "Done": "เสร็จสิ้น", "Download": "ดาวน์โหลด", "Download & Delete": "ดาวน์โหลดและลบ", + "Download as JSON": "", "Download as SVG": "ดาวน์โหลดเป็น SVG", "Download canceled": "ยกเลิกการดาวน์โหลด", "Download Database": "ดาวน์โหลดฐานข้อมูล", + "Downloading stats...": "", "Draw": "วาด", "Drop any files here to upload": "วางไฟล์ที่นี่เพื่ออัปโหลด", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "เช่น '30s', '10m' หน่วยเวลาที่ใช้ได้คือ 's', 'm', 'h'", "e.g. \"json\" or a JSON schema": "เช่น \"json\" หรือสคีมา JSON", "e.g. 60": "เช่น 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "ใส่คีย์ Bocha Search API", "Enter Brave Search API Key": "ใส่ API Key ของ Brave Search", "Enter certificate path": "ป้อนพาธใบรับรอง", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "ป้อนค่า Chunk Overlap", "Enter Chunk Size": "ใส่ขนาด Chunk", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "ป้อนคู่ \"token:bias_value\" ที่คั่นด้วยจุลภาค (ตัวอย่าง: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "ป้อน URL สำหรับค้นเว็บภายนอก", "Enter Firecrawl API Base URL": "ใส่ Firecrawl API Base URL", "Enter Firecrawl API Key": "ใส่ Firecrawl API Key", + "Enter Firecrawl Timeout": "", "Enter folder name": "ป้อนชื่อโฟลเดอร์", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "ป้อน URL Raw ของ GitHub", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "ป้อนสีในรูปแบบ Hex (เช่น #FF0000)", "Enter ID": "ใส่ ID", "Enter Image Size (e.g. 512x512)": "ใส่ขนาดภาพ (เช่น 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "ป้อน Jina API Key", "Enter JSON config (e.g., {\"disable_links\": true})": "ป้อนการตั้งค่า JSON (เช่น {\"disable_links\": true})", "Enter Jupyter Password": "ป้อนรหัสผ่าน Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "ใส่ Kagi Search API Key", "Enter Key Behavior": "การทำงานของปุ่ม Enter", "Enter language codes": "ใส่รหัสภาษา", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "ป้อน URL ฐานของ Mistral API", "Enter Mistral API Key": "กรอก API Key ของ Mistral", "Enter Model ID": "ป้อน ID โมเดล", @@ -736,6 +753,7 @@ "Failed to generate title": "สร้างชื่อไม่สำเร็จ", "Failed to import models": "นำเข้าโมเดลไม่สำเร็จ", "Failed to load chat preview": "ไม่สามารถโหลดตัวอย่างแชทได้", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "โหลดเนื้อหาไฟล์ไม่สำเร็จ", "Failed to move chat": "ย้ายแชทไม่สำเร็จ", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "ฟีเจอร์", "Features Permissions": "สิทธิ์การใช้งานฟีเจอร์", "February": "กุมภาพันธ์", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "รายละเอียดคำติชม", "Feedback History": "ประวัติข้อเสนอแนะ", - "Feedbacks": "ข้อเสนอแนะ", "Feel free to add specific details": "สามารถเพิ่มรายละเอียดเฉพาะได้", "Female": "หญิง", "File": "ไฟล์", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "ตรวจพบการปลอมแปลงลายนิ้วมือ: ไม่สามารถใช้ชื่อย่อเป็นอวตาร์ได้ กำลังใช้รูปโปรไฟล์เริ่มต้น", "Firecrawl API Base URL": "URL ฐาน Firecrawl API", "Firecrawl API Key": "API Key ของ Firecrawl", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "การดำเนินการด่วนแบบลอยตัว", "Focus Chat Input": "โฟกัสช่องป้อนแชท", "Folder": "โฟลเดอร์", "Folder Background Image": "รูปภาพพื้นหลังโฟลเดอร์", "Folder deleted successfully": "ลบโฟลเดอร์สำเร็จแล้ว", + "Folder Max File Count": "", "Folder Name": "ชื่อโฟลเดอร์", "Folder name cannot be empty.": "ชื่อโฟลเดอร์ต้องไม่เว้นว่าง", "Folder name updated successfully": "อัปเดตชื่อโฟลเดอร์สำเร็จแล้ว", @@ -826,7 +846,6 @@ "General": "ทั่วไป", "Generate": "สร้าง", "Generate an image": "สร้างรูปภาพ", - "Generate Image": "สร้างภาพ", "Generate Message Pair": "สร้างคู่ข้อความ", "Generated Image": "รูปภาพที่ถูกสร้าง", "Generating search query": "สร้างคำค้นหา", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "เริ่มต้นใช้งาน {{WEBUI_NAME}}", "Global": "ทั้งหมด", "Good Response": "การตอบกลับที่ดี", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "คีย์ API ของ Google PSE", "Google PSE Engine Id": "รหัสเอนจินของ Google PSE", "Gravatar": "Gravatar", "Grid": "", + "Grokipedia": "", "Group": "กลุ่ม", "Group Channel": "", "Group created successfully": "สร้างกลุ่มสำเร็จแล้ว", @@ -895,7 +916,6 @@ "Image Prompt Generation": "การสร้างพรอมต์รูปภาพ", "Image Prompt Generation Prompt": "พรอมต์สำหรับสร้างคำสั่งภาพ", "Image Size": "ขนาดรูปภาพ", - "Images": "ภาพ", "Import": "นำเข้า", "Import Chats": "นำเข้าการสนทนา", "Import Config from JSON File": "นำเข้า Config จากไฟล์ JSON", @@ -927,6 +947,7 @@ "Integration": "การเชื่อมต่อระบบ", "Integrations": "การเชื่อมต่อระบบ", "Interface": "อินเทอร์เฟซ", + "Interface Settings Access": "", "Invalid file content": "เนื้อหาไฟล์ไม่ถูกต้อง", "Invalid file format.": "รูปแบบไฟล์ไม่ถูกต้อง", "Invalid JSON file": "ไฟล์ JSON ไม่ถูกต้อง", @@ -940,6 +961,7 @@ "is typing...": "กำลังพิมพ์...", "Italic": "ตัวเอียง", "January": "มกราคม", + "Jina API Base URL": "", "Jina API Key": "API Key ของ Jina", "join our Discord for help.": "เข้าร่วม Discord ของเราเพื่อขอความช่วยเหลือ", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "เว้นว่างไว้เพื่อรวมโมเดลทั้งหมดจาก Endpoint \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "เว้นว่างไว้เพื่อรวมโมเดลทั้งหมดจาก 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 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.": "เว้นช่องโมเดลว่างไว้เพื่อใช้โมเดลเริ่มต้น", @@ -1029,10 +1052,12 @@ "Manage your account information.": "จัดการข้อมูลบัญชีของคุณ", "March": "มีนาคม", "Markdown": "Markdown", - "Markdown (Header)": "Markdown (ส่วนหัว)", + "Markdown Header Text Splitter": "", "Max Speakers": "จำนวนผู้พูดสูงสุด", "Max Upload Count": "จำนวนครั้งการอัปโหลดสูงสุด", "Max Upload Size": "ขนาดอัปโหลดสูงสุด", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "สามารถดาวน์โหลดโมเดลได้สูงสุด 3 โมเดลในเวลาเดียวกัน โปรดลองอีกครั้งในภายหลัง", "May": "พฤษภาคม", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "ความจำที่ LLM เข้าถึงได้จะแสดงที่นี่", "Memory": "ความจำ", "Memory added successfully": "เพิ่มความจำสำเร็จ", @@ -1051,6 +1077,7 @@ "Merge Responses": "รวมคำตอบ", "Merged Response": "การตอบกลับที่รวมกัน", "Message": "ข้อความ", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "ต้องเปิดใช้การให้คะแนนข้อความก่อนจึงจะใช้ฟีเจอร์นี้ได้", "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", @@ -1083,9 +1110,11 @@ "Model Name": "ชื่อโมเดล", "Model name already exists, please choose a different one": "มีชื่อโมเดลนี้อยู่แล้ว โปรดเลือกชื่ออื่น", "Model Name is required.": "จำเป็นต้องระบุชื่อโมเดล", + "Model names and usage frequency": "", "Model not selected": "ยังไม่ได้เลือกโมเดล", "Model Params": "พารามิเตอร์ของโมเดล", "Model Permissions": "สิทธิ์ของโมเดล", + "Model responses or outputs": "", "Model unloaded successfully": "ยกเลิกการโหลดโมเดลสำเร็จแล้ว", "Model updated successfully": "อัปเดตโมเดลเรียบร้อยแล้ว", "Model(s) do not support file upload": "โมเดลไม่รองรับการอัปโหลดไฟล์", @@ -1096,6 +1125,7 @@ "Models imported successfully": "นำเข้าโมเดลสำเร็จแล้ว", "Models Public Sharing": "การแชร์โมเดลสาธารณะ", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "API Key สำหรับ Mojeek Search", "More": "เพิ่มเติม", "More Concise": "กระชับมากขึ้น", @@ -1129,7 +1159,7 @@ "No conversation to save": "ไม่มีการสนทนาที่จะบันทึก", "No distance available": "ไม่มีข้อมูลระยะทาง", "No expiration can pose security risks.": "ไม่มีวันหมดอายุอาจทำให้เกิดความเสี่ยงด้านความปลอดภัย", - "No feedbacks found": "ไม่พบความคิดเห็น", + "No feedback found": "", "No file selected": "ไม่ได้เลือกไฟล์", "No files in this knowledge base.": "", "No functions found": "ไม่พบฟังก์ชัน", @@ -1144,6 +1174,7 @@ "No models selected": "ไม่ได้เลือกโมเดล", "No Notes": "ไม่มีบันทึก", "No notes found": "ไม่พบบันทึก", + "No one": "", "No pinned messages": "", "No prompts found": "ไม่พบพรอมต์", "No results": "ไม่มีผลลัพธ์", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "อนุญาตเฉพาะไฟล์ Markdown เท่านั้น", "Only select users and groups with permission can access": "มีเฉพาะผู้ใช้และกลุ่มที่ได้รับสิทธิ์เท่านั้นที่เข้าถึงได้", + "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.": "ขออภัย! เกิดข้อผิดพลาดในคำตอบก่อนหน้า", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI สามารถใช้เครื่องมือที่มีให้จากเซิร์ฟเวอร์ OpenAPI ใดก็ได้", "Open WebUI uses faster-whisper internally.": "Open WebUI ใช้ faster-whisper อยู่ภายใน", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI ใช้ SpeechT5 และ Embedding เสียงผู้พูด CMU Arctic", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "เวอร์ชัน Open WebUI (v{{OPEN_WEBUI_VERSION}}) ต่ำกว่าเวอร์ชันที่ต้องการ (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "หน้า", "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.": "", "Password": "รหัสผ่าน", "Passwords do not match.": "รหัสผ่านไม่ตรงกัน", "Paste Large Text as File": "วางข้อความขนาดใหญ่เป็นไฟล์", @@ -1260,7 +1295,6 @@ "Pipe": "ท่อ", "Pipeline deleted successfully": "ลบ Pipeline สำเร็จแล้ว", "Pipeline downloaded successfully": "ดาวน์โหลด Pipeline สำเร็จแล้ว", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines เป็นระบบปลั๊กอินที่สามารถรันโค้ดได้อย่างอิสระ —", "Pipelines Not Detected": "ไม่พบ Pipelines", "Pipelines Valves": "วาล์วของ Pipelines", @@ -1497,6 +1531,7 @@ "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 จะหยุดสร้างข้อความและส่งค่ากลับ สามารถตั้งค่ารูปแบบตัวหยุดหลายแบบได้โดยระบุพารามิเตอร์ Stop แยกกันหลายตัวใน Modelfile", "Setting": "", "Settings": "การตั้งค่า", + "Settings Permissions": "", "Settings saved successfully!": "บันทึกการตั้งค่าสำเร็จแล้ว!", "Share": "แชร์", "Share Chat": "แชร์แชท", @@ -1540,6 +1575,7 @@ "Speech recognition error: {{error}}": "ข้อผิดพลาดในการรู้จำเสียง: {{error}}", "Speech-to-Text": "แปลงเสียงเป็นข้อความ", "Speech-to-Text Engine": "เครื่องมือแปลงเสียงเป็นข้อความ", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "เริ่มการสนทนาใหม่", "Start of the channel": "จุดเริ่มต้นของช่อง", "Start Tag": "แท็กเริ่มต้น", @@ -1550,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "ขั้นตอน", "Stop": "หยุด", + "Stop Download": "", "Stop Generating": "หยุดการสร้าง", "Stop Sequence": "ลำดับการหยุด", "Stream Chat Response": "สตรีมการตอบกลับแชท", @@ -1570,7 +1607,14 @@ "Support": "สนับสนุน", "Support this plugin:": "สนับสนุนปลั๊กอินนี้:", "Supported MIME Types": "ชนิด MIME ที่รองรับ", + "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.": "", "System": "ระบบ", "System Instructions": "คำสั่งของระบบ", "System Prompt": "System Prompt", @@ -1615,6 +1659,7 @@ "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.": "", "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}}", @@ -1729,6 +1774,7 @@ "Upload Pipeline": "อัปโหลด Pipeline", "Upload Progress": "ความคืบหน้าการอัปโหลด", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "ความคืบหน้าการอัปโหลด: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "ต้องระบุ URL", @@ -1746,6 +1792,7 @@ "User Groups": "กลุ่มผู้ใช้", "User location successfully retrieved.": "ดึงตำแหน่งที่ตั้งของผู้ใช้สำเร็จแล้ว", "User menu": "เมนูผู้ใช้", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhooks ของผู้ใช้", "Username": "ชื่อผู้ใช้", "users": "", @@ -1795,15 +1842,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI จะส่งคำขอไปยัง \"{{url}}/chat/completions\"", "What are you trying to achieve?": "คุณพยายามจะทำอะไร?", "What are you working on?": "คุณกำลังทำอะไรอยู่?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "มีอะไรใหม่ใน", "What's on your mind?": "", "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 (Local)", + "Who can share to this group": "", "Why?": "ทำไม?", "Widescreen Mode": "โหมดหน้าจอกว้าง", "Width": "ความกว้าง", + "Wikipedia": "", "Won": "ชนะ", "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": "พื้นที่ทำงาน", @@ -1815,6 +1866,8 @@ "Yacy Instance URL": "URL ของ Yacy Instance", "Yacy Password": "รหัสผ่าน Yacy", "Yacy Username": "ชื่อผู้ใช้ Yacy", + "Yahoo": "", + "Yandex": "", "Yesterday": "เมื่อวาน", "Yesterday at {{LOCALIZED_TIME}}": "เมื่อวาน เวลา {{LOCALIZED_TIME}}", "You": "คุณ", @@ -1822,6 +1875,9 @@ "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 save this prompt.": "", "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.": "", @@ -1833,6 +1889,8 @@ "Your Account": "บัญชีของคุณ", "Your account status is currently pending activation.": "สถานะบัญชีของคุณกำลังรอการเปิดใช้งาน", "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.": "", "YouTube": "YouTube", "Youtube Language": "ภาษาของ YouTube", "Youtube Proxy URL": "URL พร็อกซี YouTube" diff --git a/src/lib/i18n/locales/tk-TM/translation.json b/src/lib/i18n/locales/tk-TM/translation.json index 93cd9dd30f..1a2060cf74 100644 --- a/src/lib/i18n/locales/tk-TM/translation.json +++ b/src/lib/i18n/locales/tk-TM/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Bu sazlamalary düzetmek ähli ulanyjylara birmeňzeş üýtgeşmeler girizer.", "admin": "admin", "Admin": "", + "Admin Contact Email": "", "Admin Panel": "Admin Paneli", "Admin Settings": "Admin Sazlamalary", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "", "and create a new shared link.": "we täze paýlaşylan baglanyşyk dörediň.", "Android": "", + "Anyone": "", "API Base URL": "API Esasy URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API Açar", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "", "Auto-playback response": "Awto-gaýtadan jogap", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Esasy URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Esasy URL zerur.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "", "Available Tools": "", "available users": "elýeterli ulanyjylar", @@ -201,6 +204,7 @@ "before": "öň", "Being lazy": "Ýaltalyk", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave Gözleg API Açar", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Täzelenmeleri barla", "Checking for updates...": "Täzelenmeleri barlamak...", "Choose a model before saving...": "Saklamazdan ozal model saýlaň...", + "Chunk Min Size Target": "", "Chunk Overlap": "Bölüm Aşyrmasy", "Chunk Size": "Bölüm Ölçegi", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "", "Citation": "Sitata", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "", "Content": "Mazmuny", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "Jogap Bermegi Dowam et", "Continue with {{provider}}": "", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "Mazada", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Dekabr", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "", - "Documents": "Resminamalar", "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.": "Ynamdar bolmadyk çeşmelerden tötänleýin pipelines almaň.", @@ -493,11 +502,14 @@ "Done": "Tamam", "Download": "", "Download & Delete": "Göçürip al we poz", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "", "Download Database": "", + "Downloading stats...": "", "Draw": "", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "", "Enter Chunk Size": "", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "Fewral", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "", - "Feedbacks": "", "Feel free to add specific details": "", "Female": "", "File": "Faýl", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "", "Folder name updated successfully": "", @@ -826,7 +846,6 @@ "General": "Umumy", "Generate": "Döret", "Generate an image": "", - "Generate Image": "", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "", "Good Response": "", + "Google": "", "Google Drive": "", "Google PSE API Key": "", "Google PSE Engine Id": "", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Topar", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "", "Import": "Import", "Import Chats": "", "Import Config from JSON File": "", @@ -927,6 +947,7 @@ "Integration": "Integrasiýa", "Integrations": "", "Interface": "", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "Ýanwar", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "", "JSON": "", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Mart", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "", "Max Upload Size": "", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "", "May": "Maý", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "", "Memory": "Ýat", "Memory added successfully": "", @@ -1051,6 +1077,7 @@ "Merge Responses": "", "Merged Response": "Birleşdirilen jogap", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "", "Model Params": "", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "Has köp", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "", "No expiration can pose security risks.": "", - "No feedbacks found": "", + "No feedback found": "", "No file selected": "", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Netije ýok", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "", "Oops! There are files still uploading. Please wait for the upload to complete.": "", "Oops! There was an error in the previous response.": "", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "", "OpenAI": "", "OpenAI API": "", @@ -1235,6 +1268,8 @@ "page": "", "Paginate": "", "Parameters": "Parametrler", + "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.": "", "Password": "Parol", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "", "Pipeline downloaded successfully": "", - "Pipelines": "", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines — islendik kody işletmäge mümkinçilik berýän plagin ulgamy —", "Pipelines Not Detected": "", "Pipelines Valves": "", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "Sazlamalar", + "Settings Permissions": "", "Settings saved successfully!": "", "Share": "Paýlaş", "Share Chat": "Çaty Paýlaş", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "", "Speech-to-Text": "", "Speech-to-Text Engine": "", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Kanal başy", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Bes et", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "", "Stream Chat Response": "", @@ -1571,7 +1608,14 @@ "Support": "Goldaw", "Support this plugin:": "", "Supported MIME Types": "", + "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.": "", "System": "Sistema", "System Instructions": "", "System Prompt": "", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "", "Upload Progress": "", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Ulanyjy Ady", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "", "What's on your mind?": "", "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.": "", "Whisper (Local)": "", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "", "Width": "", + "Wikipedia": "", "Won": "", "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.": "", "Workspace": "", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Düýn", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "", "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.": "", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index 423c5359aa..0e8830693e 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Bu ayarların yapılması, değişiklikleri tüm kullanıcılara evrensel olarak uygulayacaktır.", "admin": "yönetici", "Admin": "Yönetici", + "Admin Contact Email": "", "Admin Panel": "Yönetici Paneli", "Admin Settings": "Yönetici Ayarları", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Yöneticiler her zaman tüm araçlara erişebilir; kullanıcıların çalışma alanındaki model başına atanmış araçlara ihtiyacı vardır.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "Mesaj Silmeye İzin Ver", "Allow File Upload": "Dosya Yüklemeye İzin Ver", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Sohbette Birden Fazla Modele İzin Ver", "Allow non-local voices": "Yerel olmayan seslere izin verin", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "ve {{COUNT}} daha", "and create a new shared link.": "ve yeni bir paylaşılan bağlantı oluşturun.", "Android": "Android", + "Anyone": "", "API Base URL": "API Temel URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API Anahtarı", @@ -175,6 +176,7 @@ "Authenticate": "Kimlik Doğrulama", "Authentication": "Kimlik Doğrulama", "Auto": "Otomatik", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Yanıtı Panoya Otomatik Kopyala", "Auto-playback response": "Yanıtı otomatik oynatma", "Autocomplete Generation": "Otomatik Tamamlama Üretimi", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 API Kimlik Doğrulama Dizesi", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Temel URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Temel URL gereklidir.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Mevcut liste", "Available Tools": "Mevcut Araçlar", "available users": "kullanılabilir kullanıcılar", @@ -201,6 +204,7 @@ "before": "önce", "Being lazy": "Tembelleşiyor", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Arama V7 Uç Noktası", "Bing Search V7 Subscription Key": "Bing Arama V7 Abonelik Anahtarı", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Arama API Anahtarı", "Bold": "Kalın", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "Brave Search API Anahtarı", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Güncellemeleri kontrol et", "Checking for updates...": "Güncellemeler kontrol ediliyor...", "Choose a model before saving...": "Kaydetmeden önce bir model seçin...", + "Chunk Min Size Target": "", "Chunk Overlap": "Chunk Çakışması", "Chunk Size": "Chunk Boyutu", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Şifreler", "Citation": "Alıntı", "Citations": "Alıntılar", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Kod yürütme", - "Code Execution": "Kod Çalıştırma", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "Kod başarıyla biçimlendirildi", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "WebUI Erişimi için Yöneticiyle İletişime Geçin", "Content": "İçerik", "Content Extraction Engine": "İçerik Çıkarma Motoru", + "Content lengths (character counts only)": "", "Continue Response": "Yanıta Devam Et", "Continue with {{provider}}": "{{provider}} ile devam et", "Continue with Email": "E-posta ile devam edin", @@ -393,6 +401,7 @@ "Database": "Veritabanı", "Datalab Marker API": "", "DD/MM/YYYY": "GG/AA/YYYY", + "DDGS Backend": "", "December": "Aralık", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Bilgiye dalmak", "Do not install functions from sources you do not fully trust.": "Tamamen güvenmediğiniz kaynaklardan fonksiyonlar yüklemeyin.", "Do not install tools from sources you do not fully trust.": "Tamamen güvenmediğiniz kaynaklardan araçlar yüklemeyin.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Dökümantasyon", - "Documents": "Belgeler", "does not make any external connections, and your data stays securely on your locally hosted server.": "herhangi bir harici bağlantı yapmaz ve verileriniz güvenli bir şekilde yerel olarak barındırılan sunucunuzda kalır.", "Domain Filter List": "", "don't fetch random pipelines from sources you don't trust.": "Güvenmediğiniz kaynaklardan rastgele pipelines getirmeyin.", @@ -493,11 +502,14 @@ "Done": "Tamamlandı", "Download": "İndir", "Download & Delete": "İndir ve Sil", + "Download as JSON": "", "Download as SVG": "SVG olarak İndir", "Download canceled": "İndirme iptal edildi", "Download Database": "Veritabanını İndir", + "Downloading stats...": "", "Draw": "Çiz", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "örn. '30s', '10m'. Geçerli zaman birimleri 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "örn. \"json\" veya JSON şablonu", "e.g. 60": "örn. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "Brave Search API Anahtarını Girin", "Enter certificate path": "Sertifika yolunu girin", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Chunk Örtüşmesini Girin", "Enter Chunk Size": "Chunk Boyutunu Girin", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Github Raw URL'sini girin", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Görüntü Boyutunu Girin (örn. 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina API Anahtarını Girin", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search API Anahtarını Girin", "Enter Key Behavior": "", "Enter language codes": "Dil kodlarını girin", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Model ID'sini Girin", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Özellikler", "Features Permissions": "Özellik Yetkileri", "February": "Şubat", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Geri Bildirim Geçmişi", - "Feedbacks": "Geri Bildirimler", "Feel free to add specific details": "Spesifik ayrıntılar eklemekten çekinmeyin", "Female": "", "File": "Dosya", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Parmak izi sahteciliği tespit edildi: Avatar olarak baş harfler kullanılamıyor. Varsayılan profil resmine dönülüyor.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "Klasör", "Folder Background Image": "Klasör Arka Plan Resmi", "Folder deleted successfully": "Klasör başarıyla silindi", + "Folder Max File Count": "", "Folder Name": "Klasör Adı", "Folder name cannot be empty.": "Klasör adı boş olamaz.", "Folder name updated successfully": "Klasör adı başarıyla güncellendi", @@ -826,7 +846,6 @@ "General": "Genel", "Generate": "Oluştur", "Generate an image": "Bir Görsel Oluştur", - "Generate Image": "Görsel Üret", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Arama sorgusu oluşturma", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}} ile başlayın", "Global": "Evrensel", "Good Response": "İyi Yanıt", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API Anahtarı", "Google PSE Engine Id": "Google PSE Engine Id", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Grup", "Group Channel": "", "Group created successfully": "Grup başarıyla oluşturuldu", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "Görüntüler", "Import": "İçe Aktar", "Import Chats": "Sohbetleri İçe Aktar", "Import Config from JSON File": "Yapılandırmayı JSON Dosyasından İçe Aktar", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "Arayüz", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Geçersiz dosya biçimi.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "yazıyor...", "Italic": "", "January": "Ocak", + "Jina API Base URL": "", "Jina API Key": "Jina API Anahtarı", "join our Discord for help.": "yardım için Discord'umuza katılın.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "Tüm modelleri dahil etmek için boş bırakın veya belirli modelleri seçin", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Varsayılan promptu kullanmak için boş bırakın veya özel bir prompt girin", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Mart", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Maksimum Yükleme Sayısı", "Max Upload Size": "Maksimum Yükleme Boyutu", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Aynı anda en fazla 3 model indirilebilir. Lütfen daha sonra tekrar deneyin.", "May": "Mayıs", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLM'ler tarafından erişilebilen bellekler burada gösterilecektir.", "Memory": "Bellek", "Memory added successfully": "Bellek başarıyla eklendi", @@ -1051,6 +1077,7 @@ "Merge Responses": "Yanıtları Birleştir", "Merged Response": "Birleştirilmiş Yanıt", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Bu özelliği kullanmak için mesaj derecelendirmesi etkinleştirilmelidir", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Bağlantınızı oluşturduktan sonra gönderdiğiniz mesajlar paylaşılmayacaktır. URL'ye sahip kullanıcılar paylaşılan sohbeti görüntüleyebilecektir.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Model Adı", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model seçilmedi", "Model Params": "Model Parametreleri", "Model Permissions": "Model İzinleri", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Model başarıyla güncellendi", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search API Anahtarı", "More": "Daha Fazla", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Mesafe mevcut değil", "No expiration can pose security risks.": "", - "No feedbacks found": "Geri bildirim bulunamadı", + "No feedback found": "", "No file selected": "Hiçbir dosya seçilmedi", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Model seçilmedi", "No Notes": "Not Yok", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Sonuç bulunamadı", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Yalnızca markdown biçimli dosyalar kullanılabilir", "Only select users and groups with permission can access": "İzinli kullanıcılar ve gruplar yalnızca erişebilir", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Hop! URL geçersiz gibi görünüyor. Lütfen tekrar kontrol edin ve yeniden deneyin.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Hop! Hala yüklenen dosyalar var. Yüklemenin tamamlanmasını bekleyin.", "Oops! There was an error in the previous response.": "Hop! Önceki yanıtta bir hata oluştu.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI OpenAPI tarafından sağlanan araçları kullanabilir", "Open WebUI uses faster-whisper internally.": "Open WebUI, dahili olarak daha hızlı-fısıltı kullanır.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI, SpeechT5 ve CMU Arctic konuşmacı gömme kullanır.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open-WebUI sürümü (v{{OPEN_WEBUI_VERSION}}) gerekli sürümden (v{{REQUIRED_VERSION}}) düşük", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "sayfa", "Paginate": "", "Parameters": "Parametreler", + "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.": "", "Password": "Parola", "Passwords do not match.": "Parolalar eşleşmiyor.", "Paste Large Text as File": "Büyük Metni Dosya Olarak Yapıştır", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Pipeline başarıyla silindi", "Pipeline downloaded successfully": "Pipeline başarıyla güncellendi", - "Pipelines": "Pipelinelar", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines, keyfi kod çalıştırmaya izin veren bir eklenti sistemidir —", "Pipelines Not Detected": "Pipeline Tespit Edilmedi", "Pipelines Valves": "Pipeline Valvleri", @@ -1498,6 +1532,7 @@ "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.": "Kullanılacak durma dizilerini ayarlar. Bu desenle karşılaşıldığında, LLM metin oluşturmayı durduracak ve geri dönecektir. Birden çok durma deseni, bir modelfile'da birden çok ayrı durma parametresi belirterek ayarlanabilir.", "Setting": "", "Settings": "Ayarlar", + "Settings Permissions": "", "Settings saved successfully!": "Ayarlar başarıyla kaydedildi!", "Share": "Paylaş", "Share Chat": "Sohbeti Paylaş", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Konuşma tanıma hatası: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Konuşmadan Metne Motoru", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Kanalın başlangıcı", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Durdur", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Diziyi Durdur", "Stream Chat Response": "Akış Sohbet Yanıtı", @@ -1571,7 +1608,14 @@ "Support": "Destek", "Support this plugin:": "Bu eklentiyi destekleyin:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Dizini senkronize et", + "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": "Sistem", "System Instructions": "Sistem Talimatları", "System Prompt": "Sistem Promptu", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Tema", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Düşünüyor...", "This action cannot be undone. Do you wish to continue?": "Bu eylem geri alınamaz. Devam etmek istiyor musunuz?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Pipeline Yükle", "Upload Progress": "Yükleme İlerlemesi", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "URL gerekli", @@ -1747,6 +1793,7 @@ "User Groups": "Kullanıcı Grupları", "User location successfully retrieved.": "Kullanıcı konumu başarıyla alındı.", "User menu": "Kullanıcı menüsü", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "Kullanıcı Adı", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI, \"{{url}}/chat/completions\" adresine istek yapacak", "What are you trying to achieve?": "Ne yapmaya çalışıyorsunuz?", "What are you working on?": "Üzerinde çalıştığınız nedir?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Yenilikler:", "What's on your mind?": "", "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.": "Etkinleştirildiğinde, model her sohbet mesajına gerçek zamanlı olarak yanıt verecek ve kullanıcı bir mesaj gönderdiği anda bir yanıt üretecektir. Bu mod canlı sohbet uygulamaları için yararlıdır, ancak daha yavaş donanımlarda performansı etkileyebilir.", "wherever you are": "nerede olursanız olun", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", "Whisper (Local)": "Whisper (Yerel)", + "Who can share to this group": "", "Why?": "Neden?", "Widescreen Mode": "Geniş Ekran Modu", "Width": "", + "Wikipedia": "", "Won": "kazandı", "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.": "", "Workspace": "Çalışma Alanı", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "Yacy Parolası", "Yacy Username": "Yacy Kullanıcı Adı", + "Yahoo": "", + "Yandex": "", "Yesterday": "Dün", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Sen", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Aynı anda en fazla {{maxCount}} dosya ile sohbet edebilirsiniz.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Aşağıdaki 'Yönet' düğmesi aracılığıyla bellekler ekleyerek LLM'lerle etkileşimlerinizi kişiselleştirebilir, onları daha yararlı ve size özel hale getirebilirsiniz.", "You cannot upload an empty file.": "Boş bir dosya yükleyemezsiniz.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "Hesabınız", "Your account status is currently pending activation.": "Hesap durumunuz şu anda etkinleştirilmeyi bekliyor.", "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.": "Tüm katkınız doğrudan eklenti geliştiricisine gidecektir; Open WebUI herhangi bir yüzde almaz. Ancak seçilen finansman platformunun kendi ücretleri olabilir.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube Dili", "Youtube Proxy URL": "Youtube Vekil URL'si" diff --git a/src/lib/i18n/locales/ug-CN/translation.json b/src/lib/i18n/locales/ug-CN/translation.json index b47fc630fd..20f8fa4277 100644 --- a/src/lib/i18n/locales/ug-CN/translation.json +++ b/src/lib/i18n/locales/ug-CN/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "بۇ تەڭشەكتىكى ئۆزگەرتىشلەر بارلىق ئىشلەتكۈچىلەرگە قوللىنىلىدۇ.", "admin": "باشقۇرغۇچى", "Admin": "باشقۇرغۇچى", + "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.": "باشقۇرغۇچىلارنىڭ ھەممىسى قوراللارنى تولۇق ئىشلىتىش ھوقۇقىغا ئىگە؛ ئىشلەتكۈچىلەرنىڭ ئىشخانىدا مودېلغا باغلانغان قوراللار بولۇشى كېرەك.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "ھۆججەت چىقىرىشقا ئىجازەت", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "سۆھبەتتە بىر قانچە مودېل ئىشلىتىشكە ئىجازەت", "Allow non-local voices": "يەرلىك بولمىغان ئاۋازلارغا ئىجازەت", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "ۋە يەنە {{COUNT}}", "and create a new shared link.": "يېڭى ھەمبەھىرلەنگەن ئۇلانما قۇرۇڭ.", "Android": "Android", + "Anyone": "", "API Base URL": "API ئاساسىي URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API ئاچقۇچى", @@ -175,6 +176,7 @@ "Authenticate": "دەلىللەش", "Authentication": "كىرىش دەلىللەش", "Auto": "ئاپتوماتىك", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "ئىنكاسنى ئۆزلۈكىدىن چاپلاش تاختىسىغا كۆچۈرۈش", "Auto-playback response": "ئاپتۇماتىك قۇيۇش ئىنكاسى", "Autocomplete Generation": "ئاپتوماتىك تولدۇرۇش", @@ -183,6 +185,7 @@ "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.)": "", "Available list": "بار تىزىملىك", "Available Tools": "بار قوراللار", "available users": "ئىشلەتكىلى بولىدىغان ئىشلەتكۈچىلەر", @@ -201,6 +204,7 @@ "before": "بۇرۇن", "Being lazy": "ھورۇن بۇلۇش", "Beta": "بەتا", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 ئۇلانمىسى", "Bing Search V7 Subscription Key": "Bing Search V7 ئەزا ئاچقۇچى", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha ئىزدەش 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 Search API Key": "Brave ئىزدەش API ئاچقۇچى", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "يېڭىلاشنى تەكشۈرۈش", "Checking for updates...": "يېڭىلاشلار تەكشۈرۈلمەكتە...", "Choose a model before saving...": "ساقلاشتىن بۇرۇن مودېل تاللاڭ...", + "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.": "", "Ciphers": "شىفىرلار", "Citation": "نەقىل", "Citations": "نەقىللەر", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "كود ئىجرا قىلىش", - "Code Execution": "كود ئىجرا قىلىش", "Code Execution Engine": "كود ئىجرا ماتورى", "Code Execution Timeout": "كود ئىجرا ۋاقىت چەكلىمىسى", "Code formatted successfully": "كود مۇۋەپپەقىيەتلىك فورماتلاندى", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "WebUI كىرىش ئۈچۈن باشقۇرغۇچى بىلەن ئالاقىلىشىڭ", "Content": "مەزمۇن", "Content Extraction Engine": "مەزمۇن چىقىرىش ماتورى", + "Content lengths (character counts only)": "", "Continue Response": "ئىنكاسنى داۋاملاشتۇرۇش", "Continue with {{provider}}": "{{provider}} داۋاملاشتۇرۇش", "Continue with Email": "ئېلخەت بىلەن داۋاملاشتۇرۇش", @@ -393,6 +401,7 @@ "Database": "ساندان", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "دېكابىر", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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", "Docling Parameters": "", "Docling Server URL required.": "Docling مۇلازىمېتىر URL زۆرۈر.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "ئىشلەتكۈچى قوللانمىسى", - "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.": "ئىشەنچسىز مەنبەلەردىن خالىغان pipelines نى ئالماڭ.", @@ -493,11 +502,14 @@ "Done": "تامام", "Download": "چۈشۈرۈش", "Download & Delete": "چۈشۈرۈش ۋە ئۆچۈرۈش", + "Download as JSON": "", "Download as SVG": "SVG شەكلىدە چۈشۈرۈش", "Download canceled": "چۈشۈرۈش بىكار قىلىندى", "Download Database": "ساندان چۈشۈرۈش", + "Downloading stats...": "", "Draw": "سىزىش", "Drop any files here to upload": "ھەر قانداق ھۆججەتنى بۇ يەرگە قويۇپ يۈكلەڭ", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "مەسىلەن: '30s', '10m'. توغرا ۋاقىت بىرلىكى: 's' (سېكۇنت), 'm' (مىنۇت), 'h' (سائەت).", "e.g. \"json\" or a JSON schema": "مەسىلەن: \"json\" ياكى JSON قېلىپى", "e.g. 60": "مەسىلەن: 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Bocha ئىزدەش API ئاچقۇچى كىرگۈزۈڭ", "Enter Brave Search API Key": "Brave ئىزدەش API ئاچقۇچى كىرگۈزۈڭ", "Enter certificate path": "سىرتىفىكات يولى كىرگۈزۈڭ", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "پارچە قاپلىنىشى كىرگۈزۈڭ", "Enter Chunk Size": "پارچە چوڭلۇقى كىرگۈزۈڭ", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "پۈتتۈر بىلەن ئايرىلغان \"token:bias_value\" جۈپىنى كىرگۈزۈڭ (مەسىلەن: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "سىرتقى تور ئىزدەش URL كىرگۈزۈڭ", "Enter Firecrawl API Base URL": "Firecrawl API ئاساسىي URL كىرگۈزۈڭ", "Enter Firecrawl API Key": "Firecrawl API ئاچقۇچى كىرگۈزۈڭ", + "Enter Firecrawl Timeout": "", "Enter folder name": "", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Github Raw URL كىرگۈزۈڭ", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "رەسىم چوڭلۇقى كىرگۈزۈڭ (مەسىلەن: 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina API ئاچقۇچى كىرگۈزۈڭ", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Jupyter پارول كىرگۈزۈڭ", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi ئىزدەش API ئاچقۇچى كىرگۈزۈڭ", "Enter Key Behavior": "ئاچقۇچ ئىشلىتىش ئۇسۇلى كىرگۈزۈڭ", "Enter language codes": "تىل كودلىرى كىرگۈزۈڭ", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Mistral API ئاچقۇچى كىرگۈزۈڭ", "Enter Model ID": "مودېل ID كىرگۈزۈڭ", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "ھۆججەت مەزمۇنى يۈكلەش مەغلۇپ بولدى.", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "ئىقتىدارلار", "Features Permissions": "ئىقتىدار ھوقۇقى", "February": "فېۋرال", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "پىكىر تەپسىلاتى", "Feedback History": "پىكىر تارىخى", - "Feedbacks": "پىكىرلەر", "Feel free to add specific details": "تەپسىلىي ئۇچۇر قوشسىڭىز بولىدۇ", "Female": "", "File": "ھۆججەت", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "بارماق ئىزى ئالدامچىلىقى بايقالدى: دەسلەپتىكىنى ئاۋاتار قىلغىلى بولمىدى. كۆڭۈلدىكى پىروفىل رەسىمى ئىشلىتىلىدۇ. ", "Firecrawl API Base URL": "Firecrawl API ئاساسىي URL", "Firecrawl API Key": "Firecrawl API ئاچقۇچى", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "قىسقۇچ مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "قىسقۇچ ئاتى بوش بولسا بولمايدۇ.", "Folder name updated successfully": "قىسقۇچ ئاتى مۇۋەپپەقىيەتلىك يېڭىلاندى", @@ -826,7 +846,6 @@ "General": "ئادەتتىكى", "Generate": "ھاسىل قىلىش", "Generate an image": "رەسىم ھاسىل قىلىش", - "Generate Image": "رەسىم ھاسىل قىلىش", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "ئىزدەش سۇئالى ھاسىل قىلىنىۋاتىدۇ", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}} بىلەن باشلاڭ", "Global": "ئۇمۇمىي", "Good Response": "ياخشى ئىنكاس", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API ئاچقۇچى", "Google PSE Engine Id": "Google PSE ماتور ID", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "گۇرۇپپا", "Group Channel": "", "Group created successfully": "گۇرۇپپا مۇۋەپپەقىيەتلىك قۇرۇلدى", @@ -895,7 +916,6 @@ "Image Prompt Generation": "رەسىم تۈرتكەسى ھاسىل قىلىش", "Image Prompt Generation Prompt": "رەسىم تۈرتكەسى ھەققىدە تۈرتكە", "Image Size": "", - "Images": "رەسىملەر", "Import": "ئىمپورت قىلىش", "Import Chats": "سۆھبەتلەرنى ئىمپورت قىلىش", "Import Config from JSON File": "JSON ھۆججىتىدىن تەڭشەك ئىمپورت قىلىش", @@ -927,6 +947,7 @@ "Integration": "بىرىكتۈرۈش", "Integrations": "", "Interface": "يۈز", + "Interface Settings Access": "", "Invalid file content": "ھۆججەت مەزمۇنى خاتا", "Invalid file format.": "ھۆججەت قېلىپى خاتا.", "Invalid JSON file": "JSON ھۆججىتى خاتا", @@ -940,6 +961,7 @@ "is typing...": "يازماقتا...", "Italic": "", "January": "يانۋار", + "Jina API Base URL": "", "Jina API Key": "Jina API ئاچقۇچى", "join our Discord for help.": "ياردەم ئۈچۈن Discord غا قوشۇلىڭ.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "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 model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "كۆڭۈلدىكى تۈرتكە ئۈچۈن بوش قالدۇرۇڭ ياكى ئۆزلۈك تۈرتكە كىرگۈزۈڭ", "Leave model field empty to use the default model.": "كۆڭۈلدىكى مودېل ئۈچۈن مودېل رايونىنى بوش قالدۇرۇڭ.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "مارت", "Markdown": "Markdown", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "ئەڭ كۆپ سۆزلىگۈچىلەر", "Max Upload Count": "ئەڭ كۆپ چىقىرىش سانى", "Max Upload Size": "ئەڭ چوڭ چىقىرىش چوڭلۇقى", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "بىر ۋاقىتتا ئەڭ كۆپ 3 مودېل چۈشۈرۈلىدۇ. كىيىنچە قايتا سىناڭ.", "May": "ماي", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLM ئىشلىتەلەيدىن ئەسلەتمىلەر بۇ يەردە كۆرۈنىدۇ.", "Memory": "ئەسلەتمە", "Memory added successfully": "ئەسلەتمە مۇۋەپپەقىيەتلىك قوشۇلدى", @@ -1051,6 +1077,7 @@ "Merge Responses": "ئىنكاسلارنى بىرلەشتۈرۈش", "Merged Response": "بىرلەشتۈرۈلگەن ئىنكاس", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "بۇ ئىقتىدار ئۈچۈن ئۇچۇر باھالاشنى قوزغىتىڭ", "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", @@ -1083,9 +1110,11 @@ "Model Name": "مودېل نامى", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "مودېل تاللانمىغان", "Model Params": "مودېل پارامېتىرلىرى", "Model Permissions": "مودېل ھوقۇقى", + "Model responses or outputs": "", "Model unloaded successfully": "مودېل مۇۋەپپەقىيەتلىك چىقىرىلدى", "Model updated successfully": "مودېل مۇۋەپپەقىيەتلىك يېڭىلاندى", "Model(s) do not support file upload": "مودېل(لار) ھۆججەت چىقىرىشنى قوللىمايدۇ", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "مودېللارنى ئاممىغا ھەمبەھىرلەش", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek ئىزدەش API ئاچقۇچى", "More": "تېخىمۇ كۆپ", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "ئارىلىق ئۇچۇرى يوق", "No expiration can pose security risks.": "", - "No feedbacks found": "پىكىرلەر تېپىلمىدى", + "No feedback found": "", "No file selected": "ھۆججەت تاللانمىدى", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "مودېل تاللانمىدى", "No Notes": "خاتىرە يوق", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "نەتىجە تېپىلمىدى", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "پەقەت markdown ھۆججىتى ئىشلىتىشكە بولىدۇ", "Only select users and groups with permission can access": "پەقەت ھوقۇقى بار تاللانغان ئىشلەتكۈچى ۋە گۇرۇپپىلارلا زىيارەت قىلالايدۇ", + "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.": "ئالدىنقى ئىنكاستا خاتالىق يۈز بەردى.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI ھەر قانداق OpenAPI مۇلازىمېتىرلىرىدىكى قوراللارنى ئىشلىتەلىدۇ.", "Open WebUI uses faster-whisper internally.": "Open WebUI ئىچىدە faster-whisper ئىشلىتىدۇ.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI SpeechT5 ۋە CMU Arctic ئاۋاز سىڭدۈرۈش ئىشلىتىدۇ.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI نەشرى (v{{OPEN_WEBUI_VERSION}}) تەلەپ قىلىنغان نەشردىن (v{{REQUIRED_VERSION}}) تۆۋەن.", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "بەت", "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.": "", "Password": "پارول", "Passwords do not match.": "", "Paste Large Text as File": "چوڭ تېكستنى ھۆججەت قىلىپ چاپلا", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "جەريان مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى", "Pipeline downloaded successfully": "جەريان مۇۋەپپەقىيەتلىك چۈشۈرۈلدى", - "Pipelines": "جەريانلار", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines — خالىغان كود ئىجرا قىلىشقا ئىجازەت بېرىدىغان قىستۇرما سىستېمىسى —", "Pipelines Not Detected": "جەريان تېپىلمىدى", "Pipelines Valves": "جەريان كرانلىرى", @@ -1498,6 +1532,7 @@ "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 تېكست چىقىرىشنى توختىتىدۇ. بىر قانچە توختاش ئۇسلۇبنى modelfile دا كۆرسىتىشكە بولىدۇ.", "Setting": "", "Settings": "تەڭشەك", + "Settings Permissions": "", "Settings saved successfully!": "تەڭشەك مۇۋەپپەقىيەتلىك ساقلاندى!", "Share": "ھەمبەھىرلەش", "Share Chat": "سۆھبەت ھەمبەھىرلەش", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "ئاۋازنى تونۇش خاتالىقى: {{error}}", "Speech-to-Text": "ئاۋازدىن تېكستكە", "Speech-to-Text Engine": "ئاۋازدىن تېكستكە ماتورى", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "قانالنىڭ باشلانغىنى", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "توختات", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "توختاش تىزىقى", "Stream Chat Response": "سۆھبەت ئىنكاسىنى ئېقىم قىلىش", @@ -1571,7 +1608,14 @@ "Support": "ياردەم", "Support this plugin:": "بۇ قىستۇرما ئۈچۈن ياردەم قىلىڭ:", "Supported MIME Types": "قوللايدىغان MIME تىپى", + "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.": "", "System": "سىستېما", "System Instructions": "سىستېما كۆرسىتىلمىسى", "System Prompt": "سىستېما تۈرتكەسى", @@ -1616,6 +1660,7 @@ "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.": "رەسىم پرىسلاش كەڭلىكى (پېكسېل). پرىسلاش بولمىسا بوش قالدۇرۇڭ.", "Theme": "ئۈسلۇب", + "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}} قانالىنىڭ باشلىنىشى.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "جەريان چىقىرىش", "Upload Progress": "چىقىرىش جەريانى", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "ئىشلەتكۈچى ئورنى مۇۋەپپەقىيەتلىك ئېلىندى.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "ئىشلەتكۈچى Webhookلىرى", "Username": "ئىشلەتكۈچى نامى", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" غا تەلەپ يوللايدۇ", "What are you trying to achieve?": "نېمىگە ئېرىشمىكچىسىز؟", "What are you working on?": "نېمە ئىش قىلىۋاتىسىز؟", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "يېڭىلىق", "What's on your mind?": "", "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.": "چىقىرىشنى بەتلەندۈرۈش ئۈچۈن ئىشلىتىلدۇ. ھەربىر بەت گىزىكچىلەر بىلەن ئايرىلىدۇ. كۆڭۈلدىكىچە چەكلەنگەن.", "Whisper (Local)": "Whisper (يەرلىك)", + "Who can share to this group": "", "Why?": "نېمىشقا؟", "Widescreen Mode": "كەڭ ئېكران ھالىتى", "Width": "", + "Wikipedia": "", "Won": "ئۇتتى", "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": "ئىشخانا", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy مىسال URL", "Yacy Password": "Yacy پارول", "Yacy Username": "Yacy ئىشلەتكۈچى نامى", + "Yahoo": "", + "Yandex": "", "Yesterday": "تۈنۈگۈن", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "سىز", @@ -1823,6 +1876,9 @@ "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "ھېساباتىڭىزنىڭ ھازىرقى ھالىتى ئاكتىپلىنىشنى كۈتۈۋاتىدۇ.", "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.": "", "YouTube": "Youtube", "Youtube Language": "Youtube تىلى", "Youtube Proxy URL": "Youtube ۋاكالەتچى URL" diff --git a/src/lib/i18n/locales/uk-UA/translation.json b/src/lib/i18n/locales/uk-UA/translation.json index 076f815331..8510a17da7 100644 --- a/src/lib/i18n/locales/uk-UA/translation.json +++ b/src/lib/i18n/locales/uk-UA/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Зміни в цих налаштуваннях будуть застосовані для всіх користувачів.", "admin": "адмін", "Admin": "Адмін", + "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.": "Адміністратори мають доступ до всіх інструментів у будь-який час; користувачам потрібні інструменти, призначені для кожної моделі в робочій області.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Дозволити завантаження файлів", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Дозволити не локальні голоси", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "та ще {{COUNT}}", "and create a new shared link.": "і створіть нове спільне посилання.", "Android": "", + "Anyone": "", "API Base URL": "URL-адреса API", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Ключ API", @@ -175,6 +176,7 @@ "Authenticate": "Автентифікувати", "Authentication": "Аутентифікація", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Автокопіювання відповіді в буфер обміну", "Auto-playback response": "Автоматичне відтворення відповіді", "Autocomplete Generation": "Генерація автозаповнення", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Рядок авторизації API", "AUTOMATIC1111 Base URL": "URL-адреса AUTOMATIC1111", "AUTOMATIC1111 Base URL is required.": "Необхідна URL-адреса AUTOMATIC1111.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Список доступності", "Available Tools": "", "available users": "доступні користувачі", @@ -201,6 +204,7 @@ "before": "до того, як", "Being lazy": "Не поспішати", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Точка доступу Bing Search V7", "Bing Search V7 Subscription Key": "Ключ підписки Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Ключ API пошуку Bocha", "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 Search API Key": "Ключ API пошуку Brave", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Перевірити оновлення", "Checking for updates...": "Перевірка оновлень...", "Choose a model before saving...": "Оберіть модель перед збереженням...", + "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.": "", "Ciphers": "Шифри", "Citation": "Цитування", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Виконання коду", - "Code Execution": "Виконання коду", "Code Execution Engine": "Рушій виконання коду", "Code Execution Timeout": "Тайм-аут виконання коду", "Code formatted successfully": "Код успішно відформатовано", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Зверніться до адміна для отримання доступу до WebUI", "Content": "Зміст", "Content Extraction Engine": "Рушій вилучення контенту", + "Content lengths (character counts only)": "", "Continue Response": "Продовжити відповідь", "Continue with {{provider}}": "Продовжити з {{provider}}", "Continue with Email": "Продовжити з електронною поштою", @@ -393,6 +401,7 @@ "Database": "База даних", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Грудень", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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", "Docling Parameters": "", "Docling Server URL required.": "Потрібна URL-адреса сервера Docling.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Документація", - "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.": "Не отримуйте випадкові pipelines із джерел, яким ви не довіряєте.", @@ -493,11 +502,14 @@ "Done": "Готово", "Download": "Завантажити", "Download & Delete": "Завантажити та видалити", + "Download as JSON": "", "Download as SVG": "Завантажити як SVG", "Download canceled": "Завантаження скасовано", "Download Database": "Завантажити базу даних", + "Downloading stats...": "", "Draw": "Малювати", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "напр., '30s','10m'. Дійсні одиниці часу: 'с', 'хв', 'г'.", "e.g. \"json\" or a JSON schema": "напр., \"json\" або схема JSON", "e.g. 60": "напр. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Введіть ключ API Bocha Search", "Enter Brave Search API Key": "Введіть ключ API для пошуку Brave", "Enter certificate path": "Введіть шлях до сертифіката", + "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)", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Введіть Raw URL-адресу Github", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Введіть розмір зображення (напр., 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Введіть ключ API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Введіть пароль Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Введіть ключ API Kagi Search", "Enter Key Behavior": "Введіть поведінку клавіші", "Enter language codes": "Введіть мовні коди", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "Введіть ID моделі", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Особливості", "Features Permissions": "Дозволи функцій", "February": "Лютий", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Історія відгуків", - "Feedbacks": "Відгуки", "Feel free to add specific details": "Не соромтеся додавати конкретні деталі", "Female": "", "File": "Файл", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Виявлено підробку відбитків: Неможливо використовувати ініціали як аватар. Повернення до зображення профілю за замовчуванням.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Папку успішно видалено", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Назва папки не може бути порожньою.", "Folder name updated successfully": "Назву папки успішно оновлено", @@ -826,7 +846,6 @@ "General": "Загальні", "Generate": "", "Generate an image": "Згенерувати зображення", - "Generate Image": "Створити зображення", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Сформувати пошуковий запит", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Почати з {{WEBUI_NAME}}", "Global": "Глоб.", "Good Response": "Гарна відповідь", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Ключ API Google PSE", "Google PSE Engine Id": "Id рушія Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Група", "Group Channel": "", "Group created successfully": "Групу успішно створено", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Генерація підказок для зображень", "Image Prompt Generation Prompt": "Підказка для генерації зображень", "Image Size": "", - "Images": "Зображення", "Import": "", "Import Chats": "Імпорт чатів", "Import Config from JSON File": "Імпорт конфігурації з файлу JSON", @@ -927,6 +947,7 @@ "Integration": "Інтеграція", "Integrations": "", "Interface": "Інтерфейс", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Неправильний формат файлу.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "друкує...", "Italic": "", "January": "Січень", + "Jina API Base URL": "", "Jina API Key": "Ключ API для Jina", "join our Discord for help.": "приєднуйтеся до нашого Discord для допомоги.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "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 model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Залиште порожнім для використання стандартного запиту, або введіть власний запит", "Leave model field empty to use the default model.": "Залиште поле моделі порожнім, щоб використовувати модель за замовчуванням.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Березень", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Макс. кількість завантажень", "Max Upload Size": "Макс. розмір завантаження", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Максимум 3 моделі можна завантажити одночасно. Будь ласка, спробуйте пізніше.", "May": "Травень", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Пам'ять, яка доступна LLM, буде показана тут.", "Memory": "Пам'ять", "Memory added successfully": "Пам'ять додано успішно", @@ -1051,6 +1077,7 @@ "Merge Responses": "Об'єднати відповіді", "Merged Response": "Об'єднана відповідь", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Оцінювання повідомлень має бути увімкнено для використання цієї функції.", "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": "", @@ -1083,9 +1110,11 @@ "Model Name": "Назва моделі", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Модель не вибрана", "Model Params": "Параметри моделі", "Model Permissions": "Дозволи моделей", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Модель успішно оновлено", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Публічний обмін моделями", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "API ключ для пошуку Mojeek", "More": "Більше", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Відстань недоступна", "No expiration can pose security risks.": "", - "No feedbacks found": "Відгуків не знайдено", + "No feedback found": "", "No file selected": "Файл не обрано", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Моделі не вибрано", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Не знайдено жодного результату", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Тільки вибрані користувачі та групи з дозволом можуть отримати доступ", + "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.": "Упс! Сталася помилка в попередній відповіді.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI використовує faster-whisper внутрішньо.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI використовує вбудовування голосів SpeechT5 та CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Open WebUI версія (v{{OPEN_WEBUI_VERSION}}) нижча за необхідну версію (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "сторінка", "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.": "", "Password": "Пароль", "Passwords do not match.": "", "Paste Large Text as File": "Вставити великий текст як файл", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Конвеєр успішно видалено", "Pipeline downloaded successfully": "Конвеєр успішно завантажено", - "Pipelines": "Конвеєри", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines — це система плагінів із довільним виконанням коду —", "Pipelines Not Detected": "Конвеєрів не знайдено", "Pipelines Valves": "Клапани конвеєрів", @@ -1500,6 +1534,7 @@ "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 saved successfully!": "Налаштування успішно збережено!", "Share": "Поділитися", "Share Chat": "Поділитися чатом", @@ -1543,6 +1578,7 @@ "Speech recognition error: {{error}}": "Помилка розпізнавання мови: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Система розпізнавання мови", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Початок каналу", "Start Tag": "", @@ -1553,6 +1589,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Зупинити", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Символ зупинки", "Stream Chat Response": "Відповідь стрім-чату", @@ -1573,7 +1610,14 @@ "Support": "Підтримати", "Support this plugin:": "Підтримайте цей плагін:", "Supported MIME Types": "", + "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.": "", "System": "Система", "System Instructions": "Системні інструкції", "System Prompt": "Системний промт", @@ -1618,6 +1662,7 @@ "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.": "", "Theme": "Тема", + "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}}.", @@ -1732,6 +1777,7 @@ "Upload Pipeline": "Завантажити конвеєр", "Upload Progress": "Прогрес завантаження", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1749,6 +1795,7 @@ "User Groups": "", "User location successfully retrieved.": "Місцезнаходження користувача успішно знайдено.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "Вебхуки користувача", "Username": "Ім'я користувача", "users": "", @@ -1798,15 +1845,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI надсилатиме запити до \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Чого ви прагнете досягти?", "What are you working on?": "Над чим ти працюєш?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Що нового в", "What's on your mind?": "", "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.": "", "Whisper (Local)": "Whisper (Локально)", + "Who can share to this group": "", "Why?": "Чому?", "Widescreen Mode": "Широкоекранний режим", "Width": "", + "Wikipedia": "", "Won": "Переможець", "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": "Робочий простір", @@ -1818,6 +1869,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Вчора", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Ви", @@ -1825,6 +1878,9 @@ "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.": "Ви можете налаштувати ваші взаємодії з мовними моделями, додавши спогади через кнопку 'Керувати' внизу, що зробить їх більш корисними та персоналізованими для вас.", "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 save this prompt.": "", "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.": "", @@ -1836,6 +1892,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Статус вашого облікового запису наразі очікує на активацію.", "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.": "", "YouTube": "Youtube", "Youtube Language": "Мова YouTube", "Youtube Proxy URL": "URL проксі-сервера YouTube" diff --git a/src/lib/i18n/locales/ur-PK/translation.json b/src/lib/i18n/locales/ur-PK/translation.json index f6d5ae5159..596723c384 100644 --- a/src/lib/i18n/locales/ur-PK/translation.json +++ b/src/lib/i18n/locales/ur-PK/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "ان سیٹنگز کو ایڈجسٹ کرنے سے تمام صارفین کے لئے تبدیلیاں یکساں طور پر نافذ ہوں گی", "admin": "ایڈمن", "Admin": "ایڈمن", + "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.": "ایڈمنز کو ہر وقت تمام ٹولز تک رسائی حاصل ہوتی ہے؛ صارفین کو ورک سپیس میں ماڈل کے حساب سے ٹولز تفویض کرنے کی ضرورت ہوتی ہے", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "غیر مقامی آوازوں کی اجازت دیں", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "اور {{COUNT}} مزید", "and create a new shared link.": "اور ایک نیا مشترکہ لنک بنائیں", "Android": "", + "Anyone": "", "API Base URL": "API بنیادی URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "اے پی آئی کلید", @@ -175,6 +176,7 @@ "Authenticate": "", "Authentication": "", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "جواب خودکار طور پر کلپ بورڈ پر کاپی ہو گیا", "Auto-playback response": "آٹو پلے بیک جواب", "Autocomplete Generation": "", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 ایپلی کیشن کا تصدیقی سلسلہ", "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.)": "", "Available list": "دستیاب فہرست", "Available Tools": "", "available users": "دستیاب صارفین", @@ -201,6 +204,7 @@ "before": "پہلے", "Being lazy": "سستی کر رہا ہے", "Beta": "", + "Bing": "", "Bing Search V7 Endpoint": "", "Bing Search V7 Subscription Key": "", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "", + "Brave": "", "Brave Search API Key": "بریو سرچ API کلید", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "تازہ ترین معلومات کے لیے چیک کریں", "Checking for updates...": "تازہ ترین معلومات کی جانچ کر رہا ہے...", "Choose a model before saving...": "محفوظ کرنے سے پہلے ایک ماڈل منتخب کریں...", + "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.": "", "Ciphers": "", "Citation": "حوالہ", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "کوڈ کا نفاذ", - "Code Execution": "", "Code Execution Engine": "", "Code Execution Timeout": "", "Code formatted successfully": "کوڈ کامیابی سے فارمیٹ ہو گیا", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "ویب یو آئی رسائی کے لیے ایڈمن سے رابطہ کریں", "Content": "مواد", "Content Extraction Engine": "", + "Content lengths (character counts only)": "", "Continue Response": "ردعمل جاری رکھیں", "Continue with {{provider}}": "{{provider}} کے ساتھ جاری رکھیں", "Continue with Email": "", @@ -393,6 +401,7 @@ "Database": "ڈیٹا بیس", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "دسمبر", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "دستاویزات", - "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.": "جن ذرائع پر آپ بھروسہ نہیں کرتے ان سے بے ترتیب پائپ لائنز نہ لیں۔", @@ -493,11 +502,14 @@ "Done": "ہو گیا", "Download": "ڈاؤن لوڈ کریں", "Download & Delete": "ڈاؤن لوڈ اور حذف کریں", + "Download as JSON": "", "Download as SVG": "", "Download canceled": "ڈاؤن لوڈ منسوخ کر دیا گیا", "Download Database": "ڈیٹا بیس ڈاؤن لوڈ کریں", + "Downloading stats...": "", "Draw": "ڈرائنگ کریں", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "مثلاً '30s'، '10m' درست وقت کی اکائیاں ہیں 's'، 'm'، 'h'", "e.g. \"json\" or a JSON schema": "", "e.g. 60": "", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "", "Enter Brave Search API Key": "بریو سرچ API کلید درج کریں", "Enter certificate path": "", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "چنک اوورلیپ درج کریں", "Enter Chunk Size": "چنک سائز درج کریں", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "", @@ -595,6 +608,7 @@ "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 Github Raw URL": "گیٹ ہب را یو آر ایل درج کریں", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "تصویر کا سائز درج کریں (مثال: 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "", "Enter Key Behavior": "", "Enter language codes": "زبان کے کوڈ درج کریں", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "", "Enter Model ID": "ماڈل آئی ڈی درج کریں", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "", "Features Permissions": "", "February": "فروری", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "تاریخ رائے", - "Feedbacks": "", "Feel free to add specific details": "تفصیلات شامل کرنے کے لیے آزاد محسوس کریں", "Female": "", "File": "فائل", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "فنگر پرنٹ اسپورفنگ کا پتہ چلا: اوتار کے طور پر ابتدائی حروف استعمال کرنے سے قاصر ڈیفالٹ پروفائل تصویر منتخب کی جا رہی ہے", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "پوشہ کامیابی سے حذف ہو گیا", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "پوشے کا نام خالی نہیں ہو سکتا", "Folder name updated successfully": "فولڈر کا نام کامیابی سے اپ ڈیٹ ہوگیا", @@ -826,7 +846,6 @@ "General": "عمومی", "Generate": "", "Generate an image": "", - "Generate Image": "تصویر بنائیں", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "تلاش کے لیے سوالیہ عبارت تیار کی جا رہی ہے", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "", "Global": "عالمی", "Good Response": "اچھا جواب", + "Google": "", "Google Drive": "", "Google PSE API Key": "گوگل پی ایس ای API کی کلید", "Google PSE Engine Id": "گوگل پی ایس ای انجن آئی ڈی", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "گروپ", "Group Channel": "", "Group created successfully": "", @@ -895,7 +916,6 @@ "Image Prompt Generation": "", "Image Prompt Generation Prompt": "", "Image Size": "", - "Images": "تصاویر", "Import": "", "Import Chats": "چیٹس درآمد کریں", "Import Config from JSON File": "JSON فائل سے تشکیلات درآمد کریں", @@ -927,6 +947,7 @@ "Integration": "", "Integrations": "", "Interface": "انٹرفیس", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "غلط فائل فارمیٹ", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "", "Italic": "", "January": "جنوری", + "Jina API Base URL": "", "Jina API Key": "", "join our Discord for help.": "مدد کے لئے ہمارے ڈسکارڈ میں شامل ہوں", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "", "Leave empty to include all models from \"{{url}}/models\" endpoint": "", "Leave empty to include all models or select specific models": "تمام ماڈلز کو شامل کرنے کے لئے خالی چھوڑ دیں یا مخصوص ماڈلز منتخب کریں", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "خالی چھوڑیں تاکہ ڈیفالٹ پرامپٹ استعمال ہو، یا ایک حسب ضرورت پرامپٹ درج کریں", "Leave model field empty to use the default model.": "", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "مارچ", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "زیادہ سے زیادہ اپلوڈ تعداد", "Max Upload Size": "زیادہ سے زیادہ اپلوڈ سائز", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "بیک وقت زیادہ سے زیادہ 3 ماڈل ڈاؤن لوڈ کیے جا سکتے ہیں براہ کرم بعد میں دوبارہ کوشش کریں", "May": "مئی", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "یہاں LLMs کے ذریعہ قابل رسائی یادیں دکھائی جائیں گی", "Memory": "میموری", "Memory added successfully": "میموری کامیابی سے شامل کر دی گئی", @@ -1051,6 +1077,7 @@ "Merge Responses": "جوابات کو یکجا کریں", "Merged Response": "مرکب جواب", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "اس فیچر کو استعمال کرنے کے لئے پیغام کی درجہ بندی فعال کی جانی چاہئے", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "آپ کے لنک بنانے کے بعد بھیجے گئے پیغامات شیئر نہیں کیے جائیں گے یو آر ایل والے صارفین شیئر کیا گیا چیٹ دیکھ سکیں گے", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "ماڈل نام", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "ماڈل منتخب نہیں ہوا", "Model Params": "ماڈل پیرامیٹرز", "Model Permissions": "", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "ماڈل کامیابی کے ساتھ اپ ڈیٹ ہو گیا", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "", "More": "مزید", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "فاصلہ دستیاب نہیں ہے", "No expiration can pose security risks.": "", - "No feedbacks found": "کوئی تبصرے نہیں ملے", + "No feedback found": "", "No file selected": "کوئی فائل منتخب نہیں کی گئی", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "کوئی نتائج نہیں ملے", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "اوہ! لگتا ہے کہ یو آر ایل غلط ہے براۂ کرم دوبارہ چیک کریں اور دوبارہ کوشش کریں", "Oops! There are files still uploading. Please wait for the upload to complete.": "اوہ! کچھ فائلیں ابھی بھی اپ لوڈ ہو رہی ہیں براہ کرم اپ لوڈ مکمل ہونے کا انتظار کریں", "Oops! There was an error in the previous response.": "اوہ! پچھلے جواب میں ایک غلطی تھی", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "اوپن ویب یو آئی اندرونی طور پر فاسٹر وِسپر استعمال کرتا ہے", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "", + "Open WebUI version": "", "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 API": "اوپن اے آئی اے پی آئی\n", @@ -1235,6 +1268,8 @@ "page": "صفحہ", "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.": "", "Password": "پاس ورڈ", "Passwords do not match.": "", "Paste Large Text as File": "", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "پائپ لائن کامیابی سے حذف کر دی گئی", "Pipeline downloaded successfully": "پائپ لائن کامیابی سے ڈاؤن لوڈ ہو گئی", - "Pipelines": "پائپ لائنز", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines ایک پلگ اِن نظام ہے جس میں من مانی کوڈ چلایا جا سکتا ہے —", "Pipelines Not Detected": "پائپ لائنز کی نشاندہی نہیں ہوئی", "Pipelines Valves": "پائپ لائنز والوز", @@ -1498,6 +1532,7 @@ "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.": "", "Setting": "", "Settings": "ترتیبات", + "Settings Permissions": "", "Settings saved successfully!": "ترتیبات کامیابی کے ساتھ محفوظ ہو گئیں!", "Share": "اشتراک کریں", "Share Chat": "چیٹ شیئر کریں", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "تقریر کی پہچان کی خرابی: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "تقریر-سے-متن انجن", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "چینل کی شروعات", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "روکیں", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "ترتیب روکیں", "Stream Chat Response": "اسٹریم چیٹ جواب", @@ -1571,7 +1608,14 @@ "Support": "مدد کریں", "Support this plugin:": "اس پلگ ان کی حمایت کریں:", "Supported MIME Types": "", + "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.": "", "System": "سسٹم", "System Instructions": "نظام کی ہدایات", "System Prompt": "سسٹم پرومپٹ", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "تھیم", + "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.": "", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "اپ لوڈ پائپ لائن", "Upload Progress": "اپ لوڈ کی پیش رفت", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "صارف کا مقام کامیابی سے حاصل کیا گیا", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "", "Username": "", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "", "What are you trying to achieve?": "", "What are you working on?": "", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "میں نیا کیا ہے", "What's on your mind?": "", "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.": "", "Whisper (Local)": "سرگوشی (مقامی)", + "Who can share to this group": "", "Why?": "", "Widescreen Mode": "وائڈ اسکرین موڈ", "Width": "", + "Wikipedia": "", "Won": "جیتا", "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.": "", "Workspace": "ورک اسپیس", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "کل", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "آپ", @@ -1823,6 +1876,9 @@ "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.": "آپ نیچے موجود 'Manage' بٹن کے ذریعے LLMs کے ساتھ اپنی بات چیت کو یادداشتیں شامل کرکے ذاتی بنا سکتے ہیں، جو انہیں آپ کے لیے زیادہ مددگار اور آپ کے متعلق بنائے گی", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "آپ کے اکاؤنٹ کی حالت فی الحال فعال ہونے کے منتظر ہے", "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.": "آپ کی پوری شراکت براہ راست پلگ ان ڈیولپر کو جائے گی؛ اوپن ویب یو آئی کوئی فیصد نہیں لیتی تاہم، منتخب کردہ فنڈنگ پلیٹ فارم کی اپنی فیس ہو سکتی ہیں", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "یوٹیوب", "Youtube Language": "", "Youtube Proxy URL": "" diff --git a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json index f22161ec10..a7d8b0db6c 100644 --- a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json +++ b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ушбу созламаларни ўзгартириш барча фойдаланувчиларга универсал тарзда қўлланилади.", "admin": "админ", "Admin": "Админ", + "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.": "Администраторлар ҳар доим барча воситалардан фойдаланишлари мумкин; фойдаланувчиларга иш жойида ҳар бир модел учун тайинланган воситалар керак бўлади.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Файл юклашга рухсат беринг", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Чатда бир нечта моделларга рухсат беринг", "Allow non-local voices": "Маҳаллий бўлмаган овозларга рухсат беринг", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "ва яна {{COUNT}} та", "and create a new shared link.": "ва янги умумий ҳавола яратинг.", "Android": "Андроид", + "Anyone": "", "API Base URL": "Дастурий Илова Интерфейси(API) bazaviy URL manzili", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "Дастурий Илова Интерфейси(API) калити", @@ -175,6 +176,7 @@ "Authenticate": "Аутентификация қилиш", "Authentication": "Аутентификация", "Auto": "Автоматик", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Жавобни вақтинчалик хотирага автоматик нусхалаш", "Auto-playback response": "Автоматик ижро жавоби", "Autocomplete Generation": "Автотўлдиришни яратиш", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 базавий манзил", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 базавий манзил талаб қилинади.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Мавжуд рўйхат", "Available Tools": "Мавжуд асбоблар", "available users": "мавжуд фойдаланувчилар", @@ -201,6 +204,7 @@ "before": "олдин", "Being lazy": "Дангаса бўлиш", "Beta": "Бета", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 Endpoint", "Bing Search V7 Subscription Key": "Bing Search V7 Subscription Key", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search API Key", "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 Search API Key": "Brave Search API Key", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Янгиланишларни текширинг", "Checking for updates...": "Янгиланишлар текширилмоқда...", "Choose a model before saving...": "Сақлашдан олдин моделни танланг...", + "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.": "", "Ciphers": "Шифрлар", "Citation": "Иқтибос", "Citations": "Иқтибослар", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Коднинг бажарилиши", - "Code Execution": "Коднинг бажарилиши", "Code Execution Engine": "Кодни бажариш механизми", "Code Execution Timeout": "Кодни бажариш вақти тугаши", "Code formatted successfully": "Код муваффақиятли форматланди", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "WebUIга кириш учун администратор билан боғланинг", "Content": "Таркиб", "Content Extraction Engine": "Контентни ажратиб олиш механизми", + "Content lengths (character counts only)": "", "Continue Response": "Жавоб беришни давом эттириш", "Continue with {{provider}}": "{{provider}} билан давом этинг", "Continue with Email": "Электрон почта орқали давом этинг", @@ -393,6 +401,7 @@ "Database": "Маълумотлар базаси", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "декабр", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "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": "", "Docling Server URL required.": "Доcлинг Сервер URL манзили талаб қилинади.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Ҳужжатлар", - "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.": "Ишончсиз манбалардан тасодифий pipeline-ларни олманг.", @@ -493,11 +502,14 @@ "Done": "Бажарилди", "Download": "Юклаб олиш", "Download & Delete": "Юклаб олиш ва ўчириш", + "Download as JSON": "", "Download as SVG": "СВГ сифатида юклаб олинг", "Download canceled": "Юклаб олиш бекор қилинди", "Download Database": "Маълумотлар базасини юклаб олиш", + "Downloading stats...": "", "Draw": "Чизиш", "Drop any files here to upload": "Юклаш учун исталган файлни шу ерга ташланг", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "масалан. 30s, 10m. Яроқли вақт бирликлари 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "масалан. \"json\" ёки JSON схемаси", "e.g. 60": "масалан, 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Bocha Search API Key калитини киритинг", "Enter Brave Search API Key": "Brave Search API Key калитини киритинг", "Enter certificate path": "Сертификат йўлини киритинг", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Chunk Overlap киритинг", "Enter Chunk Size": "Chunk ҳажмини киритинг", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Вергул билан ажратилган \"token:bias_value\" жуфтларини киритинг (мисол: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Ташқи веб-қидирув УРЛ манзилини киритинг", "Enter Firecrawl API Base URL": "Firecrawl АПИ базаси УРЛ манзилини киритинг", "Enter Firecrawl API Key": "Firecrawl АПИ калитини киритинг", + "Enter Firecrawl Timeout": "", "Enter folder name": "", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Github Raw УРЛ манзилини киритинг", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Расм ҳажмини киритинг (масалан, 512х512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina АПИ калитини киритинг", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Jupiter паролини киритинг", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search АПИ калитини киритинг", "Enter Key Behavior": "Асосий хатти-ҳаракатни киритинг", "Enter language codes": "Тил кодларини киритинг", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Mistral АПИ калитини киритинг", "Enter Model ID": "Модел идентификаторини киритинг", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Файл таркибини юклаб бўлмади.", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Хусусиятлари", "Features Permissions": "Хусусиятлар Рухсатлар", "February": "Феврал", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Фикр-мулоҳаза тарихи", - "Feedbacks": "Фикр-мулоҳазалар", "Feel free to add specific details": "Муайян тафсилотларни қўшишингиз мумкин", "Female": "", "File": "Файл", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Бармоқ изи алдаш аниқланди: аватар сифатида бош ҳарфлардан фойдаланиш имконсиз. Стандарт профил расми.", "Firecrawl API Base URL": "Firecrawl АПИ асосий УРЛ манзили", "Firecrawl API Key": "Firecrawl АПИ калити", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Жилд муваффақиятли ўчирилди", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Жилд номи бўш бўлиши мумкин эмас.", "Folder name updated successfully": "Жилд номи муваффақиятли янгиланди", @@ -826,7 +846,6 @@ "General": "Умумий", "Generate": "Яратиш", "Generate an image": "Тасвир яратиш", - "Generate Image": "Расм яратиш", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Қидирув сўрови яратилмоқда", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}} билан бошланг", "Global": "Глобал", "Good Response": "Яхши жавоб", + "Google": "", "Google Drive": "Гоогле Дриве", "Google PSE API Key": "Гоогле ПСЕ АПИ калити", "Google PSE Engine Id": "Гоогле ПСЕ Энгине идентификатори", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Гуруҳ", "Group Channel": "", "Group created successfully": "Гуруҳ муваффақиятли яратилди", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Тасвир сўровини яратиш", "Image Prompt Generation Prompt": "Тасвир сўровини яратиш таклифи", "Image Size": "", - "Images": "Тасвирлар", "Import": "Импорт", "Import Chats": "Чатларни импорт қилиш", "Import Config from JSON File": "ЖСОН файлидан конфигурацияни импорт қилинг", @@ -927,6 +947,7 @@ "Integration": "Интеграция", "Integrations": "", "Interface": "Интерфейс", + "Interface Settings Access": "", "Invalid file content": "Файл мазмуни нотўғри", "Invalid file format.": "Файл формати нотўғри.", "Invalid JSON file": "ЖСОН файли яроқсиз", @@ -940,6 +961,7 @@ "is typing...": "ёзмоқда...", "Italic": "", "January": "Январ", + "Jina API Base URL": "", "Jina API Key": "Жина АПИ калити", "join our Discord for help.": "ёрдам учун Дисcордимизга қўшилинг.", "JSON": "ЖСОН", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "“{{url}}/api/тагс” сўнгги нуқтасидаги барча моделларни киритиш учун бўш қолдиринг", "Leave empty to include all models from \"{{url}}/models\" endpoint": "“{{url}}/моделс” сўнгги нуқтасидаги барча моделларни киритиш учун бўш қолдиринг", "Leave empty to include all models or select specific models": "Барча моделларни киритиш ёки муайян моделларни танлаш учун бўш қолдиринг", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Стандарт таклифдан фойдаланиш учун бўш қолдиринг ёки махсус таклифни киритинг", "Leave model field empty to use the default model.": "Стандарт моделдан фойдаланиш учун модел майдонини бўш қолдиринг.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Март", "Markdown": "Маркдоwн", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "Максимал динамиклар", "Max Upload Count": "Максимал юклаш сони", "Max Upload Size": "Максимал юклаш ҳажми", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Бир вақтнинг ўзида максимал 3 та моделни юклаб олиш мумкин. Кейинроқ қайта уриниб кўринг.", "May": "май", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "ЛЛМлар кириши мумкин бўлган хотиралар бу эрда кўрсатилади.", "Memory": "Хотира", "Memory added successfully": "Хотира муваффақиятли қўшилди", @@ -1051,6 +1077,7 @@ "Merge Responses": "Жавобларни бирлаштириш", "Merged Response": "Бирлаштирилган жавоб", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Бу функсиядан фойдаланиш учун хабарлар рейтинги ёқилиши керак", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Ҳаволани яратганингиздан кейин юборган хабарларингиз улашилмайди. УРЛ манзили бўлган фойдаланувчилар умумий чатни кўришлари мумкин бўлади.", "Microsoft OneDrive": "Microsoft ОнеДриве", @@ -1083,9 +1110,11 @@ "Model Name": "Модел номи", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Модел танланмаган", "Model Params": "Модел параметрлари", "Model Permissions": "Модел рухсатномалари", + "Model responses or outputs": "", "Model unloaded successfully": "Модел муваффақиятли юклаб олинди", "Model updated successfully": "Модел муваффақиятли янгиланди", "Model(s) do not support file upload": "Модел(лар) файлни юклашни қўллаб-қувватламайди", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Моделларни оммавий алмашиш", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Можеэк қидирув АПИ калити", "More": "Кўпроқ", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Масофа мавжуд эмас", "No expiration can pose security risks.": "", - "No feedbacks found": "Ҳеч қандай фикр топилмади", + "No feedback found": "", "No file selected": "Ҳеч қандай файл танланмаган", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Ҳеч қандай модел танланмаган", "No Notes": "Қайдлар йўқ", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Ҳеч қандай натижа топилмади", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Фақат маркдоwн файлларига рухсат берилади", "Only select users and groups with permission can access": "Фақат рухсати бор танланган фойдаланувчилар ва гуруҳларга кириш мумкин", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Вой! УРЛ нотўғри кўринади. Илтимос, икки марта текширинг ва қайта уриниб кўринг.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Вой! Ҳали ҳам файллар юкланмоқда. Илтимос, юклаш тугашини кутинг.", "Oops! There was an error in the previous response.": "Вой! Аввалги жавобда хатолик юз берди.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Опен WебУИ ҳар қандай ОпенАПИ сервери томонидан тақдим этилган воситалардан фойдаланиши мумкин.", "Open WebUI uses faster-whisper internally.": "Опен WебУИ ички тез шивирлашдан фойдаланади.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Опен WебУИ СпеэчТ5 ва CМУ Арcтиc динамик ўрнатишларидан фойдаланади.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Очиқ WебУИ версияси (в{{ОПЕН_WЕБУИ_ВЕРСИОН}}) талаб қилинган версиядан (в{{РЕҚУИРЕД_ВЕРСИОН}}) пастроқ", "OpenAI": "OpenAI", "OpenAI API": "OpenAI АПИ", @@ -1235,6 +1268,8 @@ "page": "саҳифа", "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.": "", "Password": "Парол", "Passwords do not match.": "", "Paste Large Text as File": "Катта матнни файл сифатида жойлаштиринг", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Қувур ўчирилди", "Pipeline downloaded successfully": "Қувур юклаб олинди", - "Pipelines": "Қувурлар", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines ихтиёрий код ишлатиш имконини берувчи плугин тизими —", "Pipelines Not Detected": "Қувурлар аниқланмади", "Pipelines Valves": "Қувур қувурлари клапанлари", @@ -1498,6 +1532,7 @@ "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.": "Фойдаланиш учун тўхташ кетма-кетликларини ўрнатади. Ушбу нақшга дуч келганда, ЛЛМ матн яратишни тўхтатади ва қайтиб келади. Модел файлида бир нечта алоҳида тўхташ параметрларини белгилаш орқали бир нечта тўхташ нақшлари ўрнатилиши мумкин.", "Setting": "", "Settings": "Созламалар", + "Settings Permissions": "", "Settings saved successfully!": "Созламалар муваффақиятли сақланди!", "Share": "Улашиш", "Share Chat": "Чатни улашиш", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Нутқни аниқлашда хатолик: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Нутқдан матнга восита", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Канал боши", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "СТОП", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Кетма-кетликни тўхтатиш", "Stream Chat Response": "Chat жавобини юбориш", @@ -1571,7 +1608,14 @@ "Support": "Қўллаб-қувватлаш", "Support this plugin:": "Ушбу плагинни қўллаб-қувватланг:", "Supported MIME Types": "", + "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.": "", "System": "Тизим", "System Instructions": "Тизим кўрсатмалари", "System Prompt": "Тизим сўрови", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Мавзу", + "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.": "Бу канал {{cреатедАт}} да яратилган. Бу {{чаннелНаме}} каналининг бошланиши.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Қувур линиясини юклаш", "Upload Progress": "Юклаш жараёни", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "УРЛ", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Фойдаланувчи жойлашуви муваффақиятли олинди.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "Фойдаланувчи веб-ҳуклари", "Username": "Фойдаланувчи номи", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" манзилига сўров юборади", "What are you trying to achieve?": "Нимага эришмоқчисиз?", "What are you working on?": "Нима устида ишлаяпсиз?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "", "What's on your mind?": "", "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.": "Чиқишни саҳифалаш керакми. Ҳар бир саҳифа горизонтал қоида ва саҳифа рақами билан ажратилади. Бирламчи параметрлар Фалсе.", "Whisper (Local)": "Шивирлаш (маҳаллий)", + "Who can share to this group": "", "Why?": "Нега?", "Widescreen Mode": "Кенг экран режими", "Width": "", + "Wikipedia": "", "Won": "Ғалаба қозонди", "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": "Иш майдони", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy Инстанcе УРЛ", "Yacy Password": "Yacy парол", "Yacy Username": "Yacy фойдаланувчи номи", + "Yahoo": "", + "Yandex": "", "Yesterday": "Кеча", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Сиз", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Сиз бир вақтнинг ўзида кўпи билан {{махCоунт}} та файл(лар) билан суҳбатлашишингиз мумкин.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Қуйидаги “Бошқариш” тугмаси орқали хотиралар қўшиш орқали ЛЛМлар билан ўзаро алоқаларингизни шахсийлаштиришингиз мумкин, бу уларни янада фойдалироқ ва сизга мослаштиради.", "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 save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Ҳисобингиз ҳолати ҳозирда фаоллаштиришни кутмоқда.", "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.": "", "YouTube": "Youtube", "Youtube Language": "Youtube тили", "Youtube Proxy URL": "Youtube прокси УРЛ" diff --git a/src/lib/i18n/locales/uz-Latn-Uz/translation.json b/src/lib/i18n/locales/uz-Latn-Uz/translation.json index 7059e57c95..d3b097aa6c 100644 --- a/src/lib/i18n/locales/uz-Latn-Uz/translation.json +++ b/src/lib/i18n/locales/uz-Latn-Uz/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Ushbu sozlamalarni o'zgartirish barcha foydalanuvchilarga universal tarzda qo'llaniladi.", "admin": "admin", "Admin": "Admin", + "Admin Contact Email": "", "Admin Panel": "Administrator paneli", "Admin Settings": "Administrator sozlamalari", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratorlar har doim barcha vositalardan foydalanishlari mumkin; foydalanuvchilarga ish joyida har bir model uchun tayinlangan vositalar kerak bo'ladi.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Fayl yuklashga ruxsat bering", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "Chatda bir nechta modellarga ruxsat bering", "Allow non-local voices": "Mahalliy bo'lmagan ovozlarga ruxsat bering", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "va yana {{COUNT}} ta", "and create a new shared link.": "va yangi umumiy havola yarating.", "Android": "Android", + "Anyone": "", "API Base URL": "API bazasi URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API kaliti", @@ -175,6 +176,7 @@ "Authenticate": "Autentifikatsiya qilish", "Authentication": "Autentifikatsiya", "Auto": "Avtomatik", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Javobni vaqtinchalik xotiraga avtomatik nusxalash", "Auto-playback response": "Avtomatik ijro javobi", "Autocomplete Generation": "Avtoto'ldirishni yaratish", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 Api Auth String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 asosiy URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 asosiy URL manzili talab qilinadi.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Mavjud ro'yxat", "Available Tools": "Mavjud asboblar", "available users": "mavjud foydalanuvchilar", @@ -201,6 +204,7 @@ "before": "oldin", "Being lazy": "Dangasa bo'lish", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing Search V7 Endpoint", "Bing Search V7 Subscription Key": "Bing Search V7 obuna kaliti", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha qidiruv API kaliti", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Cheklangan javoblar uchun maxsus tokenlarni kuchaytirish yoki jazolash. Yo'naltirilgan qiymatlar -100 va 100 (shu jumladan) oralig'ida mahkamlanadi. (Birlamchi: yo‘q)", + "Brave": "", "Brave Search API Key": "Brave Search API kaliti", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Yangilanishlarni tekshiring", "Checking for updates...": "Yangilanishlar tekshirilmoqda...", "Choose a model before saving...": "Saqlashdan oldin modelni tanlang...", + "Chunk Min Size Target": "", "Chunk Overlap": "Bo'laklarning bir-biriga o'xshashligi", "Chunk Size": "Bo'lak hajmi", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Shifrlar", "Citation": "Iqtibos", "Citations": "Iqtiboslar", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Kodning bajarilishi", - "Code Execution": "Kodning bajarilishi", "Code Execution Engine": "Kodni bajarish mexanizmi", "Code Execution Timeout": "Kodni bajarish vaqti tugashi", "Code formatted successfully": "Kod muvaffaqiyatli formatlandi", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "WebUI-ga kirish uchun administrator bilan bog'laning", "Content": "Tarkib", "Content Extraction Engine": "Kontentni ajratib olish mexanizmi", + "Content lengths (character counts only)": "", "Continue Response": "Javob berishni davom ettirish", "Continue with {{provider}}": "{{provider}} bilan davom eting", "Continue with Email": "Elektron pochta orqali davom eting", @@ -393,6 +401,7 @@ "Database": "Ma'lumotlar bazasi", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "dekabr", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Bilimga sho'ng'ing", "Do not install functions from sources you do not fully trust.": "Toʻliq ishonmaydigan manbalardan funksiyalarni oʻrnatmang.", "Do not install tools from sources you do not fully trust.": "O'zingiz ishonmaydigan manbalardan asboblarni o'rnatmang.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Dokling", "Docling Parameters": "", "Docling Server URL required.": "Docling Server URL manzili talab qilinadi.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Hujjatlar", - "Documents": "Hujjatlar", "does not make any external connections, and your data stays securely on your locally hosted server.": "hech qanday tashqi ulanishlarni amalga oshirmaydi va sizning ma'lumotlaringiz mahalliy serveringizda xavfsiz saqlanadi.", "Domain Filter List": "Domen filtrlari ro'yxati", "don't fetch random pipelines from sources you don't trust.": "Ishonchsiz manbalardan tasodifiy pipeline-larni olmang.", @@ -493,11 +502,14 @@ "Done": "Bajarildi", "Download": "Yuklab olish", "Download & Delete": "Yuklab olish va o‘chirish", + "Download as JSON": "", "Download as SVG": "SVG sifatida yuklab oling", "Download canceled": "Yuklab olish bekor qilindi", "Download Database": "Ma'lumotlar bazasini yuklab olish", + "Downloading stats...": "", "Draw": "Chizish", "Drop any files here to upload": "Yuklash uchun istalgan faylni shu yerga tashlang", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "masalan. '30s', '10m'. Yaroqli vaqt birliklari 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "masalan. \"json\" yoki JSON sxemasi", "e.g. 60": "masalan. 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Bocha Search API kalitini kiriting", "Enter Brave Search API Key": "Brave Search API kalitini kiriting", "Enter certificate path": "Sertifikat yo'lini kiriting", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Chunk Overlap-ni kiriting", "Enter Chunk Size": "Chunk hajmini kiriting", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Vergul bilan ajratilgan \"token:bias_value\" juftlarini kiriting (misol: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "Enter External Web Search URL": "Tashqi veb-qidiruv URL manzilini kiriting", "Enter Firecrawl API Base URL": "Firecrawl API bazasi URL manzilini kiriting", "Enter Firecrawl API Key": "Firecrawl API kalitini kiriting", + "Enter Firecrawl Timeout": "", "Enter folder name": "", "Enter function name filter list (e.g. func1, !func2)": "", "Enter Github Raw URL": "Github Raw URL manzilini kiriting", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Rasm hajmini kiriting (masalan, 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Jina API kalitini kiriting", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Jupyter parolini kiriting", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search API kalitini kiriting", "Enter Key Behavior": "Asosiy xatti-harakatni kiriting", "Enter language codes": "Til kodlarini kiriting", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Mistral API kalitini kiriting", "Enter Model ID": "Model identifikatorini kiriting", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "Fayl tarkibini yuklab bo‘lmadi.", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Xususiyatlari", "Features Permissions": "Xususiyatlar Ruxsatlar", "February": "Fevral", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Fikr-mulohaza tarixi", - "Feedbacks": "Fikr-mulohazalar", "Feel free to add specific details": "Muayyan tafsilotlarni qo'shishingiz mumkin", "Female": "", "File": "Fayl", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Barmoq izi aldash aniqlandi: avatar sifatida bosh harflardan foydalanish imkonsiz. Standart profil rasmi.", "Firecrawl API Base URL": "Firecrawl API asosiy URL manzili", "Firecrawl API Key": "Firecrawl API kaliti", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Jild muvaffaqiyatli oʻchirildi", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Jild nomi boʻsh boʻlishi mumkin emas.", "Folder name updated successfully": "Jild nomi muvaffaqiyatli yangilandi", @@ -826,7 +846,6 @@ "General": "General", "Generate": "Yaratish", "Generate an image": "Tasvir yaratish", - "Generate Image": "Rasm yaratish", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Qidiruv so'rovi yaratilmoqda", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "{{WEBUI_NAME}} bilan boshlang", "Global": "Global", "Good Response": "Yaxshi javob", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API kaliti", "Google PSE Engine Id": "Google PSE Engine identifikatori", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Guruh", "Group Channel": "", "Group created successfully": "Guruh muvaffaqiyatli yaratildi", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Tasvir so'rovini yaratish", "Image Prompt Generation Prompt": "Tasvir soʻrovini yaratish taklifi", "Image Size": "", - "Images": "Tasvirlar", "Import": "Import", "Import Chats": "Chatlarni import qilish", "Import Config from JSON File": "JSON faylidan konfiguratsiyani import qiling", @@ -927,6 +947,7 @@ "Integration": "Integratsiya", "Integrations": "", "Interface": "Interfeys", + "Interface Settings Access": "", "Invalid file content": "Fayl mazmuni noto‘g‘ri", "Invalid file format.": "Fayl formati noto‘g‘ri.", "Invalid JSON file": "JSON fayli yaroqsiz", @@ -940,6 +961,7 @@ "is typing...": "yozmoqda...", "Italic": "", "January": "Yanvar", + "Jina API Base URL": "", "Jina API Key": "Jina API kaliti", "join our Discord for help.": "yordam uchun Discordimizga qo'shiling.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "“{{url}}/api/tags” soʻnggi nuqtasidagi barcha modellarni kiritish uchun boʻsh qoldiring", "Leave empty to include all models from \"{{url}}/models\" endpoint": "“{{url}}/models” soʻnggi nuqtasidagi barcha modellarni kiritish uchun boʻsh qoldiring", "Leave empty to include all models or select specific models": "Barcha modellarni kiritish yoki muayyan modellarni tanlash uchun bo'sh qoldiring", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Standart taklifdan foydalanish uchun boʻsh qoldiring yoki maxsus taklifni kiriting", "Leave model field empty to use the default model.": "Standart modeldan foydalanish uchun model maydonini bo'sh qoldiring.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Mart", "Markdown": "Markdown", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "Maksimal dinamiklar", "Max Upload Count": "Maksimal yuklash soni", "Max Upload Size": "Maksimal yuklash hajmi", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Bir vaqtning o'zida maksimal 3 ta modelni yuklab olish mumkin. Keyinroq qayta urinib ko‘ring.", "May": "may", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "LLMlar kirishi mumkin bo'lgan xotiralar bu erda ko'rsatiladi.", "Memory": "Xotira", "Memory added successfully": "Xotira muvaffaqiyatli qo'shildi", @@ -1051,6 +1077,7 @@ "Merge Responses": "Javoblarni birlashtirish", "Merged Response": "Birlashtirilgan javob", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Bu funksiyadan foydalanish uchun xabarlar reytingi yoqilishi kerak", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Havolani yaratganingizdan keyin yuborgan xabarlaringiz ulashilmaydi. URL manzili bo'lgan foydalanuvchilar umumiy chatni ko'rishlari mumkin bo'ladi.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1083,9 +1110,11 @@ "Model Name": "Model nomi", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Model tanlanmagan", "Model Params": "Model parametrlari", "Model Permissions": "Model ruxsatnomalari", + "Model responses or outputs": "", "Model unloaded successfully": "Model muvaffaqiyatli yuklab olindi", "Model updated successfully": "Model muvaffaqiyatli yangilandi", "Model(s) do not support file upload": "Model(lar) faylni yuklashni qo'llab-quvvatlamaydi", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Modellarni ommaviy almashish", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Mojeek qidiruv API kaliti", "More": "Ko'proq", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Masofa mavjud emas", "No expiration can pose security risks.": "", - "No feedbacks found": "Hech qanday fikr topilmadi", + "No feedback found": "", "No file selected": "Hech qanday fayl tanlanmagan", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Hech qanday model tanlanmagan", "No Notes": "Qaydlar yo'q", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Hech qanday natija topilmadi", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "Faqat markdown fayllariga ruxsat beriladi", "Only select users and groups with permission can access": "Faqat ruxsati bor tanlangan foydalanuvchilar va guruhlarga kirish mumkin", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Voy! URL noto‘g‘ri ko‘rinadi. Iltimos, ikki marta tekshiring va qayta urinib ko'ring.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Voy! Hali ham fayllar yuklanmoqda. Iltimos, yuklash tugashini kuting.", "Oops! There was an error in the previous response.": "Voy! Avvalgi javobda xatolik yuz berdi.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI har qanday OpenAPI serveri tomonidan taqdim etilgan vositalardan foydalanishi mumkin.", "Open WebUI uses faster-whisper internally.": "Open WebUI ichki tez shivirlashdan foydalanadi.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI SpeechT5 va CMU Arctic dinamik oʻrnatishlaridan foydalanadi.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Ochiq WebUI versiyasi (v{{OPEN_WEBUI_VERSION}}) talab qilingan versiyadan (v{{REQUIRED_VERSION}}) pastroq", "OpenAI": "OpenAI", "OpenAI API": "OpenAI API", @@ -1235,6 +1268,8 @@ "page": "sahifa", "Paginate": "Sahifalash", "Parameters": "Parametrlar", + "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.": "", "Password": "Parol", "Passwords do not match.": "", "Paste Large Text as File": "Katta matnni fayl sifatida joylashtiring", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Quvur oʻchirildi", "Pipeline downloaded successfully": "Quvur yuklab olindi", - "Pipelines": "Quvurlar", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines — ixtiyoriy kod bajarilishini qo‘llab‑quvvatlaydigan plagin tizimi —", "Pipelines Not Detected": "Quvurlar aniqlanmadi", "Pipelines Valves": "Quvur quvurlari klapanlari", @@ -1498,6 +1532,7 @@ "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.": "Foydalanish uchun to'xtash ketma-ketliklarini o'rnatadi. Ushbu naqshga duch kelganda, LLM matn yaratishni to'xtatadi va qaytib keladi. Model faylida bir nechta alohida to'xtash parametrlarini belgilash orqali bir nechta to'xtash naqshlari o'rnatilishi mumkin.", "Setting": "", "Settings": "Sozlamalar", + "Settings Permissions": "", "Settings saved successfully!": "Sozlamalar muvaffaqiyatli saqlandi!", "Share": "Ulashish", "Share Chat": "Chatni ulashish", @@ -1541,6 +1576,7 @@ "Speech recognition error: {{error}}": "Nutqni aniqlashda xatolik: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Nutqdan matnga vosita", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Kanal boshlanishi", "Start Tag": "", @@ -1551,6 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "STOP", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Ketma-ketlikni to'xtatish", "Stream Chat Response": "Stream Chat javobi", @@ -1571,7 +1608,14 @@ "Support": "Qo'llab-quvvatlash", "Support this plugin:": "Ushbu plaginni qo'llab-quvvatlang:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Sinxronlash katalogi", + "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": "Tizim", "System Instructions": "Tizim ko'rsatmalari", "System Prompt": "Tizim so'rovi", @@ -1616,6 +1660,7 @@ "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.": "", "Theme": "Mavzu", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "O'ylash...", "This action cannot be undone. Do you wish to continue?": "Bu amalni ortga qaytarib bo‘lmaydi. Davom etishni xohlaysizmi?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Bu kanal {{createdAt}} da yaratilgan. Bu {{channelName}} kanalining boshlanishi.", @@ -1730,6 +1775,7 @@ "Upload Pipeline": "Quvur liniyasini yuklash", "Upload Progress": "Yuklash jarayoni", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1747,6 +1793,7 @@ "User Groups": "", "User location successfully retrieved.": "Foydalanuvchi joylashuvi muvaffaqiyatli olindi.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "Foydalanuvchi veb-huklari", "Username": "Foydalanuvchi nomi", "users": "", @@ -1796,15 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI \"{{url}}/chat/completions\" manziliga so'rov yuboradi", "What are you trying to achieve?": "Nimaga erishmoqchisiz?", "What are you working on?": "Nima ustida ishlayapsiz?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "", "What's on your mind?": "", "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.": "Yoqilganda, model real vaqt rejimida har bir chat xabariga javob beradi va foydalanuvchi xabar yuborishi bilanoq javob hosil qiladi. Ushbu rejim jonli chat ilovalari uchun foydalidir, lekin sekinroq uskunaning ishlashiga ta'sir qilishi mumkin.", "wherever you are": "qayerda bo'lsangiz ham", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Chiqishni sahifalash kerakmi. Har bir sahifa gorizontal qoida va sahifa raqami bilan ajratiladi. Birlamchi parametrlar False.", "Whisper (Local)": "Shivirlash (mahalliy)", + "Who can share to this group": "", "Why?": "Nega?", "Widescreen Mode": "Keng ekran rejimi", "Width": "", + "Wikipedia": "", "Won": "G'alaba qozondi", "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 bilan birga ishlaydi. Yuqori qiymat (masalan, 0,95) matnning xilma-xilligiga olib keladi, pastroq qiymat esa (masalan, 0,5) ko'proq diqqatli va konservativ matnni yaratadi.", "Workspace": "Ish maydoni", @@ -1816,6 +1867,8 @@ "Yacy Instance URL": "Yacy Instance URL", "Yacy Password": "Yacy parol", "Yacy Username": "Yacy foydalanuvchi nomi", + "Yahoo": "", + "Yandex": "", "Yesterday": "Kecha", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Siz", @@ -1823,6 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Siz bir vaqtning o'zida ko'pi bilan {{maxCount}} ta fayl(lar) bilan suhbatlashishingiz mumkin.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Quyidagi “Boshqarish” tugmasi orqali xotiralar qo‘shish orqali LLMlar bilan o‘zaro aloqalaringizni shaxsiylashtirishingiz mumkin, bu ularni yanada foydaliroq va sizga moslashtiradi.", "You cannot upload an empty file.": "Siz bo'sh faylni yuklay olmaysiz.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1834,6 +1890,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Hisobingiz holati hozirda faollashtirishni kutmoqda.", "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.": "Sizning barcha hissangiz to'g'ridan-to'g'ri plagin ishlab chiqaruvchisiga o'tadi; Open WebUI hech qanday foizni olmaydi. Biroq, tanlangan moliyalashtirish platformasi o'z to'lovlariga ega bo'lishi mumkin.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Youtube tili", "Youtube Proxy URL": "Youtube proksi URL" diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index cf4055f418..58a7ea1122 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Các thay đổi cài đặt này sẽ áp dụng cho tất cả người sử dụng.", "admin": "quản trị viên", "Admin": "Quản trị", + "Admin Contact Email": "", "Admin Panel": "Trang Quản trị", "Admin Settings": "Cài đặt hệ thống", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Quản trị viên luôn có quyền truy cập vào tất cả các tool; người dùng cần các tools được chỉ định cho mỗi mô hình trong workspace.", @@ -101,7 +102,6 @@ "Allow Continue Response": "", "Allow Delete Messages": "", "Allow File Upload": "Cho phép Tải tệp lên", - "Allow Group Sharing": "", "Allow Multiple Models in Chat": "", "Allow non-local voices": "Cho phép giọng nói không bản xứ", "Allow Rate Response": "", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "và {{COUNT}} mục khác", "and create a new shared link.": "và tạo một link chia sẻ mới", "Android": "", + "Anyone": "", "API Base URL": "Đường dẫn tới API (API Base URL)", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "", "API Key": "API Key", @@ -175,6 +176,7 @@ "Authenticate": "Xác thực", "Authentication": "Xác thực", "Auto": "", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "Tự động Sao chép Phản hồi vào clipboard", "Auto-playback response": "Tự động phát lại phản hồi (Auto-playback)", "Autocomplete Generation": "Tạo Tự động Hoàn thành", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "Chuỗi xác thực API AUTOMATIC1111", "AUTOMATIC1111 Base URL": "Đường dẫn kết nối tới AUTOMATIC1111 (Base URL)", "AUTOMATIC1111 Base URL is required.": "Base URL của AUTOMATIC1111 là bắt buộc.", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "Danh sách có sẵn", "Available Tools": "Công cụ có sẵn", "available users": "người dùng khả dụng", @@ -201,6 +204,7 @@ "before": "trước", "Being lazy": "Lười biếng", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Endpoint Bing Search V7", "Bing Search V7 Subscription Key": "Khóa đăng ký Bing Search V7", "Bio": "", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Khóa API Bocha Search", "Bold": "", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Tăng cường hoặc phạt các token cụ thể cho các phản hồi bị ràng buộc. Giá trị bias sẽ được giới hạn trong khoảng từ -100 đến 100 (bao gồm). (Mặc định: không có)", + "Brave": "", "Brave Search API Key": "Khóa API tìm kiếm dũng cảm", + "Builtin Tools": "", "Bullet List": "", "Button ID": "", "Button Label": "", @@ -256,8 +262,10 @@ "Check for updates": "Kiểm tra cập nhật", "Checking for updates...": "Đang kiểm tra cập nhật...", "Choose a model before saving...": "Chọn mô hình trước khi lưu...", + "Chunk Min Size Target": "", "Chunk Overlap": "Chồng lấn (overlap)", "Chunk Size": "Kích thước khối (size)", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "Bộ mã hóa", "Citation": "Trích dẫn", "Citations": "", @@ -293,7 +301,6 @@ "Code Block": "", "Code Editor": "", "Code execution": "Thực thi mã", - "Code Execution": "Thực thi Mã", "Code Execution Engine": "Engine Thực thi Mã", "Code Execution Timeout": "Thời gian chờ Thực thi Mã", "Code formatted successfully": "Mã được định dạng thành công", @@ -336,6 +343,7 @@ "Contact Admin for WebUI Access": "Liên hệ với Quản trị viên để được cấp quyền truy cập", "Content": "Nội dung", "Content Extraction Engine": "Engine Trích xuất Nội dung", + "Content lengths (character counts only)": "", "Continue Response": "Tiếp tục trả lời", "Continue with {{provider}}": "Tiếp tục với {{provider}}", "Continue with Email": "Tiếp tục với Email", @@ -393,6 +401,7 @@ "Database": "Cơ sở dữ liệu", "Datalab Marker API": "", "DD/MM/YYYY": "", + "DDGS Backend": "", "December": "Tháng 12", "Decrease UI Scale": "", "Deepgram": "", @@ -474,6 +483,7 @@ "Dive into knowledge": "Đi sâu vào kiến thức", "Do not install functions from sources you do not fully trust.": "Không cài đặt các functions từ các nguồn mà bạn không hoàn toàn tin tưởng.", "Do not install tools from sources you do not fully trust.": "Không cài đặt các tools từ những nguồn mà bạn không hoàn toàn tin tưởng.", + "Do you want to sync your usage stats with Open WebUI Community?": "", "Docling": "Docling", "Docling Parameters": "", "Docling Server URL required.": "Yêu cầu URL Máy chủ Docling.", @@ -482,7 +492,6 @@ "Document Intelligence endpoint required.": "", "Document Intelligence Model": "", "Documentation": "Tài liệu", - "Documents": "Tài liệu", "does not make any external connections, and your data stays securely on your locally hosted server.": "không thực hiện bất kỳ kết nối ngoài nào, và dữ liệu của bạn vẫn được lưu trữ an toàn trên máy chủ lưu trữ cục bộ của bạn.", "Domain Filter List": "Danh sách Lọc Tên miền", "don't fetch random pipelines from sources you don't trust.": "Đừng lấy các pipelines ngẫu nhiên từ nguồn không đáng tin cậy.", @@ -493,11 +502,14 @@ "Done": "Hoàn thành", "Download": "Tải về", "Download & Delete": "Tải xuống và xóa", + "Download as JSON": "", "Download as SVG": "Tải xuống dưới dạng SVG", "Download canceled": "Đã hủy download", "Download Database": "Tải xuống Cơ sở dữ liệu", + "Downloading stats...": "", "Draw": "Vẽ", "Drop any files here to upload": "", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "vd: '30s','10m'. Đơn vị thời gian hợp lệ là 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "ví dụ: \"json\" hoặc một lược đồ JSON", "e.g. 60": "vd: 60", @@ -572,6 +584,7 @@ "Enter Bocha Search API Key": "Nhập Khóa API Bocha Search", "Enter Brave Search API Key": "Nhập API key cho Brave Search", "Enter certificate path": "Nhập đường dẫn chứng chỉ", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "Nhập Chunk chồng lấn (overlap)", "Enter Chunk Size": "Nhập Kích thước Chunk", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Nhập các cặp \"token:giá_trị_bias\" được phân tách bằng dấu phẩy (ví dụ: 5432:100, 413:-100)", @@ -595,6 +608,7 @@ "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 Github Raw URL": "Nhập URL cho Github Raw", @@ -603,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "", "Enter ID": "", "Enter Image Size (e.g. 512x512)": "Nhập Kích thước ảnh (vd: 512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "Nhập Khóa API Jina", "Enter JSON config (e.g., {\"disable_links\": true})": "", "Enter Jupyter Password": "Nhập Mật khẩu Jupyter", @@ -611,6 +626,8 @@ "Enter Kagi Search API Key": "Nhập Khóa API Kagi Search", "Enter Key Behavior": "Nhập Hành vi phím", "Enter language codes": "Nhập mã ngôn ngữ", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "", "Enter Mistral API Key": "Nhập Khóa API Mistral", "Enter Model ID": "Nhập ID Mô hình", @@ -736,6 +753,7 @@ "Failed to generate title": "", "Failed to import models": "", "Failed to load chat preview": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "", "Failed to move chat": "", "Failed to process URL: {{url}}": "", @@ -752,10 +770,10 @@ "Features": "Tính năng", "Features Permissions": "Quyền Tính năng", "February": "Tháng 2", + "Feedback": "", "Feedback deleted successfully": "", "Feedback Details": "", "Feedback History": "Lịch sử Phản hồi", - "Feedbacks": "Các phản hồi", "Feel free to add specific details": "Mô tả chi tiết về chất lượng của câu hỏi và phương án trả lời", "Female": "", "File": "Tệp", @@ -776,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Phát hiện giả mạo vân tay: Không thể sử dụng tên viết tắt làm hình đại diện. Mặc định là hình ảnh hồ sơ mặc định.", "Firecrawl API Base URL": "", "Firecrawl API Key": "", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "", "Focus Chat Input": "", "Folder": "", "Folder Background Image": "", "Folder deleted successfully": "Xóa thư mục thành công", + "Folder Max File Count": "", "Folder Name": "", "Folder name cannot be empty.": "Tên thư mục không được để trống.", "Folder name updated successfully": "Cập nhật tên thư mục thành công", @@ -826,7 +846,6 @@ "General": "Cài đặt chung", "Generate": "", "Generate an image": "Tạo một hình ảnh", - "Generate Image": "Sinh ảnh", "Generate Message Pair": "", "Generated Image": "", "Generating search query": "Tạo truy vấn tìm kiếm", @@ -836,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Bắt đầu với {{WEBUI_NAME}}", "Global": "Toàn hệ thống", "Good Response": "Trả lời tốt", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Khóa API Google PSE", "Google PSE Engine Id": "ID công cụ Google PSE", "Gravatar": "", "Grid": "", + "Grokipedia": "", "Group": "Nhóm", "Group Channel": "", "Group created successfully": "Đã tạo nhóm thành công", @@ -895,7 +916,6 @@ "Image Prompt Generation": "Tạo Prompt Ảnh", "Image Prompt Generation Prompt": "Prompt Tạo Prompt Ảnh", "Image Size": "", - "Images": "Hình ảnh", "Import": "", "Import Chats": "Nạp lại nội dung chat", "Import Config from JSON File": "Nhập Cấu hình từ Tệp JSON", @@ -927,6 +947,7 @@ "Integration": "Tích hợp", "Integrations": "", "Interface": "Giao diện", + "Interface Settings Access": "", "Invalid file content": "", "Invalid file format.": "Định dạng tệp không hợp lệ.", "Invalid JSON file": "", @@ -940,6 +961,7 @@ "is typing...": "đang gõ...", "Italic": "", "January": "Tháng 1", + "Jina API Base URL": "", "Jina API Key": "Khóa API Jina", "join our Discord for help.": "tham gia Discord của chúng tôi để được trợ giúp.", "JSON": "JSON", @@ -990,6 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Để trống để bao gồm tất cả các mô hình từ điểm cuối \"{{url}}/api/tags\"", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Để trống để bao gồm tất cả các mô hình từ điểm cuối \"{{url}}/models\"", "Leave empty to include all models or select specific models": "Để trống để bao gồm tất cả các mô hình hoặc chọn các mô hình cụ thể", + "Leave empty to use first admin user": "", "Leave empty to use the default model (voxtral-mini-latest).": "", "Leave empty to use the default prompt, or enter a custom prompt": "Để trống để sử dụng prompt mặc định, hoặc nhập prompt tùy chỉnh", "Leave model field empty to use the default model.": "Để trống trường mô hình để sử dụng mô hình mặc định.", @@ -1029,10 +1052,12 @@ "Manage your account information.": "", "March": "Tháng 3", "Markdown": "", - "Markdown (Header)": "", + "Markdown Header Text Splitter": "", "Max Speakers": "", "Max Upload Count": "Số lượng Tải lên Tối đa", "Max Upload Size": "Kích thước Tải lên Tối đa", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Tối đa 3 mô hình có thể được tải xuống cùng lúc. Vui lòng thử lại sau.", "May": "Tháng 5", "MBR": "", @@ -1042,6 +1067,7 @@ "Member removed successfully": "", "Members": "", "Members added successfully": "", + "Memories": "", "Memories accessible by LLMs will be shown here.": "Memory có thể truy cập bởi LLMs sẽ hiển thị ở đây.", "Memory": "Memory", "Memory added successfully": "Memory đã được thêm thành công", @@ -1051,6 +1077,7 @@ "Merge Responses": "Hợp nhất các phản hồi", "Merged Response": "Phản hồi Hợp nhất", "Message": "", + "Message counts and response timestamps": "", "Message rating should be enabled to use this feature": "Cần bật tính năng đánh giá tin nhắn để sử dụng tính năng này", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Tin nhắn bạn gửi sau khi tạo liên kết sẽ không được chia sẻ. Người dùng có URL sẽ có thể xem cuộc trò chuyện được chia sẻ.", "Microsoft OneDrive": "", @@ -1083,9 +1110,11 @@ "Model Name": "Tên Mô hình", "Model name already exists, please choose a different one": "", "Model Name is required.": "", + "Model names and usage frequency": "", "Model not selected": "Chưa chọn Mô hình", "Model Params": "Mô hình Params", "Model Permissions": "Quyền Mô hình", + "Model responses or outputs": "", "Model unloaded successfully": "", "Model updated successfully": "Model đã được cập nhật thành công", "Model(s) do not support file upload": "", @@ -1096,6 +1125,7 @@ "Models imported successfully": "", "Models Public Sharing": "Chia sẻ Công khai Mô hình", "Models Sharing": "", + "Mojeek": "", "Mojeek Search API Key": "Khóa API Mojeek Search", "More": "Thêm", "More Concise": "", @@ -1129,7 +1159,7 @@ "No conversation to save": "", "No distance available": "Không có khoảng cách khả dụng", "No expiration can pose security risks.": "", - "No feedbacks found": "Không tìm thấy phản hồi nào", + "No feedback found": "", "No file selected": "Chưa có tệp nào được chọn", "No files in this knowledge base.": "", "No functions found": "", @@ -1144,6 +1174,7 @@ "No models selected": "Chưa chọn mô hình nào", "No Notes": "", "No notes found": "", + "No one": "", "No pinned messages": "", "No prompts found": "", "No results": "Không tìm thấy kết quả", @@ -1195,6 +1226,7 @@ "Only invited users can access": "", "Only markdown files are allowed": "", "Only select users and groups with permission can access": "Chỉ người dùng và nhóm được chọn có quyền mới có thể truy cập", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Rất tiếc! URL dường như không hợp lệ. Vui lòng kiểm tra lại và thử lại.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ối! Vẫn còn tệp đang tải lên. Vui lòng đợi quá trình tải lên hoàn tất.", "Oops! There was an error in the previous response.": "Ối! Đã xảy ra lỗi trong phản hồi trước đó.", @@ -1211,6 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "", "Open WebUI uses faster-whisper internally.": "Open WebUI sử dụng faster-whisper bên trong.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI sử dụng SpeechT5 và các embedding giọng nói CMU Arctic.", + "Open WebUI version": "", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Phiên bản Open WebUI (v{{OPEN_WEBUI_VERSION}}) hiện thấp hơn phiên bản bắt buộc (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "API OpenAI", @@ -1235,6 +1268,8 @@ "page": "trang", "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.": "", "Password": "Mật khẩu", "Passwords do not match.": "", "Paste Large Text as File": "Dán Văn bản Lớn dưới dạng Tệp", @@ -1260,7 +1295,6 @@ "Pipe": "", "Pipeline deleted successfully": "Đã xóa pipeline thành công", "Pipeline downloaded successfully": "Đã tải xuống pipeline thành công", - "Pipelines": "Pipelines", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines là hệ thống plugin cho phép thực thi mã tùy ý —", "Pipelines Not Detected": "Chưa tìm thấy Pipelines", "Pipelines Valves": "Các Valve của Pipeline", @@ -1497,6 +1531,7 @@ "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.": "Đặt các chuỗi dừng để sử dụng. Khi gặp mẫu này, LLM sẽ ngừng tạo văn bản và trả về. Có thể đặt nhiều mẫu dừng bằng cách chỉ định nhiều tham số stop riêng biệt trong modelfile.", "Setting": "", "Settings": "Cài đặt", + "Settings Permissions": "", "Settings saved successfully!": "Cài đặt đã được lưu thành công!", "Share": "Chia sẻ", "Share Chat": "Chia sẻ Chat", @@ -1540,6 +1575,7 @@ "Speech recognition error: {{error}}": "Lỗi nhận dạng giọng nói: {{error}}", "Speech-to-Text": "", "Speech-to-Text Engine": "Công cụ Nhận dạng Giọng nói", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "", "Start of the channel": "Đầu kênh", "Start Tag": "", @@ -1550,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "", "Stop": "Dừng", + "Stop Download": "", "Stop Generating": "", "Stop Sequence": "Trình tự Dừng", "Stream Chat Response": "Truyền trực tiếp Phản hồi Chat", @@ -1570,7 +1607,14 @@ "Support": "Hỗ trợ", "Support this plugin:": "Hỗ trợ plugin này:", "Supported MIME Types": "", + "Sync": "", + "Sync Complete!": "", "Sync directory": "Đồng bộ thư mục", + "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": "Hệ thống", "System Instructions": "Hướng dẫn Hệ thống", "System Prompt": "Prompt Hệ thống (System Prompt)", @@ -1615,6 +1659,7 @@ "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.": "", "Theme": "Chủ đề", + "There was an error syncing your stats. Please try again.": "", "Thinking...": "Đang suy luận...", "This action cannot be undone. Do you wish to continue?": "Hành động này không thể được hoàn tác. Bạn có muốn tiếp tục không?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Kênh này được tạo vào {{createdAt}}. Đây là điểm khởi đầu của kênh {{channelName}}.", @@ -1729,6 +1774,7 @@ "Upload Pipeline": "Tải lên Pipeline", "Upload Progress": "Tiến trình tải tệp lên hệ thống", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "", + "Uploaded files or images": "", "Uploading file...": "", "URL": "URL", "URL is required": "", @@ -1746,6 +1792,7 @@ "User Groups": "", "User location successfully retrieved.": "Đã truy xuất thành công vị trí của người dùng.", "User menu": "", + "User ratings (thumbs up/down)": "", "User Webhooks": "Webhook Người dùng", "Username": "Tên đăng nhập", "users": "", @@ -1795,15 +1842,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI sẽ thực hiện yêu cầu đến \"{{url}}/chat/completions\"", "What are you trying to achieve?": "Bạn đang cố gắng đạt được điều gì?", "What are you working on?": "Bạn đang làm gì vậy?", + "What is NOT shared:": "", + "What is shared:": "", "What's New in": "Thông tin mới về", "What's on your mind?": "", "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.": "Khi được bật, mô hình sẽ phản hồi từng tin nhắn trò chuyện trong thời gian thực, tạo ra phản hồi ngay khi người dùng gửi tin nhắn. Chế độ này hữu ích cho các ứng dụng trò chuyện trực tiếp, nhưng có thể ảnh hưởng đến hiệu suất trên phần cứng chậm hơn.", "wherever you are": "bất cứ nơi nào bạn đang ở", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "", "Whisper (Local)": "Whisper (Cục bộ)", + "Who can share to this group": "", "Why?": "Tại sao?", "Widescreen Mode": "Chế độ màn hình rộng", "Width": "", + "Wikipedia": "", "Won": "Thắng", "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.": "Hoạt động cùng với top-k. Giá trị cao hơn (ví dụ: 0.95) sẽ dẫn đến văn bản đa dạng hơn, trong khi giá trị thấp hơn (ví dụ: 0.5) sẽ tạo ra văn bản tập trung và thận trọng hơn.", "Workspace": "Không gian làm việc", @@ -1815,6 +1866,8 @@ "Yacy Instance URL": "", "Yacy Password": "", "Yacy Username": "", + "Yahoo": "", + "Yandex": "", "Yesterday": "Hôm qua", "Yesterday at {{LOCALIZED_TIME}}": "", "You": "Bạn", @@ -1822,6 +1875,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Bạn chỉ có thể trò chuyện với tối đa {{maxCount}} tệp cùng một lúc.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Bạn có thể cá nhân hóa các tương tác của mình với LLM bằng cách thêm bộ nhớ thông qua nút 'Quản lý' bên dưới, làm cho chúng hữu ích hơn và phù hợp với bạn hơn.", "You cannot upload an empty file.": "Bạn không thể tải lên một tệp trống.", + "You do not have permission to edit this model": "", + "You do not have permission to edit this prompt.": "", + "You do not have permission to save this prompt.": "", "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.": "", @@ -1833,6 +1889,8 @@ "Your Account": "", "Your account status is currently pending activation.": "Tài khoản của bạn hiện đang ở trạng thái chờ kích hoạt.", "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.": "Toàn bộ đóng góp của bạn sẽ được chuyển trực tiếp đến nhà phát triển plugin; Open WebUI không lấy bất kỳ tỷ lệ phần trăm nào. Tuy nhiên, nền tảng được chọn tài trợ có thể có phí riêng.", + "Your message text or inputs": "", + "Your usage stats have been successfully synced.": "", "YouTube": "Youtube", "Youtube Language": "Ngôn ngữ Youtube", "Youtube Proxy URL": "URL Proxy Youtube" diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index 091927eb6d..df8396b5f1 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "调整这些设置将会对所有用户生效", "admin": "管理员", "Admin": "管理员", + "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.": "管理员拥有所有工具的完全访问权限;用户则需在工作空间中为每个模型单独分配工具。", @@ -101,7 +102,6 @@ "Allow Continue Response": "允许继续生成回答", "Allow Delete Messages": "允许删除对话消息", "Allow File Upload": "允许上传文件", - "Allow Group Sharing": "允许群组内共享", "Allow Multiple Models in Chat": "允许在对话中使用多个模型", "Allow non-local voices": "允许调用非本土音色", "Allow Rate Response": "允许对回答进行评价", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "还有 {{COUNT}} 个", "and create a new shared link.": "并创建新的分享链接", "Android": "Android", + "Anyone": "", "API Base URL": "接口地址", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "Datalab Marker 服务的接口地址。默认为:https://www.datalab.to/api/v1/marker", "API Key": "API 密钥", @@ -175,6 +176,7 @@ "Authenticate": "认证", "Authentication": "身份验证", "Auto": "自动", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "自动复制回答内容到剪贴板", "Auto-playback response": "自动朗读回答内容", "Autocomplete Generation": "输入框内容自动补全", @@ -183,6 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 接口鉴权字符串", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 接口地址", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 接口地址是必填项。", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", "Available list": "可用列表", "Available Tools": "可用工具", "available users": "可用用户", @@ -201,6 +204,7 @@ "before": "之前", "Being lazy": "回答不完整或敷衍了事", "Beta": "Beta", + "Bing": "", "Bing Search V7 Endpoint": "Bing 搜索 V7 端点", "Bing Search V7 Subscription Key": "Bing 搜索 V7 订阅密钥", "Bio": "个人简介", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha Search 接口密钥", "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 Search API Key": "Brave Search 接口密钥", + "Builtin Tools": "", "Bullet List": "无序列表", "Button ID": "按钮 ID", "Button Label": "按钮文本", @@ -256,8 +262,10 @@ "Check for updates": "检查更新", "Checking for updates...": "正在检查更新...", "Choose a model before saving...": "保存前选择一个模型...", + "Chunk Min Size Target": "", "Chunk Overlap": "块重叠 (Chunk Overlap)", "Chunk Size": "块大小 (Chunk Size)", + "Chunks smaller than this threshold will be merged with neighboring chunks when possible. Set to 0 to disable merging.": "", "Ciphers": "加密算法 (Ciphers)", "Citation": "引文", "Citations": "引用", @@ -293,7 +301,6 @@ "Code Block": "代码块", "Code Editor": "代码编辑器", "Code execution": "代码执行", - "Code Execution": "代码执行", "Code Execution Engine": "代码执行引擎", "Code Execution Timeout": "代码执行超时", "Code formatted successfully": "代码格式化成功", @@ -394,6 +401,7 @@ "Database": "数据库", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "DD/MM/YYYY", + "DDGS Backend": "", "December": "十二月", "Decrease UI Scale": "减少界面缩放比例", "Deepgram": "Deepgram", @@ -484,7 +492,6 @@ "Document Intelligence endpoint required.": "Document Intelligence 接口地址是必填项。", "Document Intelligence Model": "Document Intelligence 模型", "Documentation": "帮助文档", - "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.": "请勿从未经验证或不可信的来源获取 Pipelines。", @@ -495,11 +502,14 @@ "Done": "完成", "Download": "下载", "Download & Delete": "下载并删除", + "Download as JSON": "", "Download as SVG": "下载为 SVG", "Download canceled": "下载已取消", "Download Database": "下载数据库", + "Downloading stats...": "", "Draw": "平局", "Drop any files here to upload": "拖拽文件至此上传", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "例如:“30s”,“10m”。有效的时间单位包括:“s”(秒), “m”(分), “h”(时)", "e.g. \"json\" or a JSON schema": "例如:\"json\" 或一个 JSON schema", "e.g. 60": "例如:60", @@ -574,6 +584,7 @@ "Enter Bocha Search API Key": "输入 Bocha Search 接口密钥", "Enter Brave Search API Key": "输入 Brave Search 接口密钥", "Enter certificate path": "输入证书路径", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "输入块重叠 (Chunk Overlap)", "Enter Chunk Size": "输入块大小 (Chunk Size)", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "输入以逗号分隔的“token:bias_value”对(例如:5432:100, 413:-100)", @@ -597,6 +608,7 @@ "Enter External Web Search URL": "输入外部联网搜索接口地址", "Enter Firecrawl API Base URL": "输入 Firecrawl 接口地址", "Enter Firecrawl API Key": "输入 Firecrawl 接口密钥", + "Enter Firecrawl Timeout": "", "Enter folder name": "输入分组名称", "Enter function name filter list (e.g. func1, !func2)": "输入函数名称过滤列表(例如:func1, !func2)", "Enter Github Raw URL": "输入 Github Raw 链接", @@ -605,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "输入十六进制颜色(例如:#FF0000)", "Enter ID": "输入 ID", "Enter Image Size (e.g. 512x512)": "输入图像分辨率(例如:512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "输入 Jina 接口密钥", "Enter JSON config (e.g., {\"disable_links\": true})": "输入 JSON 配置(例如:{\"disable_links\": true})", "Enter Jupyter Password": "输入 Jupyter 密码", @@ -613,6 +626,8 @@ "Enter Kagi Search API Key": "输入 Kagi Search 接口密钥", "Enter Key Behavior": "Enter 键行为", "Enter language codes": "输入语言代码", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "输入 Mistral 接口地址", "Enter Mistral API Key": "输入 Mistral 接口密钥", "Enter Model ID": "输入模型 ID", @@ -738,6 +753,7 @@ "Failed to generate title": "生成标题失败", "Failed to import models": "导入模型配置失败", "Failed to load chat preview": "对话预览加载失败", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "文件内容加载失败", "Failed to move chat": "移动对话失败", "Failed to process URL: {{url}}": "处理链接失败: {{url}}", @@ -754,10 +770,10 @@ "Features": "功能", "Features Permissions": "功能权限", "February": "二月", + "Feedback": "", "Feedback deleted successfully": "反馈删除成功", "Feedback Details": "反馈详情", "Feedback History": "历史反馈", - "Feedbacks": "反馈", "Feel free to add specific details": "欢迎补充具体细节", "Female": "女性", "File": "文件", @@ -778,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "检测到浏览器指纹伪造插件:无法使用姓名缩写作为头像,将使用系统默认的头像。", "Firecrawl API Base URL": "Firecrawl 接口地址", "Firecrawl API Key": "Firecrawl 接口密钥", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "快捷操作浮窗", "Focus Chat Input": "聚焦对话框", "Folder": "分组", "Folder Background Image": "分组背景图", "Folder deleted successfully": "分组删除成功", + "Folder Max File Count": "", "Folder Name": "分组名称", "Folder name cannot be empty.": "分组名称不能为空", "Folder name updated successfully": "分组名称更新成功", @@ -828,7 +846,6 @@ "General": "通用", "Generate": "生成", "Generate an image": "生成图像", - "Generate Image": "生成图像", "Generate Message Pair": "生成消息对", "Generated Image": "已生成图像", "Generating search query": "生成搜索查询", @@ -838,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "开始使用 {{WEBUI_NAME}}", "Global": "全局", "Good Response": "点赞此回答", + "Google": "", "Google Drive": "Google 云端硬盘", "Google PSE API Key": "Google PSE 接口密钥", "Google PSE Engine Id": "Google PSE 引擎 ID", "Gravatar": "Gravatar 头像", "Grid": "网格", + "Grokipedia": "", "Group": "权限组", "Group Channel": "群组频道", "Group created successfully": "权限组创建成功", @@ -897,7 +916,6 @@ "Image Prompt Generation": "图像提示词生成", "Image Prompt Generation Prompt": "用于生成图像提示词的提示词", "Image Size": "图片尺寸", - "Images": "图像", "Import": "导入", "Import Chats": "导入对话记录", "Import Config from JSON File": "从 JSON 文件中导入配置信息", @@ -929,6 +947,7 @@ "Integration": "集成", "Integrations": "扩展功能", "Interface": "界面", + "Interface Settings Access": "", "Invalid file content": "文件内容无效", "Invalid file format.": "文件格式无效", "Invalid JSON file": "JSON 文件格式无效", @@ -942,6 +961,7 @@ "is typing...": "输入中...", "Italic": "斜体", "January": "一月", + "Jina API Base URL": "", "Jina API Key": "Jina 接口密钥", "join our Discord for help.": "加入我们的 Discord 寻求帮助", "JSON": "JSON", @@ -992,6 +1012,7 @@ "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 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.": "模型字段留空以使用默认模型", @@ -1031,10 +1052,12 @@ "Manage your account information.": "管理您的账号信息。", "March": "三月", "Markdown": "Markdown", - "Markdown (Header)": "Markdown(标题)", + "Markdown Header Text Splitter": "", "Max Speakers": "最大扬声器数量", "Max Upload Count": "最大上传数量", "Max Upload Size": "最大上传大小", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多可同时下载 3 个模型,请稍后重试。", "May": "五月", "MBR": "成员", @@ -1044,6 +1067,7 @@ "Member removed successfully": "成员移除成功", "Members": "成员", "Members added successfully": "成员添加成功", + "Memories": "", "Memories accessible by LLMs will be shown here.": "大语言模型可访问的记忆将在此显示", "Memory": "记忆", "Memory added successfully": "记忆添加成功", @@ -1101,6 +1125,7 @@ "Models imported successfully": "已成功导入模型配置", "Models Public Sharing": "模型公开分享", "Models Sharing": "分享模型", + "Mojeek": "", "Mojeek Search API Key": "Mojeek Search 接口密钥", "More": "更多", "More Concise": "精炼表达", @@ -1134,7 +1159,7 @@ "No conversation to save": "没有可保存的对话", "No distance available": "没有可用距离", "No expiration can pose security risks.": "未设置 JWT 过期时间会导致安全风险。", - "No feedbacks found": "暂无任何反馈", + "No feedback found": "", "No file selected": "未选中文件", "No files in this knowledge base.": "此知识库中没有文件。", "No functions found": "未找到函数", @@ -1149,6 +1174,7 @@ "No models selected": "未选择任何模型", "No Notes": "没有笔记", "No notes found": "没有任何笔记", + "No one": "", "No pinned messages": "没有置顶消息", "No prompts found": "未找到提示词", "No results": "未找到结果", @@ -1200,6 +1226,7 @@ "Only invited users can access": "只有受邀用户才能访问", "Only markdown files are allowed": "仅允许使用 markdown 文件", "Only select users and groups with permission can access": "只有具有权限的用户和组才能访问", + "Only sync new/updated chats": "", "Oops! Looks like the URL is invalid. Please double-check and try again.": "糟糕!此链接似乎为无效链接。请检查后重试。", "Oops! There are files still uploading. Please wait for the upload to complete.": "糟糕!仍有文件正在上传。请等待上传完成。", "Oops! There was an error in the previous response.": "糟糕!之前的回答中出现了错误。", @@ -1241,6 +1268,7 @@ "page": "页", "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.": "欢迎您参与社区排行榜和评估!同步使用统计数据有助于 Open WebUI 的研发和改进。您的隐私至关重要:我们绝不会发送任何消息内容。", "Password": "密码", "Passwords do not match.": "两次输入的密码不一致。", @@ -1267,7 +1295,6 @@ "Pipe": "Pipe", "Pipeline deleted successfully": "Pipeline 删除成功", "Pipeline downloaded successfully": "Pipeline 下载成功", - "Pipelines": "Pipeline", "Pipelines are a plugin system with arbitrary code execution —": "Pipelines 是具有任意代码执行风险的插件系统 —", "Pipelines Not Detected": "未检测到 Pipeline", "Pipelines Valves": "Pipeline 配置项", @@ -1504,6 +1531,7 @@ "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.": "设置要使用的停止序列。在该模式下,大语言模型将停止生成文本并返回。可以通过在模型文件中指定多个单独的停止参数来设置多个停止模式。", "Setting": "设置", "Settings": "设置", + "Settings Permissions": "", "Settings saved successfully!": "设置已成功保存!", "Share": "分享", "Share Chat": "分享对话", @@ -1547,6 +1575,7 @@ "Speech recognition error: {{error}}": "语音识别错误:{{error}}", "Speech-to-Text": "语音转文本", "Speech-to-Text Engine": "语音转文本引擎", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "开始新对话", "Start of the channel": "频道起点", "Start Tag": "起始标签", @@ -1557,6 +1586,7 @@ "STDOUT/STDERR": "标准输出/标准错误", "Steps": "迭代步数", "Stop": "停止", + "Stop Download": "", "Stop Generating": "停止生成", "Stop Sequence": "停止序列 (Stop Sequence)", "Stream Chat Response": "流式对话响应 (Stream Chat Response)", @@ -1580,8 +1610,11 @@ "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.": "", "System": "系统", "System Instructions": "系统指令", "System Prompt": "系统提示词", @@ -1626,6 +1659,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "BM25 混合检索权重(输入接近 0 的数字会倾向于全语义搜索,反之输入接近 1 的数字会倾向于关键词搜索,默认为 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.": "", "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.": "欢迎来到 {{channelName}},本频道创建于 {{createdAt}}。", @@ -1816,9 +1850,11 @@ "wherever you are": "纵使身在远方,亦与世界同频", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "是否对输出内容进行分页。每页之间将用水平分隔线和页码隔开。默认为关闭", "Whisper (Local)": "Whisper (本地)", + "Who can share to this group": "", "Why?": "为什么?", "Widescreen Mode": "宽屏模式", "Width": "宽度", + "Wikipedia": "", "Won": "获胜", "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": "工作空间", @@ -1830,6 +1866,8 @@ "Yacy Instance URL": "YaCy 实例接口地址", "Yacy Password": "YaCy 密码", "Yacy Username": "YaCy 用户名", + "Yahoo": "", + "Yandex": "", "Yesterday": "昨天", "Yesterday at {{LOCALIZED_TIME}}": "昨天 {{LOCALIZED_TIME}}", "You": "你", @@ -1837,6 +1875,9 @@ "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.": "点击下方“管理”按钮,您可以添加记忆,定制与大语言模型之间的互动,使其提供更加到位的帮助,更符合您的需求。", "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 save this prompt.": "", "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.": "您没有权限上传文件到此知识库。", @@ -1849,7 +1890,7 @@ "Your account status is currently pending activation.": "您的账号当前状态为待激活", "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 with the Open WebUI Community.": "您的使用统计数据已成功同步至 Open WebUI 社区。", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "Youtube 语言", "Youtube Proxy URL": "Youtube 代理地址" diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index a6d5ba69a6..0fcbef53e0 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -77,6 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "調整這些設定將會影響所有使用者。", "admin": "管理員", "Admin": "管理員", + "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.": "管理員可以隨時使用所有工具;使用者則需在工作區中為每個模型分配工具。", @@ -101,7 +102,6 @@ "Allow Continue Response": "允許繼續回應", "Allow Delete Messages": "允許刪除訊息", "Allow File Upload": "允許上傳檔案", - "Allow Group Sharing": "允許在群組內分享", "Allow Multiple Models in Chat": "允許在對話中使用多個模型", "Allow non-local voices": "允許非本機語音", "Allow Rate Response": "允許為回應評分", @@ -130,6 +130,7 @@ "and {{COUNT}} more": "和另外 {{COUNT}} 個", "and create a new shared link.": "並建立新的共用連結。", "Android": "Android", + "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 金鑰", @@ -175,6 +176,7 @@ "Authenticate": "驗證", "Authentication": "驗證", "Auto": "自動", + "Auto (Random)": "", "Auto-Copy Response to Clipboard": "自動將回應複製到剪貼簿", "Auto-playback response": "自動播放回應", "Autocomplete Generation": "自動完成生成", @@ -183,6 +185,7 @@ "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.)": "", "Available list": "可用清單", "Available Tools": "可用工具", "available users": "可用名額", @@ -201,6 +204,7 @@ "before": "之前", "Being lazy": "懶惰模式", "Beta": "測試", + "Bing": "", "Bing Search V7 Endpoint": "Bing 搜尋 V7 端點", "Bing Search V7 Subscription Key": "Bing 搜尋 V7 訂閱金鑰", "Bio": "個人簡介", @@ -209,7 +213,9 @@ "Bocha Search API Key": "Bocha 搜尋 API 金鑰", "Bold": "粗體", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "針對受限的回應,增強或懲罰特定 tokens。偏差值將限制在 -100 到 100 (含)。 (預設:none)", + "Brave": "", "Brave Search API Key": "Brave 搜尋 API 金鑰", + "Builtin Tools": "", "Bullet List": "無序清單", "Button ID": "按鈕 ID", "Button Label": "按鈕文字", @@ -256,8 +262,10 @@ "Check for updates": "檢查更新", "Checking for updates...": "正在檢查更新...", "Choose a model before saving...": "儲存前請選擇一個模型...", + "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.": "", "Ciphers": "加密方式", "Citation": "引用", "Citations": "引用", @@ -293,7 +301,6 @@ "Code Block": "程式碼區塊", "Code Editor": "程式碼編輯器", "Code execution": "程式碼執行", - "Code Execution": "程式碼執行", "Code Execution Engine": "程式碼執行引擎", "Code Execution Timeout": "程式執行超時", "Code formatted successfully": "成功格式化程式碼", @@ -394,6 +401,7 @@ "Database": "資料庫", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "DD/MM/YYYY", + "DDGS Backend": "", "December": "12 月", "Decrease UI Scale": "減小介面縮放比例", "Deepgram": "Deepgram", @@ -484,7 +492,6 @@ "Document Intelligence endpoint required.": "需要提供 Document Intelligence 端點。", "Document Intelligence Model": "Document Intelligence 模型", "Documentation": "說明檔案", - "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.": "請勿從您無法信任的來源擷取任意管線。", @@ -495,11 +502,14 @@ "Done": "完成", "Download": "下載", "Download & Delete": "下載並刪除", + "Download as JSON": "", "Download as SVG": "以 SVG 格式下載", "Download canceled": "已取消下載", "Download Database": "下載資料庫", + "Downloading stats...": "", "Draw": "平手", "Drop any files here to upload": "拖曳檔案至此處進行上傳", + "DuckDuckGo": "", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "例如:'30s'、'10m'。有效的時間單位為 's'、'm'、'h'。", "e.g. \"json\" or a JSON schema": "範例:\"json\" 或一個 JSON schema", "e.g. 60": "例如:60", @@ -574,6 +584,7 @@ "Enter Bocha Search API Key": "輸入 Bocha 搜尋 API 金鑰", "Enter Brave Search API Key": "輸入 Brave 搜尋 API 金鑰", "Enter certificate path": "輸入憑證路徑", + "Enter Chunk Min Size Target": "", "Enter Chunk Overlap": "輸入區塊重疊", "Enter Chunk Size": "輸入區塊大小", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "輸入逗號分隔的 \"token:bias_value\" 配對 (範例:5432:100, 413:-100)", @@ -597,6 +608,7 @@ "Enter External Web Search URL": "輸入外部網路搜尋 URL", "Enter Firecrawl API Base URL": "輸入 Firecrawl API 基底 URL", "Enter Firecrawl API Key": "輸入 Firecrawl API 金鑰", + "Enter Firecrawl Timeout": "", "Enter folder name": "輸入分組名稱", "Enter function name filter list (e.g. func1, !func2)": "輸入函式名稱篩選列表(例如:func1, !func2)", "Enter Github Raw URL": "輸入 GitHub Raw URL", @@ -605,6 +617,7 @@ "Enter hex color (e.g. #FF0000)": "輸入十六進制色彩(例如:#FF0000)", "Enter ID": "輸入 ID", "Enter Image Size (e.g. 512x512)": "輸入圖片尺寸(例如:512x512)", + "Enter Jina API Base URL": "", "Enter Jina API Key": "輸入 Jina API 金鑰", "Enter JSON config (e.g., {\"disable_links\": true})": "輸入 JSON 設定(例如:{\"disable_links\": true})", "Enter Jupyter Password": "輸入 Jupyter 密碼", @@ -613,6 +626,8 @@ "Enter Kagi Search API Key": "輸入 Kagi 搜尋 API 金鑰", "Enter Key Behavior": "Enter 鍵行為", "Enter language codes": "輸入語言代碼", + "Enter max file count per folder": "", + "Enter MinerU API Key": "", "Enter Mistral API Base URL": "輸入 Mistral API 基底 URL", "Enter Mistral API Key": "輸入 Mistral API 金鑰", "Enter Model ID": "輸入模型 ID", @@ -738,6 +753,7 @@ "Failed to generate title": "產生標題失敗", "Failed to import models": "匯入模型失敗", "Failed to load chat preview": "對話預覽載入失敗", + "Failed to load Excel/CSV file. Please try downloading it instead.": "", "Failed to load file content.": "載入檔案內容失敗。", "Failed to move chat": "移動對話失敗", "Failed to process URL: {{url}}": "處理鏈接失敗: {{url}}", @@ -754,10 +770,10 @@ "Features": "功能", "Features Permissions": "功能權限", "February": "2 月", + "Feedback": "", "Feedback deleted successfully": "成功刪除回饋", "Feedback Details": "回饋詳情", "Feedback History": "回饋歷史", - "Feedbacks": "回饋", "Feel free to add specific details": "歡迎自由新增特定細節", "Female": "女性", "File": "檔案", @@ -778,11 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "偵測到指紋偽造:無法使用姓名縮寫作為大頭貼。將預設為預設個人檔案圖片。", "Firecrawl API Base URL": "Firecrawl API 基底 URL", "Firecrawl API Key": "Firecrawl API 金鑰", + "Firecrawl Timeout (s)": "", "Floating Quick Actions": "浮動快速操作", "Focus Chat Input": "聚焦對話輸入框", "Folder": "分組", "Folder Background Image": "分組背景圖", "Folder deleted successfully": "成功刪除分組", + "Folder Max File Count": "", "Folder Name": "分組名稱", "Folder name cannot be empty.": "分組名稱不能為空。", "Folder name updated successfully": "成功更新分組名稱", @@ -828,7 +846,6 @@ "General": "一般", "Generate": "生成", "Generate an image": "生成圖片", - "Generate Image": "生成圖片", "Generate Message Pair": "生成訊息對", "Generated Image": "生成圖片", "Generating search query": "正在生成搜尋查詢", @@ -838,11 +855,13 @@ "Get started with {{WEBUI_NAME}}": "開始使用 {{WEBUI_NAME}}", "Global": "全域", "Good Response": "回應良好", + "Google": "", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API 金鑰", "Google PSE Engine Id": "Google PSE 引擎 ID", "Gravatar": "Gravatar 大頭貼", "Grid": "網格", + "Grokipedia": "", "Group": "群組", "Group Channel": "群組頻道", "Group created successfully": "成功建立群組", @@ -897,7 +916,6 @@ "Image Prompt Generation": "圖片提示詞生成", "Image Prompt Generation Prompt": "生成圖片提示詞的提示詞", "Image Size": "圖片尺寸", - "Images": "圖片", "Import": "匯入", "Import Chats": "匯入對話紀錄", "Import Config from JSON File": "從 JSON 檔案匯入設定", @@ -929,6 +947,7 @@ "Integration": "整合", "Integrations": "外掛功能", "Interface": "介面", + "Interface Settings Access": "", "Invalid file content": "檔案內容無效", "Invalid file format.": "檔案格式無效。", "Invalid JSON file": "JSON 檔案無效", @@ -942,6 +961,7 @@ "is typing...": "正在輸入...", "Italic": "斜體", "January": "1 月", + "Jina API Base URL": "", "Jina API Key": "Jina API 金鑰", "join our Discord for help.": "加入我們的 Discord 以取得協助。", "JSON": "JSON", @@ -992,6 +1012,7 @@ "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 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.": "留空模型欄位以使用預設模型。", @@ -1031,10 +1052,12 @@ "Manage your account information.": "管理您的帳號資訊。", "March": "3 月", "Markdown": "Markdown", - "Markdown (Header)": "Markdown(標題)", + "Markdown Header Text Splitter": "", "Max Speakers": "最大發言者數量", "Max Upload Count": "最大上傳數量", "Max Upload Size": "最大上傳大小", + "Maximum number of files allowed per folder.": "", + "Maximum number of files per folder is {{max}}.": "", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "最多同時下載 3 個模型。請稍後再試。", "May": "5 月", "MBR": "成員", @@ -1044,6 +1067,7 @@ "Member removed successfully": "成功移除成員", "Members": "成員", "Members added successfully": "成功新增成員", + "Memories": "", "Memories accessible by LLMs will be shown here.": "可被大型語言模型存取的記憶將顯示在此。", "Memory": "記憶", "Memory added successfully": "成功新增記憶", @@ -1101,6 +1125,7 @@ "Models imported successfully": "已成功匯入模型", "Models Public Sharing": "模型公開分享", "Models Sharing": "分享模型", + "Mojeek": "", "Mojeek Search API Key": "Mojeek 搜尋 API 金鑰", "More": "更多", "More Concise": "精煉表達", @@ -1134,7 +1159,7 @@ "No conversation to save": "沒有可儲存的對話", "No distance available": "無可用距離", "No expiration can pose security risks.": "未設定 JWT 到期時間可能造成安全風險。", - "No feedbacks found": "未找到回饋", + "No feedback found": "", "No file selected": "未選取檔案", "No files in this knowledge base.": "此知識庫中沒有文件。", "No functions found": "未找到函式", @@ -1149,6 +1174,7 @@ "No models selected": "未選取模型", "No Notes": "尚無筆記", "No notes found": "沒有任何筆記", + "No one": "", "No pinned messages": "沒有置頂訊息", "No prompts found": "未找到提示詞", "No results": "沒有結果", @@ -1200,6 +1226,7 @@ "Only invited users can access": "只有受邀使用者可以存取", "Only markdown files are allowed": "僅允許 Markdown 檔案", "Only select users and groups with permission can access": "只有具有權限的選定使用者和群組可以存取", + "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.": "哎呀!之前的回應有一處錯誤。", @@ -1241,6 +1268,7 @@ "page": "頁面", "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.": "參與社群排行榜和評估!同步聚合的使用統計資料有助於推動 Open WebUI 的研究和改進。您的隱私至關重要:絕不會分享訊息內容。", "Password": "密碼", "Passwords do not match.": "兩次輸入的密碼不一致。", @@ -1267,7 +1295,6 @@ "Pipe": "Pipe", "Pipeline deleted successfully": "成功刪除管線", "Pipeline downloaded successfully": "成功下載管線", - "Pipelines": "管線", "Pipelines are a plugin system with arbitrary code execution —": "管線是具任意程式碼執行風險的外掛系統 —", "Pipelines Not Detected": "未偵測到管線", "Pipelines Valves": "管線設定項目", @@ -1504,6 +1531,7 @@ "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.": "設定要使用的停止序列。當遇到此模式時,大型語言模型將停止生成文字並返回。可以在模型檔案中指定多個單獨的停止參數來設定多個停止模式。", "Setting": "設定", "Settings": "設定", + "Settings Permissions": "", "Settings saved successfully!": "設定已成功儲存!", "Share": "分享", "Share Chat": "分享對話", @@ -1547,6 +1575,7 @@ "Speech recognition error: {{error}}": "語音辨識錯誤:{{error}}", "Speech-to-Text": "語音轉文字 (STT) ", "Speech-to-Text Engine": "語音轉文字 (STT) 引擎", + "Split documents by markdown headers before applying character/token splitting.": "", "Start a new conversation": "開始新對話", "Start of the channel": "頻道起點", "Start Tag": "起始標籤", @@ -1557,6 +1586,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "迭代步數", "Stop": "停止", + "Stop Download": "", "Stop Generating": "停止生成", "Stop Sequence": "停止序列", "Stream Chat Response": "串流式對話回應", @@ -1580,8 +1610,11 @@ "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.": "", "System": "系統", "System Instructions": "系統指令", "System Prompt": "系統提示詞", @@ -1626,6 +1659,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "BM25 混合搜尋權重。0 更語意化,1 更關鍵詞化。預設 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.": "", "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}} 頻道的起點。", @@ -1816,9 +1850,11 @@ "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": "", "Why?": "為什麼?", "Widescreen Mode": "寬螢幕模式", "Width": "寬度", + "Wikipedia": "", "Won": "獲勝", "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": "工作區", @@ -1830,6 +1866,8 @@ "Yacy Instance URL": "Yacy 執行個體 URL", "Yacy Password": "Yacy 密碼", "Yacy Username": "Yacy 使用者名稱", + "Yahoo": "", + "Yandex": "", "Yesterday": "昨天", "Yesterday at {{LOCALIZED_TIME}}": "昨天 {{LOCALIZED_TIME}}", "You": "您", @@ -1837,6 +1875,9 @@ "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.": "您可以透過下方的「管理」按鈕新增記憶,將您與大型語言模型的互動個人化,讓它們更有幫助並更符合您的需求。", "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 save this prompt.": "", "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.": "您沒有權限上傳檔案到此知識庫。", @@ -1849,7 +1890,7 @@ "Your account status is currently pending activation.": "您的帳號目前正在等待啟用。", "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 with the Open WebUI Community.": "您的使用統計資料已成功同步至 Open WebUI 社群。", + "Your usage stats have been successfully synced.": "", "YouTube": "YouTube", "Youtube Language": "YouTube 語言", "Youtube Proxy URL": "YouTube 代理伺服器 URL" diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index 1e148972c3..a7a0fca32e 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -357,9 +357,9 @@ export const generateInitialsImage = (name) => { const initials = sanitizedName.length > 0 ? sanitizedName[0] + - (sanitizedName.split(' ').length > 1 - ? sanitizedName[sanitizedName.lastIndexOf(' ') + 1] - : '') + (sanitizedName.split(' ').length > 1 + ? sanitizedName[sanitizedName.lastIndexOf(' ') + 1] + : '') : ''; ctx.fillText(initials.toUpperCase(), canvas.width / 2, canvas.height / 2); @@ -515,10 +515,10 @@ export const compareVersion = (latest, current) => { return current === '0.0.0' ? false : current.localeCompare(latest, undefined, { - numeric: true, - sensitivity: 'case', - caseFirst: 'upper' - }) < 0; + numeric: true, + sensitivity: 'case', + caseFirst: 'upper' + }) < 0; }; export const extractCurlyBraceWords = (text) => { diff --git a/src/lib/utils/marked/citation-extension.ts b/src/lib/utils/marked/citation-extension.ts index ca8325fe11..ea714e5447 100644 --- a/src/lib/utils/marked/citation-extension.ts +++ b/src/lib/utils/marked/citation-extension.ts @@ -31,7 +31,7 @@ export function citationExtension() { while ((m = groupRegex.exec(raw))) { // m[1] is the content inside brackets, e.g. "1, 2#foo" const parts = m[1].split(',').map((p) => p.trim()); - + parts.forEach((part) => { // Check if it starts with digit const match = /^(\d+)(?:#(.+))?$/.exec(part); @@ -45,7 +45,7 @@ export function citationExtension() { } }); } - + if (ids.length === 0) return; return { From ae56bca7c5dcd2639b2378238579d2de9a8b5d5f Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Wed, 7 Jan 2026 23:29:18 +0100 Subject: [PATCH 175/254] Update translation.json (#20472) --- src/lib/i18n/locales/de-DE/translation.json | 134 ++++++++++---------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 146c1ebcba..7128974dd2 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -77,7 +77,7 @@ "Adjusting these settings will apply changes universally to all users.": "Das Anpassen dieser Einstellungen wendet Änderungen universell auf alle Benutzer an.", "admin": "Administrator", "Admin": "Administrator", - "Admin Contact Email": "", + "Admin Contact Email": "Admin Kontakt E-Mail", "Admin Panel": "Admin-Bereich", "Admin Settings": "Admin-Einstellungen", "Admins have access to all tools at all times; users need tools assigned per model in the workspace.": "Administratoren haben jederzeit Zugriff auf alle Werkzeuge; Benutzern müssen Werkzeuge pro Modell im Arbeitsbereich zugewiesen werden.", @@ -130,7 +130,7 @@ "and {{COUNT}} more": "und {{COUNT}} weitere", "and create a new shared link.": "und erstellen Sie einen neuen Freigabe-Link.", "Android": "Android", - "Anyone": "", + "Anyone": "Jeder", "API Base URL": "API-Basis-URL", "API Base URL for Datalab Marker service. Defaults to: https://www.datalab.to/api/v1/marker": "API-Basis-URL für den Datalab Marker-Dienst. Standardwert: https://www.datalab.to/api/v1/marker", "API Key": "API-Schlüssel", @@ -176,7 +176,7 @@ "Authenticate": "Authentifizieren", "Authentication": "Authentifizierung", "Auto": "Automatisch", - "Auto (Random)": "", + "Auto (Random)": "Auto (zufällig)", "Auto-Copy Response to Clipboard": "Antwort autom. in Zwischenablage kopieren", "Auto-playback response": "Antwort automatisch abspielen", "Autocomplete Generation": "Autovervollständigung", @@ -185,7 +185,7 @@ "AUTOMATIC1111 Api Auth String": "AUTOMATIC1111 API-Auth-String", "AUTOMATIC1111 Base URL": "AUTOMATIC1111 Basis-URL", "AUTOMATIC1111 Base URL is required.": "AUTOMATIC1111 Basis-URL ist erforderlich.", - "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "", + "Automatically inject system tools in native function calling mode (e.g., timestamps, memory, chat history, notes, etc.)": "Automatische Injektion von System-Werkzeugen bei nativen Funktionsaufrufen (z. B. Zeitstempel, Erinnerungen, Chatverlauf, Notizen etc.)", "Available list": "Verfügbare Liste", "Available Tools": "Verfügbare Werkzeuge", "available users": "verfügbare Benutzer", @@ -204,7 +204,7 @@ "before": "zuvor", "Being lazy": "Faulheit", "Beta": "Beta", - "Bing": "", + "Bing": "Bing", "Bing Search V7 Endpoint": "Bing Search V7 Endpunkt", "Bing Search V7 Subscription Key": "Bing Search V7 Abonnement-Schlüssel", "Bio": "Biografie", @@ -213,9 +213,9 @@ "Bocha Search API Key": "Bocha Search API-Schlüssel", "Bold": "Fett", "Boosting or penalizing specific tokens for constrained responses. Bias values will be clamped between -100 and 100 (inclusive). (Default: none)": "Bevorzugung oder Benachteiligung spezifischer Token für die Antwortsteuerung. Bias-Werte werden zwischen -100 und 100 (inklusive) begrenzt. (Standard: keine)", - "Brave": "", + "Brave": "Brave", "Brave Search API Key": "Brave Search API-Schlüssel", - "Builtin Tools": "", + "Builtin Tools": "Eingebaute Werkzeuge", "Bullet List": "Aufzählungsliste", "Button ID": "Schaltflächen-ID", "Button Label": "Schaltflächenbeschriftung", @@ -262,10 +262,10 @@ "Check for updates": "Nach Updates suchen", "Checking for updates...": "Suche nach Updates...", "Choose a model before saving...": "Wählen Sie vor dem Speichern ein Modell...", - "Chunk Min Size Target": "", + "Chunk Min Size Target": "Zielwert für minimale Chunk-Größe", "Chunk Overlap": "Chunk-Überlappung", "Chunk Size": "Chunk-Größe", - "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 unterhalb dieser Grenze werden, sofern möglich, mit angrenzenden Chunks verschmolzen. Zum Deaktivieren den Wert 0 wählen.", "Ciphers": "Chiffren", "Citation": "Zitat", "Citations": "Zitate", @@ -343,7 +343,7 @@ "Contact Admin for WebUI Access": "Kontaktieren Sie den Administrator für WebUI-Zugriff", "Content": "Inhalt", "Content Extraction Engine": "Engine zur Inhaltsextraktion", - "Content lengths (character counts only)": "", + "Content lengths (character counts only)": "Content-Längen (nur Zeichen)", "Continue Response": "Antwort fortsetzen", "Continue with {{provider}}": "Mit {{provider}} fortfahren", "Continue with Email": "Mit E-Mail fortfahren", @@ -401,7 +401,7 @@ "Database": "Datenbank", "Datalab Marker API": "Datalab Marker API", "DD/MM/YYYY": "TT.MM.JJJJ", - "DDGS Backend": "", + "DDGS Backend": "DDGS Backend", "December": "Dezember", "Decrease UI Scale": "UI-Skalierung verringern", "Deepgram": "Deepgram", @@ -483,7 +483,7 @@ "Dive into knowledge": "In Wissen eintauchen", "Do not install functions from sources you do not fully trust.": "Installieren Sie keine Funktionen aus nicht vertrauenswürdigen Quellen.", "Do not install tools from sources you do not fully trust.": "Installieren Sie keine Werkzeuge aus nicht vertrauenswürdigen Quellen.", - "Do you want to sync your usage stats with Open WebUI Community?": "", + "Do you want to sync your usage stats with Open WebUI Community?": "Möchten Sie Ihre Nutzungsstatistiken mit der Open WebUI Community synchronisieren?", "Docling": "Docling", "Docling Parameters": "Docling-Parameter", "Docling Server URL required.": "Docling Server-URL erforderlich.", @@ -502,14 +502,14 @@ "Done": "Fertig", "Download": "Herunterladen", "Download & Delete": "Herunterladen & Löschen", - "Download as JSON": "", + "Download as JSON": "Als JSON herunterladen", "Download as SVG": "Als SVG herunterladen", "Download canceled": "Download abgebrochen", "Download Database": "Datenbank herunterladen", - "Downloading stats...": "", + "Downloading stats...": "Statistik wird heruntergeladen...", "Draw": "Zeichnen", "Drop any files here to upload": "Dateien zum Hochladen hier ablegen", - "DuckDuckGo": "", + "DuckDuckGo": "DuckDuckGo", "e.g. '30s','10m'. Valid time units are 's', 'm', 'h'.": "z. B. '30s', '10m'. Gültig: 's', 'm', 'h'.", "e.g. \"json\" or a JSON schema": "z. B. \"json\" oder ein JSON-Schema", "e.g. 60": "z. B. 60", @@ -584,7 +584,7 @@ "Enter Bocha Search API Key": "Bocha Search API-Schlüssel eingeben", "Enter Brave Search API Key": "Brave Search API-Schlüssel eingeben", "Enter certificate path": "Zertifikatpfad eingeben", - "Enter Chunk Min Size Target": "", + "Enter Chunk Min Size Target": "Zielwert für minimale Chunk-Größe eingeben", "Enter Chunk Overlap": "Chunk-Überlappung eingeben", "Enter Chunk Size": "Chunk-Größe eingeben", "Enter comma-separated \"token:bias_value\" pairs (example: 5432:100, 413:-100)": "Kommagetrennte \"token:bias_value\"-Paare eingeben (Bsp: 5432:100, 413:-100)", @@ -608,7 +608,7 @@ "Enter External Web Search URL": "URL für ext. Websuche", "Enter Firecrawl API Base URL": "Firecrawl API Basis-URL eingeben", "Enter Firecrawl API Key": "Firecrawl API-Schlüssel eingeben", - "Enter Firecrawl Timeout": "", + "Enter Firecrawl Timeout": "Firecrawl Timeout eingeben", "Enter folder name": "Ordnername eingeben", "Enter function name filter list (e.g. func1, !func2)": "Funktionsnamen-Filterliste eingeben (z. B. func1, !func2)", "Enter Github Raw URL": "Github Raw URL eingeben", @@ -617,7 +617,7 @@ "Enter hex color (e.g. #FF0000)": "Hex-Farbe eingeben (z. B. #FF0000)", "Enter ID": "ID eingeben", "Enter Image Size (e.g. 512x512)": "Bildgröße eingeben (z. B. 512x512)", - "Enter Jina API Base URL": "", + "Enter Jina API Base URL": "Jina API Base URL eingeben", "Enter Jina API Key": "Jina API-Schlüssel eingeben", "Enter JSON config (e.g., {\"disable_links\": true})": "JSON-Konfig eingeben (z. B. {\"disable_links\": true})", "Enter Jupyter Password": "Jupyter-Passwort eingeben", @@ -626,8 +626,8 @@ "Enter Kagi Search API Key": "Kagi Search API-Schlüssel eingeben", "Enter Key Behavior": "Eingabetasten-Verhalten", "Enter language codes": "Sprachcodes eingeben", - "Enter max file count per folder": "", - "Enter MinerU API Key": "", + "Enter max file count per folder": "Maximale Anzahl an Dateien pro Ordner eingeben", + "Enter MinerU API Key": "MinerU-API-Schlüssel eingeben", "Enter Mistral API Base URL": "Mistral API Basis-URL eingeben", "Enter Mistral API Key": "Mistral API-Schlüssel eingeben", "Enter Model ID": "Modell-ID eingeben", @@ -753,7 +753,7 @@ "Failed to generate title": "Titel konnte nicht generiert werden", "Failed to import models": "Modelle konnten nicht importiert werden", "Failed to load chat preview": "Chat-Vorschau konnte nicht geladen werden", - "Failed to load Excel/CSV file. Please try downloading it instead.": "", + "Failed to load Excel/CSV file. Please try downloading it instead.": "Excel/CSV-Datei konnte nicht geladen werden. Bitte versuchen Sie stattdessen, sie herunterzuladen.", "Failed to load file content.": "Dateiinhalt konnte nicht geladen werden.", "Failed to move chat": "Chat konnte nicht verschoben werden", "Failed to process URL: {{url}}": "{{url}} konnte nicht verarbeitet werden", @@ -770,7 +770,7 @@ "Features": "Funktionen", "Features Permissions": "Funktionsberechtigungen", "February": "Februar", - "Feedback": "", + "Feedback": "Feedback", "Feedback deleted successfully": "Feedback erfolgreich gelöscht", "Feedback Details": "Feedback-Details", "Feedback History": "Feedback-Verlauf", @@ -794,13 +794,13 @@ "Fingerprint spoofing detected: Unable to use initials as avatar. Defaulting to default profile image.": "Fingerabdruck-Spoofing erkannt: Initialen können nicht verwendet werden. Nutze Standard-Profilbild.", "Firecrawl API Base URL": "Firecrawl API Basis-URL", "Firecrawl API Key": "Firecrawl API-Schlüssel", - "Firecrawl Timeout (s)": "", + "Firecrawl Timeout (s)": "Firecrawl Timeout (s)", "Floating Quick Actions": "Schwebende Schnellaktionen", "Focus Chat Input": "Chat-Eingabe fokussieren", "Folder": "Ordner", "Folder Background Image": "Ordner-Hintergrundbild", "Folder deleted successfully": "Ordner erfolgreich gelöscht", - "Folder Max File Count": "", + "Folder Max File Count": "Maximale Dateianzahl pro Ordner", "Folder Name": "Ordnername", "Folder name cannot be empty.": "Ordnername darf nicht leer sein.", "Folder name updated successfully": "Ordnername erfolgreich aktualisiert", @@ -855,13 +855,13 @@ "Get started with {{WEBUI_NAME}}": "Loslegen mit {{WEBUI_NAME}}", "Global": "Global", "Good Response": "Gute Antwort", - "Google": "", + "Google": "Google", "Google Drive": "Google Drive", "Google PSE API Key": "Google PSE API-Schlüssel", "Google PSE Engine Id": "Google PSE Engine-ID", "Gravatar": "Gravatar", "Grid": "Raster", - "Grokipedia": "", + "Grokipedia": "Grokipedia", "Group": "Gruppe", "Group Channel": "Gruppenkanal", "Group created successfully": "Gruppe erfolgreich erstellt", @@ -947,7 +947,7 @@ "Integration": "Integration", "Integrations": "Integrationen", "Interface": "Benutzeroberfläche", - "Interface Settings Access": "", + "Interface Settings Access": "Zugriff auf Oberflächeneinstellungen", "Invalid file content": "Ungültiger Dateiinhalt", "Invalid file format.": "Ungültiges Dateiformat.", "Invalid JSON file": "Ungültige JSON-Datei", @@ -961,7 +961,7 @@ "is typing...": "schreibt ...", "Italic": "Kursiv", "January": "Januar", - "Jina API Base URL": "", + "Jina API Base URL": "Jina API Base URL", "Jina API Key": "Jina-API-Schlüssel", "join our Discord for help.": "Treten Sie unserem Discord bei, um Hilfe zu erhalten.", "JSON": "JSON", @@ -1012,7 +1012,7 @@ "Leave empty to include all models from \"{{url}}/api/tags\" endpoint": "Leer lassen, um alle Modelle vom Endpunkt \"{{url}}/api/tags\" einzuschließen", "Leave empty to include all models from \"{{url}}/models\" endpoint": "Leer lassen, um alle Modelle vom Endpunkt \"{{url}}/models\" einzuschließen", "Leave empty to include all models or select specific models": "Leer lassen, um alle Modelle einzuschließen oder spezifische Modelle auszuwählen", - "Leave empty to use first admin user": "", + "Leave empty to use first admin user": "Leer lassen, um den ersten Administrator zu verwenden", "Leave empty to use the default model (voxtral-mini-latest).": "Leer lassen, um das Standardmodell zu nutzen (voxtral-mini-latest).", "Leave empty to use the default prompt, or enter a custom prompt": "Leer lassen, um den Standard-Prompt zu verwenden, oder geben Sie einen eigenen Prompt ein", "Leave model field empty to use the default model.": "Leer lassen, um das Standardmodell zu verwenden.", @@ -1052,12 +1052,12 @@ "Manage your account information.": "Verwalten Sie Ihre Kontoinformationen.", "March": "März", "Markdown": "Markdown", - "Markdown Header Text Splitter": "", + "Markdown Header Text Splitter": "Markdown-Header-Text-Splitter", "Max Speakers": "Max. Sprecher", "Max Upload Count": "Max. Anzahl Uploads", "Max Upload Size": "Max. Uploadgröße", - "Maximum number of files allowed per folder.": "", - "Maximum number of files per folder is {{max}}.": "", + "Maximum number of files allowed per folder.": "Maximale Anzahl der pro Ordner erlaubten Dateien.", + "Maximum number of files per folder is {{max}}.": "Die maximale Anzahl der Dateien pro Ordner ist {{max}}.", "Maximum of 3 models can be downloaded simultaneously. Please try again later.": "Es können maximal 3 Modelle gleichzeitig heruntergeladen werden. Bitte versuchen Sie es später erneut.", "May": "Mai", "MBR": "MBR", @@ -1067,7 +1067,7 @@ "Member removed successfully": "Mitglied erfolgreich entfernt", "Members": "Mitglieder", "Members added successfully": "Mitglieder erfolgreich hinzugefügt", - "Memories": "", + "Memories": "Erinnerungen", "Memories accessible by LLMs will be shown here.": "Erinnerungen, auf die LLMs zugreifen können, werden hier angezeigt.", "Memory": "Erinnerungen", "Memory added successfully": "Erinnerung erfolgreich hinzugefügt", @@ -1077,7 +1077,7 @@ "Merge Responses": "Antworten zusammenführen", "Merged Response": "Zusammengeführte Antwort", "Message": "Nachricht", - "Message counts and response timestamps": "", + "Message counts and response timestamps": "Nachrichtenanzahl und Antwort-Zeitstempel", "Message rating should be enabled to use this feature": "Nachrichtenbewertung muss aktiviert sein, um diese Funktion zu nutzen", "Messages you send after creating your link won't be shared. Users with the URL will be able to view the shared chat.": "Nachrichten, die Sie nach dem Erstellen des Links senden, werden nicht geteilt. Benutzer mit der URL können nur den bis dahin geteilten Chat sehen.", "Microsoft OneDrive": "Microsoft OneDrive", @@ -1110,11 +1110,11 @@ "Model Name": "Modellname", "Model name already exists, please choose a different one": "Modellname existiert bereits, bitte wählen Sie einen anderen", "Model Name is required.": "Modellname ist erforderlich.", - "Model names and usage frequency": "", + "Model names and usage frequency": "Modellnamen und Nutzungshäufigkeit", "Model not selected": "Kein Modell ausgewählt", "Model Params": "Modell-Parameter", "Model Permissions": "Modellberechtigungen", - "Model responses or outputs": "", + "Model responses or outputs": "Modellantworten oder -ausgaben", "Model unloaded successfully": "Modell erfolgreich entladen", "Model updated successfully": "Modell erfolgreich aktualisiert", "Model(s) do not support file upload": "Modell(e) unterstützen keinen Dateiupload", @@ -1125,7 +1125,7 @@ "Models imported successfully": "Modelle erfolgreich importiert", "Models Public Sharing": "Öffentliche Freigabe von Modellen", "Models Sharing": "Modelle teilen", - "Mojeek": "", + "Mojeek": "Mojeek", "Mojeek Search API Key": "Mojeek Search API-Schlüssel", "More": "Mehr", "More Concise": "Kürzer", @@ -1159,7 +1159,7 @@ "No conversation to save": "Keine Unterhaltung zum Speichern vorhanden", "No distance available": "Keine Distanz verfügbar", "No expiration can pose security risks.": "Ein fehlendes Ablaufdatum kann Sicherheitsrisiken bergen.", - "No feedback found": "", + "No feedback found": "Kein Feedback gefunden", "No file selected": "Keine Datei ausgewählt", "No files in this knowledge base.": "Keine Dateien in diesem Wissensspeicher", "No functions found": "Keine Funktionen gefunden", @@ -1174,7 +1174,7 @@ "No models selected": "Keine Modelle ausgewählt", "No Notes": "Keine Notizen", "No notes found": "Keine Notizen gefunden", - "No one": "", + "No one": "Niemand", "No pinned messages": "Keine angehefteten Nachrichten", "No prompts found": "Keine Prompts gefunden", "No results": "Keine Ergebnisse", @@ -1226,7 +1226,7 @@ "Only invited users can access": "Nur eingeladene Benutzer haben Zugriff", "Only markdown files are allowed": "Nur Markdown-Dateien sind erlaubt", "Only select users and groups with permission can access": "Nur ausgewählte Benutzer und Gruppen mit Berechtigung haben Zugriff", - "Only sync new/updated chats": "", + "Only sync new/updated chats": "Nur neue/aktualisierte Chats synchronisieren", "Oops! Looks like the URL is invalid. Please double-check and try again.": "Ups! Die URL scheint ungültig zu sein. Bitte überprüfen Sie diese und versuchen Sie es erneut.", "Oops! There are files still uploading. Please wait for the upload to complete.": "Ups! Es werden noch Dateien hochgeladen. Bitte warten Sie, bis der Upload abgeschlossen ist.", "Oops! There was an error in the previous response.": "Ups! Es gab einen Fehler in der vorherigen Antwort.", @@ -1243,7 +1243,7 @@ "Open WebUI can use tools provided by any OpenAPI server.": "Open WebUI kann Werkzeuge verwenden, die von jedem OpenAPI-Server bereitgestellt werden.", "Open WebUI uses faster-whisper internally.": "Open WebUI verwendet intern faster-whisper.", "Open WebUI uses SpeechT5 and CMU Arctic speaker embeddings.": "Open WebUI verwendet SpeechT5 und CMU Arctic Speaker-Embeddings.", - "Open WebUI version": "", + "Open WebUI version": "Open WebUI Version", "Open WebUI version (v{{OPEN_WEBUI_VERSION}}) is lower than required version (v{{REQUIRED_VERSION}})": "Die installierte Open-WebUI-Version (v{{OPEN_WEBUI_VERSION}}) ist niedriger als die erforderliche Version (v{{REQUIRED_VERSION}})", "OpenAI": "OpenAI", "OpenAI API": "OpenAI-API", @@ -1268,8 +1268,8 @@ "page": "Seite", "Paginate": "Paginieren", "Parameters": "Parameter", - "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": "Übergeordnete Nachricht nicht gefunden", + "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.": "Nehmen Sie an Community-Bestenlisten und Evaluationen teil! Das Synchronisieren aggregierter Nutzungsstatistiken hilft dabei, die Forschung und Verbesserungen von Open WebUI voranzutreiben. Ihre Privatsphäre steht an erster Stelle: Es werden niemals Nachrichteninhalte geteilt.", "Password": "Passwort", "Passwords do not match.": "Die Passwörter stimmen nicht überein.", "Paste Large Text as File": "Großen Text als Datei einfügen", @@ -1532,7 +1532,7 @@ "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.": "Legt die zu verwendenden Stoppsequenzen fest. Wenn dieses Muster erkannt wird, stoppt das LLM die Textgenerierung. Mehrere Stoppmuster können durch separate Stopp-Parameter in einer Modelldatei angegeben werden.", "Setting": "Einstellung", "Settings": "Einstellungen", - "Settings Permissions": "", + "Settings Permissions": "Berechtigungen für Einstellungen", "Settings saved successfully!": "Einstellungen erfolgreich gespeichert!", "Share": "Teilen", "Share Chat": "Chat teilen", @@ -1576,7 +1576,7 @@ "Speech recognition error: {{error}}": "Spracherkennungsfehler: {{error}}", "Speech-to-Text": "Sprache-zu-Text", "Speech-to-Text Engine": "Sprache-zu-Text-Engine", - "Split documents by markdown headers before applying character/token splitting.": "", + "Split documents by markdown headers before applying character/token splitting.": "Dokumente nach Markdown-Überschriften trennen, bevor die Segmentierung nach Zeichen oder Tokens angewendet wird.", "Start a new conversation": "Neue Unterhaltung beginnen", "Start of the channel": "Beginn des Kanals", "Start Tag": "Start-Tag", @@ -1587,7 +1587,7 @@ "STDOUT/STDERR": "STDOUT/STDERR", "Steps": "Schritte", "Stop": "Stopp", - "Stop Download": "", + "Stop Download": "Download stoppen", "Stop Generating": "Generierung stoppen", "Stop Sequence": "Stoppsequenz", "Stream Chat Response": "Chat-Antwort streamen", @@ -1608,14 +1608,14 @@ "Support": "Unterstützung", "Support this plugin:": "Unterstützen Sie dieses Plugin:", "Supported MIME Types": "Unterstützte MIME-Typen", - "Sync": "", - "Sync Complete!": "", + "Sync": "Synchronisieren", + "Sync Complete!": "Synchronisierung abgeschlossen!", "Sync directory": "Verzeichnis synchronisieren", - "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": "Synchronisierung fehlgeschlagen", + "Sync Usage Stats": "Nutzungsstatistiken synchronisieren", + "Syncing stats...": "Statistiken werden synchronisiert …", + "Syncing...": "Synchronisierung läuft …", + "Syncs only chats with updates after your last sync timestamp. Disable to re-sync all chats.": "Synchronisiert nur Chats mit Änderungen seit dem letzten Abgleich. Deaktivieren, um alle Chats neu zu synchronisieren.", "System": "System", "System Instructions": "Systemanweisungen", "System Prompt": "System-Prompt", @@ -1660,7 +1660,7 @@ "The Weight of BM25 Hybrid Search. 0 more semantic, 1 more lexical. Default 0.5": "Die Gewichtung der BM25-Hybridsuche. 0 ist semantischer, 1 ist lexikalischer. Standard ist 0.5.", "The width in pixels to compress images to. Leave empty for no compression.": "Die Breite in Pixeln, auf die Bilder komprimiert werden sollen. Leer lassen für keine Kompression.", "Theme": "Design", - "There was an error syncing your stats. Please try again.": "", + "There was an error syncing your stats. Please try again.": "Beim Synchronisieren Ihrer Statistiken ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.", "Thinking...": "Denke nach...", "This action cannot be undone. Do you wish to continue?": "Diese Aktion kann nicht rückgängig gemacht werden. Möchten Sie fortfahren?", "This channel was created on {{createdAt}}. This is the very beginning of the {{channelName}} channel.": "Dieser Kanal wurde am {{createdAt}} erstellt. Dies ist der Anfang des Kanals {{channelName}}.", @@ -1775,7 +1775,7 @@ "Upload Pipeline": "Pipeline hochladen", "Upload Progress": "Upload-Fortschritt", "Upload Progress: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)": "Fortschritt: {{uploadedFiles}}/{{totalFiles}} ({{percentage}}%)", - "Uploaded files or images": "", + "Uploaded files or images": "Hochgeladene Dateien oder Bilder", "Uploading file...": "Datei wird hochgeladen...", "URL": "URL", "URL is required": "URL ist erforderlich", @@ -1793,7 +1793,7 @@ "User Groups": "Benutzergruppen", "User location successfully retrieved.": "Benutzerstandort erfolgreich abgerufen.", "User menu": "Benutzermenü", - "User ratings (thumbs up/down)": "", + "User ratings (thumbs up/down)": "Benutzerbewertungen (Daumen hoch/runter)", "User Webhooks": "Benutzer-Webhooks", "Username": "Benutzername", "users": "Benutzer", @@ -1843,19 +1843,19 @@ "WebUI will make requests to \"{{url}}/chat/completions\"": "WebUI wird Anfragen an \"{{url}}/chat/completions\" senden", "What are you trying to achieve?": "Was möchten Sie erreichen?", "What are you working on?": "Woran arbeiten Sie?", - "What is NOT shared:": "", - "What is shared:": "", + "What is NOT shared:": "Was NICHT geteilt wird:", + "What is shared:": "Was geteilt wird:", "What's New in": "Neuigkeiten in", "What's on your mind?": "Was beschäftigt Sie?", "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.": "Wenn aktiviert, antwortet das Modell in Echtzeit auf jede Chat-Nachricht. Dieser Modus ist nützlich für Live-Chats, kann jedoch die Leistung auf langsamerer Hardware beeinträchtigen.", "wherever you are": "wo immer Sie sind", "Whether to paginate the output. Each page will be separated by a horizontal rule and page number. Defaults to False.": "Ob die Ausgabe paginiert werden soll. Jede Seite wird durch eine horizontale Linie und Seitennummer getrennt. Standard ist False.", "Whisper (Local)": "Whisper (Lokal)", - "Who can share to this group": "", + "Who can share to this group": "Wer Inhalte mit dieser Gruppe teilen kann", "Why?": "Warum?", "Widescreen Mode": "Breitbildmodus", "Width": "Breite", - "Wikipedia": "", + "Wikipedia": "Wikipedia", "Won": "Gewonnen", "Works together with top-k. A higher value (e.g., 0.95) will lead to more diverse text, while a lower value (e.g., 0.5) will generate more focused and conservative text.": "Funktioniert zusammen mit Top-K. Ein höherer Wert (z. B. 0.95) führt zu vielfältigerem Text, während ein niedrigerer Wert (z. B. 0.5) fokussierteren und konservativeren Text erzeugt.", "Workspace": "Arbeitsbereich", @@ -1867,8 +1867,8 @@ "Yacy Instance URL": "Yacy-Instanz-URL", "Yacy Password": "Yacy-Passwort", "Yacy Username": "Yacy-Benutzername", - "Yahoo": "", - "Yandex": "", + "Yahoo": "Yahoo", + "Yandex": "Yandex", "Yesterday": "Gestern", "Yesterday at {{LOCALIZED_TIME}}": "Gestern um {{LOCALIZED_TIME}}", "You": "Du", @@ -1876,9 +1876,9 @@ "You can only chat with a maximum of {{maxCount}} file(s) at a time.": "Sie können mit maximal {{maxCount}} Datei(en) gleichzeitig chatten.", "You can personalize your interactions with LLMs by adding memories through the 'Manage' button below, making them more helpful and tailored to you.": "Sie können Interaktionen mit LLMs personalisieren, indem Sie über die Schaltfläche \"Verwalten\" Erinnerungen hinzufügen.", "You cannot upload an empty file.": "Sie können keine leere Datei hochladen.", - "You do not have permission to edit this model": "", - "You do not have permission to edit this prompt.": "", - "You do not have permission to save this prompt.": "", + "You do not have permission to edit this model": "Sie haben keine Berechtigung, dieses Modell zu bearbeiten.", + "You do not have permission to edit this prompt.": "Sie haben keine Berechtigung, diesen Prompt zu bearbeiten.", + "You do not have permission to save this prompt.": "Sie haben keine Berechtigung, diesen Prompt zu speichern.", "You do not have permission to send messages in this channel.": "Sie haben keine Berechtigung, Nachrichten in diesem Kanal zu senden.", "You do not have permission to send messages in this thread.": "Sie haben keine Berechtigung, Nachrichten in diesem Thread zu senden.", "You do not have permission to upload files to this knowledge base.": "Sie haben keine Berechtigung, Dateien in diese Wissensspeicher hochzuladen.", @@ -1890,8 +1890,8 @@ "Your Account": "Ihr Konto", "Your account status is currently pending activation.": "Ihr Kontostatus wartet derzeit auf Aktivierung.", "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.": "Ihr gesamter Beitrag geht direkt an den Plugin-Entwickler; Open WebUI behält keinen Anteil ein. Die gewählte Plattform kann jedoch eigene Gebühren erheben.", - "Your message text or inputs": "", - "Your usage stats have been successfully synced.": "", + "Your message text or inputs": "Ihre Nachrichtentexte oder Eingaben", + "Your usage stats have been successfully synced.": "Ihre Nutzungsstatistiken wurden erfolgreich synchronisiert.", "YouTube": "YouTube", "Youtube Language": "YouTube-Sprache", "Youtube Proxy URL": "YouTube-Proxy-URL" From e7207c8f55888912c1515c6332710bf923fa363f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Thu, 8 Jan 2026 02:43:19 +0400 Subject: [PATCH 176/254] refac: styling --- src/lib/components/admin/Settings.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/components/admin/Settings.svelte b/src/lib/components/admin/Settings.svelte index d47b68ddee..5fe6f8bbe1 100644 --- a/src/lib/components/admin/Settings.svelte +++ b/src/lib/components/admin/Settings.svelte @@ -291,7 +291,7 @@ class="tabs mx-[16px] lg:mx-0 lg:px-[16px] flex flex-row overflow-x-auto gap-2.5 max-w-full lg:gap-1 lg:flex-col lg:flex-none lg:w-50 dark:text-gray-200 text-sm font-medium text-left scrollbar-none" >
+ + {#if !rankedModels.length && !loading} +
{$i18n.t('No models found')}
+ {:else if rankedModels.length} +
- - - - - - + + {#each [ + { key: 'rating', label: 'RK', class: 'w-3' }, + { key: 'name', label: 'Model', class: '' }, + { key: 'rating', label: 'Rating', class: 'text-right w-fit' }, + { key: 'won', label: 'Won', class: 'text-right w-5' }, + { key: 'lost', label: 'Lost', class: 'text-right w-5' } + ] as col} + + {/each} - - {#each sortedModels as model, modelIdx (model.id)} + + {#each sortedModels as model, idx (model.id)} openLeaderboardModelModal(model)} + class="bg-white dark:bg-gray-900 text-xs group cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-850/50 transition" + on:click={() => openModal(model)} > - - - - - - - {/each} @@ -562,15 +201,11 @@ {/if} -
-
+
+
- ⓘ {$i18n.t( - 'The evaluation leaderboard is based on the Elo rating system and is updated in real-time.' - )} + ⓘ {$i18n.t('The evaluation leaderboard is based on the Elo rating system and is updated in real-time.')}
- {$i18n.t( - 'The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.' - )} + {$i18n.t('The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.')}
diff --git a/src/lib/components/admin/Evaluations/LeaderboardModal.svelte b/src/lib/components/admin/Evaluations/LeaderboardModal.svelte index b3d7849797..0b82f9a6fc 100644 --- a/src/lib/components/admin/Evaluations/LeaderboardModal.svelte +++ b/src/lib/components/admin/Evaluations/LeaderboardModal.svelte @@ -3,7 +3,6 @@ import { getContext } from 'svelte'; export let show = false; export let model = null; - export let feedbacks = []; export let onClose: () => void = () => {}; const i18n = getContext('i18n'); import XMark from '$lib/components/icons/XMark.svelte'; @@ -13,22 +12,8 @@ onClose(); }; - $: topTags = model ? getTopTagsForModel(model.id, feedbacks) : []; - - const getTopTagsForModel = (modelId: string, feedbacks: any[], topN = 5) => { - const tagCounts = new Map(); - feedbacks - .filter((fb) => fb.data.model_id === modelId) - .forEach((fb) => { - (fb.data.tags || []).forEach((tag) => { - tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1); - }); - }); - return Array.from(tagCounts.entries()) - .sort((a, b) => b[1] - a[1]) - .slice(0, topN) - .map(([tag, count]) => ({ tag, count })); - }; + // Use top_tags from backend response (already computed) + $: topTags = model?.top_tags ?? []; From 401c1949a04dfd1bcc3c8b9a4f77b73beb78b818 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 18:51:38 +0400 Subject: [PATCH 200/254] refac --- backend/open_webui/routers/auths.py | 26 ++++++++++++++++++++++++++ src/lib/apis/auths/index.ts | 13 +++++++++++++ src/routes/auth/+page.svelte | 10 ++++++++-- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index 32e62526fc..30d4ebe4cc 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -189,6 +189,32 @@ async def update_profile( raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) +############################ +# Update Timezone +############################ + + +class UpdateTimezoneForm(BaseModel): + timezone: str + + +@router.post("/update/timezone") +async def update_timezone( + form_data: UpdateTimezoneForm, + session_user=Depends(get_current_user), + db: Session = Depends(get_session), +): + if session_user: + Users.update_user_by_id( + session_user.id, + {"timezone": form_data.timezone}, + db=db, + ) + return {"status": True} + else: + raise HTTPException(400, detail=ERROR_MESSAGES.INVALID_CRED) + + ############################ # Update Password ############################ diff --git a/src/lib/apis/auths/index.ts b/src/lib/apis/auths/index.ts index 5450479af5..1fd22494b5 100644 --- a/src/lib/apis/auths/index.ts +++ b/src/lib/apis/auths/index.ts @@ -423,6 +423,19 @@ export const updateUserProfile = async (token: string, profile: object) => { return res; }; +export const updateUserTimezone = async (token: string, timezone: string) => { + await fetch(`${WEBUI_API_BASE_URL}/auths/update/timezone`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + }, + body: JSON.stringify({ timezone }) + }).catch((err) => { + console.error('Failed to update timezone:', err); + }); +}; + export const updateUserPassword = async (token: string, password: string, newPassword: string) => { let error = null; diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte index 727c104100..660a7b3a72 100644 --- a/src/routes/auth/+page.svelte +++ b/src/routes/auth/+page.svelte @@ -9,12 +9,12 @@ import { page } from '$app/stores'; import { getBackendConfig } from '$lib/apis'; - import { ldapUserSignIn, getSessionUser, userSignIn, userSignUp } from '$lib/apis/auths'; + import { ldapUserSignIn, getSessionUser, userSignIn, userSignUp, updateUserTimezone } from '$lib/apis/auths'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; import { WEBUI_NAME, config, user, socket } from '$lib/stores'; - import { generateInitialsImage, canvasPixelTest } from '$lib/utils'; + import { generateInitialsImage, canvasPixelTest, getUserTimezone } from '$lib/utils'; import Spinner from '$lib/components/common/Spinner.svelte'; import OnBoarding from '$lib/components/OnBoarding.svelte'; @@ -47,6 +47,12 @@ await user.set(sessionUser); await config.set(await getBackendConfig()); + // Update user timezone + const timezone = getUserTimezone(); + if (sessionUser.token && timezone) { + updateUserTimezone(sessionUser.token, timezone); + } + if (!redirectPath) { redirectPath = $page.url.searchParams.get('redirect') || '/'; } From bb6188abf04302f79d80b0d6cc42c232624b5757 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 19:05:09 +0400 Subject: [PATCH 201/254] feat: per model tts voice --- .../chat/MessageInput/CallOverlay.svelte | 24 ++++++++++----- .../chat/Messages/ResponseMessage.svelte | 29 ++++++++++++++----- .../workspace/Models/ModelEditor.svelte | 28 ++++++++++++++++++ 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/lib/components/chat/MessageInput/CallOverlay.svelte b/src/lib/components/chat/MessageInput/CallOverlay.svelte index a7077941d9..da45336242 100644 --- a/src/lib/components/chat/MessageInput/CallOverlay.svelte +++ b/src/lib/components/chat/MessageInput/CallOverlay.svelte @@ -363,6 +363,19 @@ let currentMessageId = null; let currentUtterance = null; + // Get voice: model-specific > user settings > config default + const getVoiceId = () => { + // Check for model-specific TTS voice first + if (model?.info?.meta?.tts?.voice) { + return model.info.meta.tts.voice; + } + // Fall back to user settings or config default + if ($settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice) { + return $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice; + } + return $config?.audio?.tts?.voice; + }; + const speakSpeechSynthesisHandler = (content) => { if ($showCallOverlay) { return new Promise((resolve) => { @@ -372,11 +385,10 @@ if (voices.length > 0) { clearInterval(getVoicesLoop); + const voiceId = getVoiceId(); const voice = voices - ?.filter( - (v) => v.voiceURI === ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice) - ) + ?.filter((v) => v.voiceURI === voiceId) ?.at(0) ?? undefined; currentUtterance = new SpeechSynthesisUtterance(content); @@ -471,7 +483,7 @@ const url = await $TTSWorker .generate({ text: content, - voice: $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice + voice: getVoiceId() }) .catch((error) => { console.error(error); @@ -484,9 +496,7 @@ } else if ($config.audio.tts.engine !== '') { const res = await synthesizeOpenAISpeech( localStorage.token, - $settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice - ? ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice) - : $config?.audio?.tts?.voice, + getVoiceId(), content ).catch((error) => { console.error(error); diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index d2056554dc..bd085573f4 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -207,6 +207,19 @@ speaking = true; const content = removeAllDetails(message.content); + // Get voice: model-specific > user settings > config default + const getVoiceId = () => { + // Check for model-specific TTS voice first + if (model?.info?.meta?.tts?.voice) { + return model.info.meta.tts.voice; + } + // Fall back to user settings or config default + if ($settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice) { + return $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice; + } + return $config?.audio?.tts?.voice; + }; + if ($config.audio.tts.engine === '') { let voices = []; const getVoicesLoop = setInterval(() => { @@ -214,11 +227,10 @@ if (voices.length > 0) { clearInterval(getVoicesLoop); + const voiceId = getVoiceId(); const voice = voices - ?.filter( - (v) => v.voiceURI === ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice) - ) + ?.filter((v) => v.voiceURI === voiceId) ?.at(0) ?? undefined; console.log(voice); @@ -265,7 +277,9 @@ return; } - console.debug('Prepared message content for TTS', messageContentParts); + const voiceId = getVoiceId(); + console.debug('Prepared message content for TTS', messageContentParts, 'voice:', voiceId); + if ($settings.audio?.tts?.engine === 'browser-kokoro') { if (!$TTSWorker) { await TTSWorker.set( @@ -281,7 +295,7 @@ const url = await $TTSWorker .generate({ text: sentence, - voice: $settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice + voice: voiceId }) .catch((error) => { console.error(error); @@ -300,9 +314,7 @@ for (const [idx, sentence] of messageContentParts.entries()) { const res = await synthesizeOpenAISpeech( localStorage.token, - $settings?.audio?.tts?.defaultVoice === $config.audio.tts.voice - ? ($settings?.audio?.tts?.voice ?? $config?.audio?.tts?.voice) - : $config?.audio?.tts?.voice, + voiceId, sentence ).catch((error) => { console.error(error); @@ -324,6 +336,7 @@ } }; + let preprocessedDetailsCache = []; function preprocessForEditing(content: string): string { diff --git a/src/lib/components/workspace/Models/ModelEditor.svelte b/src/lib/components/workspace/Models/ModelEditor.svelte index 8d70667bd9..e26d3d02cc 100644 --- a/src/lib/components/workspace/Models/ModelEditor.svelte +++ b/src/lib/components/workspace/Models/ModelEditor.svelte @@ -107,6 +107,7 @@ let actionIds = []; let accessControl = {}; + let tts = { voice: '' }; const submitHandler = async () => { loading = true; @@ -194,6 +195,18 @@ } } + if (tts.voice !== '') { + if (!info.meta.tts) info.meta.tts = {}; + info.meta.tts.voice = tts.voice; + } else { + if (info.meta.tts?.voice) { + delete info.meta.tts.voice; + if (Object.keys(info.meta.tts).length === 0) { + delete info.meta.tts; + } + } + } + info.params.system = system.trim() === '' ? null : system; info.params.stop = params.stop ? params.stop.split(',').filter((s) => s.trim()) : null; Object.keys(info.params).forEach((key) => { @@ -275,6 +288,7 @@ capabilities = { ...capabilities, ...(model?.meta?.capabilities ?? {}) }; defaultFeatureIds = model?.meta?.defaultFeatureIds ?? []; + tts = { voice: model?.meta?.tts?.voice ?? '' }; if ('access_control' in model) { accessControl = model.access_control; @@ -766,6 +780,20 @@ {/if} {/if} +
+
+
+ {$i18n.t('TTS Voice')} +
+
+ +
+
From 869108a3e1ce2b8110084113c1b392072e98fd5f Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 19:08:35 +0400 Subject: [PATCH 202/254] refac: tts split --- src/lib/utils/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts index a7a0fca32e..265c47cec2 100644 --- a/src/lib/utils/index.ts +++ b/src/lib/utils/index.ts @@ -894,8 +894,8 @@ export const extractSentences = (text: string) => { return placeholder; }); - // Split the modified text into sentences based on common punctuation marks, avoiding these blocks - let sentences = text.split(/(?<=[.!?])\s+/); + // Split the modified text into sentences based on common punctuation marks or newlines, avoiding these blocks + let sentences = text.split(/(?<=[.!?])\s+|\n+/); // Restore code blocks and process sentences sentences = sentences.map((sentence) => { From 83dce80e308328a14bbccf78aedb5d2863dab87f Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 9 Jan 2026 16:26:48 +0100 Subject: [PATCH 203/254] Update translation.json (#20513) --- src/lib/i18n/locales/de-DE/translation.json | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index c2dcc68486..5f0d709d5a 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -220,7 +220,7 @@ "Button ID": "Schaltflächen-ID", "Button Label": "Schaltflächenbeschriftung", "Button Prompt": "Schaltflächen-Prompt", - "by {{name}}": "", + "by {{name}}": "von {{name}}", "By {{name}}": "Von {{name}}", "Bypass Embedding and Retrieval": "Embedding und Retrieval umgehen", "Bypass Web Loader": "Web-Loader umgehen", @@ -365,7 +365,7 @@ "Copy link": "Link kopieren", "Copy Link": "Link kopieren", "Copy to clipboard": "In Zwischenablage kopieren", - "Copy URL": "", + "Copy URL": "URL kopieren", "Copying to clipboard was successful!": "Erfolgreich in die Zwischenablage kopiert!", "CORS must be properly configured by the provider to allow requests from Open WebUI.": "CORS muss vom Anbieter korrekt konfiguriert sein, um Anfragen von Open WebUI zuzulassen.", "Create": "Erstellen", @@ -389,7 +389,7 @@ "Created At": "Erstellt am", "Created by": "Erstellt von", "Created by you": "Von Ihnen erstellt", - "Created on {{date}}": "", + "Created on {{date}}": "Erstellt am {{date}}", "CSV Import": "CSV-Import", "Ctrl+Enter to Send": "Strg+Enter zum Senden", "Current Model": "Aktuelles Modell", @@ -445,7 +445,7 @@ "delete this link": "diesen Link löschen", "Delete tool?": "Werkzeug löschen?", "Delete User": "Benutzer löschen", - "Deleted": "", + "Deleted": "Gelöscht", "Deleted {{deleteModelTag}}": "{{deleteModelTag}} gelöscht", "Deleted {{name}}": "{{name}} gelöscht", "Deleted User": "Gelöschter Benutzer", @@ -989,7 +989,7 @@ "Knowledge created successfully.": "Wissen erfolgreich erstellt.", "Knowledge deleted successfully.": "Wissen erfolgreich gelöscht.", "Knowledge Description": "Wissensbeschreibung", - "Knowledge exported successfully": "", + "Knowledge exported successfully": "Wissensspeicher erfolgreich exportiert", "Knowledge Name": "Wissensname", "Knowledge Public Sharing": "Öffentliche Freigabe von Wissen", "Knowledge reset successfully.": "Wissen erfolgreich zurückgesetzt.", @@ -1151,7 +1151,7 @@ "New Prompt": "Neuer Prompt", "New Temporary Chat": "Neuer temporärer Chat", "New Tool": "Neues Werkzeug", - "New Webhook": "", + "New Webhook": "Neuer Webhook", "new-channel": "neuer-kanal", "Next message": "Nächste Nachricht", "No authentication": "Keine Authentifizierung", @@ -1192,7 +1192,7 @@ "No users were found.": "Keine Benutzer gefunden.", "No valves": "Keine Valves", "No valves to update": "Keine Valves zum Aktualisieren", - "No webhooks yet": "", + "No webhooks yet": "Noch keine Webhooks", "Node Ids": "Knoten-IDs", "None": "Keine", "Not factually correct": "Inhaltlich nicht korrekt", @@ -1800,7 +1800,7 @@ "User location successfully retrieved.": "Benutzerstandort erfolgreich abgerufen.", "User menu": "Benutzermenü", "User ratings (thumbs up/down)": "Benutzerbewertungen (Daumen hoch/runter)", - "User Status": "", + "User Status": "Nutzerstatus", "User Webhooks": "Benutzer-Webhooks", "Username": "Benutzername", "users": "Benutzer", @@ -1841,9 +1841,9 @@ "Web Search Engine": "Web-Suchmaschine", "Web Search in Chat": "Websuche im Chat", "Web Search Query Generation": "Suchanfragen-Generierung", - "Webhook Name": "", + "Webhook Name": "Webhook-Name", "Webhook URL": "Webhook-URL", - "Webhooks": "", + "Webhooks": "Webhooks", "Webpage URLs": "Webseiten URLs", "WebUI Settings": "WebUI-Einstellungen", "WebUI URL": "WebUI-URL", From a7b4b6e51a0933ce4ffbd487b1279a51c1e78cf4 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 19:42:13 +0400 Subject: [PATCH 204/254] enh: WHISPER_MULTILINGUAL --- backend/open_webui/config.py | 8 +++----- backend/open_webui/main.py | 1 - backend/open_webui/routers/audio.py | 5 ++++- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 6a00c21c02..dab5b6cfe8 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -3744,11 +3744,9 @@ WHISPER_MODEL_AUTO_UPDATE = ( and os.environ.get("WHISPER_MODEL_AUTO_UPDATE", "").lower() == "true" ) -WHISPER_VAD_FILTER = PersistentConfig( - "WHISPER_VAD_FILTER", - "audio.stt.whisper_vad_filter", - os.getenv("WHISPER_VAD_FILTER", "False").lower() == "true", -) +WHISPER_VAD_FILTER = os.getenv("WHISPER_VAD_FILTER", "False").lower() == "true" + +WHISPER_MULTILINGUAL = os.getenv("WHISPER_MULTILINGUAL", "False").lower() == "true" WHISPER_LANGUAGE = os.getenv("WHISPER_LANGUAGE", "").lower() or None diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index 9b1ae53bed..82a87e3fd9 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1174,7 +1174,6 @@ app.state.config.STT_OPENAI_API_BASE_URL = AUDIO_STT_OPENAI_API_BASE_URL app.state.config.STT_OPENAI_API_KEY = AUDIO_STT_OPENAI_API_KEY app.state.config.WHISPER_MODEL = WHISPER_MODEL -app.state.config.WHISPER_VAD_FILTER = WHISPER_VAD_FILTER app.state.config.DEEPGRAM_API_KEY = DEEPGRAM_API_KEY app.state.config.AUDIO_STT_AZURE_API_KEY = AUDIO_STT_AZURE_API_KEY diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py index c999c132f7..2a64a3598d 100644 --- a/backend/open_webui/routers/audio.py +++ b/backend/open_webui/routers/audio.py @@ -41,8 +41,10 @@ from open_webui.config import ( WHISPER_MODEL_AUTO_UPDATE, WHISPER_COMPUTE_TYPE, WHISPER_MODEL_DIR, + WHISPER_VAD_FILTER, CACHE_DIR, WHISPER_LANGUAGE, + WHISPER_MULTILINGUAL, ELEVENLABS_API_BASE_URL, ) @@ -601,8 +603,9 @@ def transcription_handler(request, file_path, metadata, user=None): segments, info = model.transcribe( file_path, beam_size=5, - vad_filter=request.app.state.config.WHISPER_VAD_FILTER, + vad_filter=WHISPER_VAD_FILTER, language=languages[0], + multilingual=WHISPER_MULTILINGUAL, ) log.info( "Detected language '%s' with probability %f" From f4d99135e401915a411e7e31685039768a94bd21 Mon Sep 17 00:00:00 2001 From: Classic298 <27028174+Classic298@users.noreply.github.com> Date: Fri, 9 Jan 2026 16:44:32 +0100 Subject: [PATCH 205/254] chore: CHANGELOG (#20261) * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md --- CHANGELOG.md | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4915f28376..fd9cec0d14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,125 @@ 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.7] - 2026-01-09 + +### Added + +- 🤖 **Revolutionary Agentic AI: Models can now think and act autonomously** — When configured for agentic mode, AI models independently research topics by searching the web multiple times, fetching and analyzing web pages, managing their own memory, and generating images without waiting for user prompts, transforming conversations from simple Q&A into dynamic research sessions where the AI proactively investigates and synthesizes information across multiple sources. [#19397](https://github.com/open-webui/open-webui/issues/19397), [Commit](https://github.com/open-webui/open-webui/commit/5c1d52231a3997a17381c48639bd7e339262cf7c) +- 🧠 **Agentic AI unlocks your entire knowledge ecosystem** — Models in agentic mode autonomously search through your notes, past conversations, channels, and messages to find relevant context, calculate timestamps for temporal queries, and access your complete communication history without explicit commands, turning AI into a self-sufficient research assistant that knows when and where to look for information. [Commit](https://github.com/open-webui/open-webui/commit/646835d76744ad9b2e67ede0407a61d62e969aab) +- 📚 **Agentic AI independently explores knowledge bases** — Models in agentic mode proactively list accessible knowledge bases, search files by name, retrieve full document contents, and perform semantic vector searches across your entire knowledge repository to find relevant information autonomously, eliminating the need to manually specify which documents to reference. [Commit](https://github.com/open-webui/open-webui/commit/c8622adcb01f3091b17ca50f8c8e2f20c7b9cd2a) +- 💭 **AI thinks between actions for smarter research** — Models with interleaved thinking support can now reason and reflect between tool calls, analyzing search results before deciding what to search for next, leading to dramatically more focused and effective multi-step research as the AI refines its strategy based on what it learns. +- 🔍 **Transparent agentic research with automatic source citations** — When AI models autonomously search the web in agentic mode, users see every search result as clickable citations in real-time, making the AI's research process completely transparent and allowing full verification of sources even when the model initiates searches independently. [Commit](https://github.com/open-webui/open-webui/commit/2789f6a24d8405c30cd48ae460071f6a4f2c35f9) +- 📖 **Knowledge base queries surface as verifiable citations** — When AI models autonomously query knowledge bases in agentic mode, every retrieved file and content chunk appears as grouped, clickable citations showing exactly which documents informed the response, with sources automatically organized by origin for easy verification. [#20380](https://github.com/open-webui/open-webui/pull/20380), [Commit](https://github.com/open-webui/open-webui/commit/ab400e3eae569a5e09fe391d4b4bab104423bb0b) +- 🎚️ **Fine-grained control over agentic capabilities per model** — Users can now selectively disable built-in agentic tools for individual models through the model editor's capabilities settings, allowing precise control over which models can autonomously access timestamps, memory, chat history, notes, web search, and knowledge bases. [Commit](https://github.com/open-webui/open-webui/commit/60e916d6c0c5f7db9e6d670e12be2d1d4abc2dd6) +- 👁️ **Watch AI think in real-time with live tool call visualization** — Users now see exactly which agentic tools are being invoked as AI models work, with pending tool calls displayed during response generation so it's always clear the system is actively researching rather than frozen or stuck. [Commit](https://github.com/open-webui/open-webui/commit/1d08376860e775049abd1dd5f568ac0c6466c944) +- ⚡ **Massive database performance overhaul delivers dramatically faster operations** — Users experience transformative speed improvements across the entire application through completely reengineered database connection handling, delivering noticeably faster page loads, butter-smooth interactions, and rock-solid stability during intensive operations like user management and bulk data processing. [Commit](https://github.com/open-webui/open-webui/commit/2041ab483e21b3a757baa25c47dc2fa29018674f), [Commit](https://github.com/open-webui/open-webui/commit/145c7516f227ce56fd52373cee86217fadf16181), [Commit](https://github.com/open-webui/open-webui/commit/475dd91ed798f2efcdf27799d5c5cae3f0e6e847), [Commit](https://github.com/open-webui/open-webui/commit/5d1459df166cce8445eb1556cc26abbd65a3f9f4), [Commit](https://github.com/open-webui/open-webui/commit/2453b75ff0fb2dc75b929d96f417d84e332922d9), [Commit](https://github.com/open-webui/open-webui/commit/5649a668fad15393a52c27a2f188841af8b66989) +- 🚀 Users experience significantly faster initial page load times through dynamic loading of document processing libraries, reducing the initial bundle size. [#20200](https://github.com/open-webui/open-webui/pull/20200), [#20202](https://github.com/open-webui/open-webui/pull/20202), [#20203](https://github.com/open-webui/open-webui/pull/20203), [#20204](https://github.com/open-webui/open-webui/pull/20204) +- 💨 Administrators experience dramatically faster user list loading through optimized database queries that eliminate N+1 query patterns, reducing query count from 1+N to just 2 total queries regardless of user count. [#20427](https://github.com/open-webui/open-webui/pull/20427) +- 📋 Notes now load faster through optimized database queries that batch user lookups instead of fetching each note's author individually. [Commit](https://github.com/open-webui/open-webui/commit/084f0ef6a5491e186bf6b71c6386973ba18ef2fa) +- 💬 Channel messages, pinned messages, and thread replies now load faster through batched user lookups instead of individual queries per message. [#20458](https://github.com/open-webui/open-webui/pull/20458), [#20459](https://github.com/open-webui/open-webui/pull/20459), [#20460](https://github.com/open-webui/open-webui/pull/20460) +- 📊 Users can now sync their chat statistics to create public profile pages on the Open WebUI Community website or download them as JSON files, with incremental synchronization by default and an administrator option to disable the feature. [Commit](https://github.com/open-webui/open-webui/commit/4be99174be505b187812e0b48b9f9f7bf6897c52), [Commit](https://github.com/open-webui/open-webui/commit/df106099a159f8cf7910a89c50338ec045a78e61), [Commit](https://github.com/open-webui/open-webui/commit/9c61e95ecba071f5a99d93d1b1c5d17b80159329), [Commit](https://github.com/open-webui/open-webui/commit/85bbed3ec539dc958d306117f97d6be977b7253b), [Commit](https://github.com/open-webui/open-webui/commit/459cfde1f80e76618fb7fb75318d8daf2ccf1590), [Commit](https://github.com/open-webui/open-webui/commit/37b15604de0eaa5bfde378f12ac2d94c7aab60b9), [Commit](https://github.com/open-webui/open-webui/commit/71ca25c8ac4ad97b5a52016a5b2f385b333bd480) +- 🔗 Users can now click citation content links to jump directly to the relevant portion of source documents with automatic text highlighting, making it easier to verify AI responses against their original sources. [#20116](https://github.com/open-webui/open-webui/pull/20116), [Commit](https://github.com/open-webui/open-webui/commit/40c45ffe1f9b45538d32c8ecba8cac62c6eca503) +- 📌 Users can now pin or hide models directly from the Workspace Models page and Admin Settings Models page, making it easier to manage which models appear in the sidebar without switching to the chat interface. [#20176](https://github.com/open-webui/open-webui/pull/20176) +- 🔎 Administrators can now quickly find settings using the new search bar in the Admin Settings sidebar, which supports fuzzy filtering by category names and related keywords like "whisper" for Audio or "rag" for Documents. [#20434](https://github.com/open-webui/open-webui/pull/20434) +- 🎛️ Users can now view read-only models in the workspace models list, with clear "Read Only" badges indicating when editing is restricted. [#20243](https://github.com/open-webui/open-webui/issues/20243), [#20369](https://github.com/open-webui/open-webui/pull/20369) +- 📝 Users can now view read-only prompts in the workspace prompts list, with clear "Read Only" badges indicating when editing is restricted. [#20368](https://github.com/open-webui/open-webui/pull/20368) +- 🔧 Users can now view read-only tools in the workspace tools list, with clear "Read Only" badges indicating when editing is restricted. [#20243](https://github.com/open-webui/open-webui/issues/20243), [#20370](https://github.com/open-webui/open-webui/pull/20370) +- 📂 Searching for files is now significantly faster, especially for users with large file collections. [Commit](https://github.com/open-webui/open-webui/commit/a9a979fb3db1743553ca0705f571c0b9c252841f) +- 🏆 The Evaluations leaderboard now calculates Elo ratings on the backend instead of in the browser, improving performance and enabling topic-based model ranking through semantic search. [#15392](https://github.com/open-webui/open-webui/pull/15392), [#20476](https://github.com/open-webui/open-webui/issues/20476), [Commit](https://github.com/open-webui/open-webui/commit/10838b3654bf6fdef02d57311f7f1c01df4cd033) +- 🎞️ Users can now upload animated GIF and WebP formats as model profile images, with animation preserved by skipping resize processing for these file types. [Commit](https://github.com/open-webui/open-webui/commit/00af37bb4ed1ea0957c7c84a6a8def3a7998b8ca) +- 📸 Users uploading profile images for users, models, and arena models now benefit from WebP compression at 80% quality instead of JPEG, resulting in significantly smaller file sizes and faster uploads while maintaining visual quality. [Commit](https://github.com/open-webui/open-webui/commit/b1d30673b69571e081abb881d34944cf33cdc67e) +- ⭐ Action Function developers can now update message favorite status using the new "chat:message:favorite" event, enabling the development of pin/unpin message actions without race conditions from frontend auto-save. [#20375](https://github.com/open-webui/open-webui/pull/20375) +- 🌐 Users with OpenAI-compatible models that have web search capabilities now see URL citations displayed as sources in the interface. [#20172](https://github.com/open-webui/open-webui/pull/20172), [Commit](https://github.com/open-webui/open-webui/commit/fe84afd09a2bc8a89311f30186ec2608a4edda3a) +- 📰 Users can now dismiss the "What's New" changelog modal permanently using the X button, matching the behavior of the "Okay, Let's Go!" button. [#20258](https://github.com/open-webui/open-webui/pull/20258) +- 📧 Administrators can now configure the admin contact email displayed in the Account Pending overlay directly from the Admin Panel instead of only through environment variables. [#12500](https://github.com/open-webui/open-webui/issues/12500), [#20260](https://github.com/open-webui/open-webui/pull/20260) +- 📄 Administrators can now enable markdown header text splitting as a preprocessing step that works with either character or token splitting, through the new "ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER" setting. [Commit](https://github.com/open-webui/open-webui/commit/d3a682759f375c6cb0bc8c170f62863a070f712e), [Commit](https://github.com/open-webui/open-webui/commit/18a33a079bf07487edffc421a721c86194cc90c9), [Commit](https://github.com/open-webui/open-webui/commit/08bf4670ec862018f9dc57296cb19fd5eab14ef6) +- 🧩 Administrators can now set a minimum chunk size target using the "CHUNK_MIN_SIZE_TARGET" setting to merge small markdown header chunks with neighbors, which improves retrieval quality by eliminating tiny meaningless fragments, significantly speeds up document processing and embedding, reduces storage costs, and lowers embedding API costs or local compute requirements. [#19595](https://github.com/open-webui/open-webui/issues/19595), [#20314](https://github.com/open-webui/open-webui/pull/20314), [Commit](https://github.com/open-webui/open-webui/commit/c32435958073cf002d87e78544baa88bc4e15d7f) +- 💨 Administrators can now enable KV prefix caching optimization by setting "RAG_SYSTEM_CONTEXT" to true, which injects RAG context into the system message instead of user messages, enabling models to reuse cached tokens for follow-up questions instead of reprocessing the entire context on each turn, significantly improving response times and reducing costs for cloud-based models. [#20301](https://github.com/open-webui/open-webui/discussions/20301), [#20317](https://github.com/open-webui/open-webui/pull/20317) +- 🖼️ Administrators and Action developers can now control image generation denoising steps per-request using a steps parameter, allowing Actions and API calls to override the global IMAGE_STEPS configuration for both ComfyUI and Automatic1111 engines. [#20337](https://github.com/open-webui/open-webui/pull/20337) +- 📁 Administrators can now limit the number of files that can be uploaded to folders using the "FOLDER_MAX_FILE_COUNT" setting, preventing resource exhaustion from bulk uploads. [#19810](https://github.com/open-webui/open-webui/issues/19810), [Commit](https://github.com/open-webui/open-webui/commit/a1036e544d573e3d35e05c1c2472ba762c32431b), [Commit](https://github.com/open-webui/open-webui/commit/d3ee3fd23e762c9d83fe1da5636d03259e186e57) +- 🗄️ Administrators running multi-pod deployments can now designate a master pod to handle database migrations using the "ENABLE_DB_MIGRATIONS" environment variable. [Commit](https://github.com/open-webui/open-webui/commit/9824f0e33359a917ac07b60bf1f972074d5c8203) +- 🎙️ Administrators can now configure Whisper's compute type using the "WHISPER_COMPUTE_TYPE" environment variable to fix compatibility issues with CUDA/GPU deployments. [Commit](https://github.com/open-webui/open-webui/commit/26af1f92e21ddfd08348570bf54a6f345ac69648) +- 🔍 Administrators can now control sigmoid normalization for CrossEncoder reranking models using the "SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION" environment variable, enabled by default for proper relevance threshold behavior with MS MARCO models. [#20228](https://github.com/open-webui/open-webui/pull/20228) +- 🔒 Administrators can now disable SSL certificate verification for external tools using the "REQUESTS_VERIFY" environment variable, enabling integration with self-signed certificates for Tika, Ollama embeddings, and external rerankers. [#19968](https://github.com/open-webui/open-webui/issues/19968), [Commit](https://github.com/open-webui/open-webui/commit/dfc5dad63167eabb7fb027e63c324675b23f2e9d) +- 📈 Administrators can now control audit log output destinations using "ENABLE_AUDIT_STDOUT" and "ENABLE_AUDIT_LOGS_FILE" environment variables, allowing audit logs to be sent to container logs for centralized logging systems. [#20114](https://github.com/open-webui/open-webui/pull/20114), [Commit](https://github.com/open-webui/open-webui/commit/fdae5644e36972384b3e2513e3074f95f9f7381f) +- 🛡️ Administrators can now restrict non-admin user access to Interface Settings through per-user or per-group permissions. [#20424](https://github.com/open-webui/open-webui/pull/20424) +- 🧠 Administrators can now globally enable or disable the Memories feature and control access through per-user or per-group permissions, with the Personalization tab automatically hidden when the feature is disabled. [#20462](https://github.com/open-webui/open-webui/pull/20462) +- 🟢 Administrators can now globally enable or disable user status visibility through the "ENABLE_USER_STATUS" setting in Admin Settings. [#20488](https://github.com/open-webui/open-webui/pull/20488) +- 🪝 Channel managers can now create webhooks to allow external services to post messages to channels without authentication. [Commit](https://github.com/open-webui/open-webui/commit/cd296fcf0d79cecd1a6a3ee4e492c6b5246ca7ae) +- 📄 In the model editor users can now disable the "File Context" capability to skip automatic file content extraction and injection, forwarding raw messages with file attachment metadata instead for use with custom tools or future built-in file access tools. [Commit](https://github.com/open-webui/open-webui/commit/daccf0713e3ecd6d24f003a87b5f8b3c61852958), [Docs:Commit](https://github.com/open-webui/docs/commit/18ec6eaefc071a278ec57d4d1b8d66d686af0870) +- 🔊 In the model editor users can now configure a specific TTS voice for each model, overriding user preferences and global defaults to give different AI personas distinct voices. [#3097](https://github.com/open-webui/open-webui/issues/3097), [Commit](https://github.com/open-webui/open-webui/commit/bb6188abf04302f79d80b0d6cc42c232624b5757) +- 🕐 User timezones are now automatically detected and stored on login, enabling accurate timestamp handling for time-sensitive features. [Commit](https://github.com/open-webui/open-webui/commit/401c1949a04dfd1bcc3c8b9a4f77b73beb78b818) +- 👥 Administrators now have three granular group sharing permission options instead of a simple on/off toggle, allowing them to choose between "No one", "Members", or "Anyone" for who can share content to each group. [Commit](https://github.com/open-webui/open-webui/commit/ca514cd3eda2524b8da472ef17c0ccb216bac2e8) +- 📦 Administrators can now export knowledge bases as zip files containing text files for backup and archival purposes. [#20120](https://github.com/open-webui/open-webui/issues/20120), [Commit](https://github.com/open-webui/open-webui/commit/c1147578c073a8c7fa7e7f836149e1cdfec8f18d) +- 🚀 Administrators can now create an admin account automatically at startup via "WEBUI_ADMIN_EMAIL", "WEBUI_ADMIN_PASSWORD", and "WEBUI_ADMIN_NAME" environment variables, enabling headless and automated deployments without exposing the signup page. [#17654](https://github.com/open-webui/open-webui/issues/17654), [Commit](https://github.com/open-webui/open-webui/commit/1138929f4d083931305f1f925899971b190562ae) +- 🦆 Administrators can now select a specific search backend for DDGS instead of random selection, with options including Bing, Brave, DuckDuckGo, Google, Wikipedia, Yahoo, and others. [#20330](https://github.com/open-webui/open-webui/issues/20330), [#20366](https://github.com/open-webui/open-webui/pull/20366) +- 🧭 Administrators can now configure custom Jina Search API endpoints using the "JINA_API_BASE_URL" environment variable, enabling region-specific deployments such as EU data processing. [#19718](https://github.com/open-webui/open-webui/pull/19718), [Commit](https://github.com/open-webui/open-webui/commit/f7f8a263b92289df8d4f8dbc3bae09bd009a5699) +- 🔥 Administrators can now configure Firecrawl timeout values using the "FIRECRAWL_TIMEOUT" environment variable to control web scraping wait times. [#19973](https://github.com/open-webui/open-webui/pull/19973), [Commit](https://github.com/open-webui/open-webui/commit/89ad1c68d1aadf849960b5e202aa4651096b05f5) +- 💾 Administrators can now use openGauss as the vector database backend for knowledge base document storage and retrieval. [#20179](https://github.com/open-webui/open-webui/pull/20179) +- 🔄 Various improvements were implemented across the application to enhance performance, stability, and security. +- 🌐 Translations for German, Portuguese (Brazil), Spanish, Simplified Chinese, Traditional Chinese, and Polish were enhanced and expanded. + +### Fixed + +- 🔊 Text-to-speech now correctly splits on newlines in addition to punctuation, so markdown bullet points and lists are spoken as separate sentences instead of being merged together. [#5924](https://github.com/open-webui/open-webui/issues/5924), [Commit](https://github.com/open-webui/open-webui/commit/869108a3e1ce2b8110084113c1b392072e98fd5f) +- 🔒 Users are now protected from stored XSS vulnerabilities in iFrame embeds for citations and response messages through configurable same-origin sandbox settings instead of hardcoded values. [#20209](https://github.com/open-webui/open-webui/pull/20209), [#20210](https://github.com/open-webui/open-webui/pull/20210) +- 🔑 Image Generation, Web Search, and Audio (TTS/STT) API endpoints now enforce permission checks on the backend, closing a security gap where disabled features could previously be accessed via direct API calls. [#20471](https://github.com/open-webui/open-webui/pull/20471) +- 🛠️ Tools and Tool Servers (MCP and OpenAPI) now enforce access control checks on the backend, ensuring users can only access tools they have permission to use even via direct API calls. [#20443](https://github.com/open-webui/open-webui/issues/20443), [Commit](https://github.com/open-webui/open-webui/commit/9b06fdc8fe1c933071610336be05f11e77e6c8eb) +- 🔁 System prompts are no longer duplicated when using native function calling, fixing an issue where the prompt would be applied twice during tool-calling workflows. [Commit](https://github.com/open-webui/open-webui/commit/9223efaff0db6e56bfa157ef214d9590005156d2) +- 🗂️ Knowledge base uploads to folders no longer fail when "FOLDER_MAX_FILE_COUNT" is unset, fixing an issue where the default null value caused all uploads to error. [Commit](https://github.com/open-webui/open-webui/commit/ef9cd0e0ad6e45b8a3efec6f3858b3d69d42f619) +- 📝 The "Create Note" button in the chat input now correctly hides for users without Notes permissions instead of showing and returning a 401 error when clicked. [#20486](https://github.com/open-webui/open-webui/issues/20486), [Commit](https://github.com/open-webui/open-webui/commit/9e9616b670c1c4389193b18500a7d80d86d7e280) +- 📊 The Evaluations page no longer crashes when administrators have large amounts of feedback data, as the leaderboard now fetches only the minimal required fields instead of loading entire conversation snapshots. [#20476](https://github.com/open-webui/open-webui/issues/20476), [#20489](https://github.com/open-webui/open-webui/pull/20489), [Commit](https://github.com/open-webui/open-webui/commit/b2a1f71d920e55b143f1c02e61104938d2588762) +- 💬 Users can now export chats, use the Ask/Explain popup, and view chat lists correctly again after these features were broken by recent refactoring changes that caused 500 and 400 server errors. [#20146](https://github.com/open-webui/open-webui/issues/20146), [#20205](https://github.com/open-webui/open-webui/issues/20205), [#20206](https://github.com/open-webui/open-webui/issues/20206), [#20212](https://github.com/open-webui/open-webui/pull/20212) +- 💭 Users no longer experience data corruption when switching between chats during background operations like image generation, where messages from one chat would appear in another chat's history. [#20266](https://github.com/open-webui/open-webui/pull/20266) +- 🛡️ Users no longer encounter critical chat stability errors, including duplicate key errors from circular message dependencies, null message access during chat loading, and errors in the chat overview visualization. [#20268](https://github.com/open-webui/open-webui/pull/20268) +- 📡 Users with Channels no longer experience infinite recursion and connection pool exhaustion when fetching threaded replies, preventing RecursionError crashes during chat history loading. [#20299](https://github.com/open-webui/open-webui/pull/20299), [Commit](https://github.com/open-webui/open-webui/commit/c144122f608759c2b79472e1f6948a7c1600a3d1) +- 📎 Users no longer encounter TypeError crashes when viewing messages with file attachments that have undefined URL properties. [#20343](https://github.com/open-webui/open-webui/pull/20343) +- 🔐 Users with MCP integrations now experience reliable OAuth 2.1 token refresh after access token expiration through proper Protected Resource discovery, preventing integration failures that caused sessions to be deleted. [#19794](https://github.com/open-webui/open-webui/issues/19794), [#20138](https://github.com/open-webui/open-webui/pull/20138), [#20291](https://github.com/open-webui/open-webui/issues/20291), [Commit](https://github.com/open-webui/open-webui/commit/bf2b2962399e341926bdbf9e0a82101f31a90b23), [Commit](https://github.com/open-webui/open-webui/commit/89565c58c6ae6b5b129559ef68b5a0c18c110765) +- 📚 Users who belong to multiple groups can now see Knowledge Bases shared with those groups, fixing an issue where they would disappear when shared with more than one group. [#20124](https://github.com/open-webui/open-webui/issues/20124), [#20229](https://github.com/open-webui/open-webui/issues/20229), [Commit](https://github.com/open-webui/open-webui/commit/61e25dc2dce9c12dcb5b88a6b814060c4338e67b) +- 📂 Users now see the correct Knowledge Base name when hovering over # file references in chat input instead of "undefined". [#20329](https://github.com/open-webui/open-webui/issues/20329), [#20333](https://github.com/open-webui/open-webui/pull/20333) +- 📋 Users now see notes displayed in correct chronological order within their time range groupings, fixing an issue where insertion order was not preserved. [Commit](https://github.com/open-webui/open-webui/commit/3f577c0c3fbfd9f09c02940e4ae474f987149277) +- 📑 Users collaborating on notes now experience proper content sync when initializing from both HTML and JSON formats, fixing sync failures in collaborative editing sessions. [Commit](https://github.com/open-webui/open-webui/commit/e27fb3e291a735c715a089a80e7a49d2c2209096) +- 🔎 Users searching notes can now find hyphenated words and variations with spaces, so searching "todo" now finds "to-do" and "to do". [Commit](https://github.com/open-webui/open-webui/commit/a3270648d8b8535443d8ce2ea719f8e678e4e358) +- 📥 Users no longer experience false duplicate file warnings when reuploading files after initial processing failed, as the file hash is now only stored after successful processing completion. [#19264](https://github.com/open-webui/open-webui/issues/19264), [#20282](https://github.com/open-webui/open-webui/pull/20282), [Commit](https://github.com/open-webui/open-webui/commit/d3ab9f4b96eee7f91c9b1355cee055fdabca9730) +- 💾 Users experience significantly improved page load performance as model profile images now cache properly in browsers, avoiding unnecessary image refetches. [Commit](https://github.com/open-webui/open-webui/commit/bb821ab654e93908a3b4632c359753eeff053264) +- 🎨 Users can now successfully edit uploaded images instead of having new images generated, fixing an issue introduced by the file storage refactor where images with type "file" and content_type starting with "image/" weren't being recognized as editable images. [#20237](https://github.com/open-webui/open-webui/issues/20237), [#20169](https://github.com/open-webui/open-webui/pull/20169), [#20239](https://github.com/open-webui/open-webui/pull/20239), [Commit](https://github.com/open-webui/open-webui/commit/1148d1c927d096e14917b6d762789fca3188f281) +- 🌐 Users writing in Persian and Arabic now see properly displayed right-to-left text in the notes section through automatic text direction detection. [#19743](https://github.com/open-webui/open-webui/issues/19743), [#20102](https://github.com/open-webui/open-webui/pull/20102), [Commit](https://github.com/open-webui/open-webui/commit/b619a157bc54c5bc44d223d2ae3acb9ce4ac6a6c) +- 🤖 Users can now successfully @ mention models in Channels instead of experiencing silent failures. [Commit](https://github.com/open-webui/open-webui/commit/59957715836acb635f4b1c4ddbfb4ba7b82b3281) +- 📋 Users on Windows now see correctly preserved line breaks when using the {{CLIPBOARD}} variable through CRLF to LF normalization. [#19370](https://github.com/open-webui/open-webui/issues/19370), [#20283](https://github.com/open-webui/open-webui/pull/20283) +- 📁 Users now see the Knowledge Selector dropdown correctly displayed above the Create Folder modal instead of being hidden behind it. [#20219](https://github.com/open-webui/open-webui/issues/20219), [#20213](https://github.com/open-webui/open-webui/pull/20213) +- 🌅 Users now see profile images in non-PNG formats like SVG, JPEG, and GIF displayed correctly instead of appearing broken. [#20171](https://github.com/open-webui/open-webui/pull/20171) +- 🆕 Non-admin users with disabled temporary chat permissions can now successfully create new chats and use pinned models from the sidebar. [#20336](https://github.com/open-webui/open-webui/issues/20336), [#20367](https://github.com/open-webui/open-webui/pull/20367), [Commit](https://github.com/open-webui/open-webui/commit/e754940c031f9689fb4f6edb3625aa06aeb53377) +- 🎛️ Users can now successfully use workspace models in chat, fixing "Model not found" errors that occurred when using custom model presets. [#20340](https://github.com/open-webui/open-webui/issues/20340), [#20344](https://github.com/open-webui/open-webui/pull/20344), [Commit](https://github.com/open-webui/open-webui/commit/b55a46ae99c32068ed306a5ecdaafa9f75504cd7), [Commit](https://github.com/open-webui/open-webui/commit/2bb13d5dbc6e233856e8aa26143222ceda8f6c11) +- 🔁 Users can now regenerate messages without crashes when the parent message is missing or corrupted in the chat history. [#20264](https://github.com/open-webui/open-webui/pull/20264) +- ✏️ Users no longer experience TipTap rich text editor crashes with "editor view is not available" errors when plugins or async methods try to access the editor after it has been destroyed. [#20266](https://github.com/open-webui/open-webui/pull/20266) +- 📗 Administrators with bypass access control enabled now correctly have write access to all knowledge bases. [#20371](https://github.com/open-webui/open-webui/pull/20371) +- 🔍 Administrators using local CrossEncoder reranking models now see proper relevance threshold behavior through MS MARCO model score normalization to the 0-1 range via sigmoid activation. [#19999](https://github.com/open-webui/open-webui/issues/19999), [#20228](https://github.com/open-webui/open-webui/pull/20228) +- 🎯 Administrators using local SentenceTransformers embedding engine now benefit from proper batch size settings, preventing excessive memory usage from the default batch size of 32. [#20053](https://github.com/open-webui/open-webui/issues/20053), [#20054](https://github.com/open-webui/open-webui/pull/20054), [Commit](https://github.com/open-webui/open-webui/commit/e4a5b06ca68303512678b4d2dc296bc78b9f983f) +- 🔧 Administrators and users in offline mode or restricted environments like uv, poetry, and NixOS no longer experience crashes when Tools and Functions have frontmatter requirements, as pip installation is now skipped when offline mode is enabled. [#20320](https://github.com/open-webui/open-webui/issues/20320), [#20321](https://github.com/open-webui/open-webui/pull/20321), [Commit](https://github.com/open-webui/open-webui/commit/bd07ef8) +- 📄 Administrators can now properly configure the MinerU document parsing service as the MinerU Cloud API key field is now available in the Admin Panel Documents settings. [#20319](https://github.com/open-webui/open-webui/issues/20319), [#20328](https://github.com/open-webui/open-webui/pull/20328) +- ⚠️ Administrators no longer see SyntaxWarnings for invalid escape sequences in password validation regex patterns. [#20298](https://github.com/open-webui/open-webui/pull/20298), [Commit](https://github.com/open-webui/open-webui/commit/e55bf2c2ac391caed871d41f0484820091081908) +- 🎨 Users with ComfyUI workflows now see only the intended final output images in chat instead of duplicate images from intermediate processing nodes like masks, crops, or segmentation previews. [#20158](https://github.com/open-webui/open-webui/issues/20158), [#20182](https://github.com/open-webui/open-webui/pull/20182) +- 🖼️ Users with image generation enabled no longer see false vision capability warnings, allowing them to send follow-up messages after generating images and to send images to non-vision models for image editing. [#20129](https://github.com/open-webui/open-webui/issues/20129), [#20256](https://github.com/open-webui/open-webui/pull/20256) +- 🔌 Administrators no longer experience infinite loading screens when invalid or MCP-style configurations are used with OpenAPI connection types for external tools. [#20207](https://github.com/open-webui/open-webui/issues/20207), [#20257](https://github.com/open-webui/open-webui/pull/20257) +- 📥 Administrators no longer encounter TypeError crashes during SHA256 verification when uploading GGUF models via URL, fixing 500 Internal Server Error crashes. [#20263](https://github.com/open-webui/open-webui/issues/20263) +- 🚦 Users with Brave Search now experience automatic retry with a 1-second delay when hitting rate limits, preventing failures when sequential requests exceed the 1 request per second limit, though this only works reliably when web search concurrency is set to a maximum of 1. [#15134](https://github.com/open-webui/open-webui/issues/15134), [#20255](https://github.com/open-webui/open-webui/pull/20255) +- 🗄️ Administrators with Redis Sentinel deployments no longer experience crashes during websocket disconnections due to improper async-generator handling in the YDocManager. [#20142](https://github.com/open-webui/open-webui/issues/20142), [#20145](https://github.com/open-webui/open-webui/pull/20145) +- 🔐 Administrators using SCIM group management no longer encounter 500 errors when working with groups that have no members. [#20187](https://github.com/open-webui/open-webui/pull/20187) +- 🔗 Users now experience more reliable citations from AI models, especially when using smaller or weaker models that may not format citation references perfectly. [Commit](https://github.com/open-webui/open-webui/commit/c0ec04935b4eea3d334bfdec2fc41278f1085a49) +- 🕸️ Administrators can now successfully save WebSearch settings without encountering validation errors for domain filter lists, YouTube language settings, or timeout values. [#20422](https://github.com/open-webui/open-webui/pull/20422) +- 📦 Administrators installing with the uv package manager now experience successful installation after deprecated dependencies that were causing conflicts were removed. [#20177](https://github.com/open-webui/open-webui/issues/20177), [#20192](https://github.com/open-webui/open-webui/pull/20192) +- ⏱️ Administrators using custom "AIOHTTP_CLIENT_TIMEOUT" settings now see the configured timeout correctly applied to embedding generation, OAuth discovery, webhook calls, and tool/function loading instead of falling back to the default 300-second timeout. [Commit](https://github.com/open-webui/open-webui/commit/e67891a374625d9888ec391da561f0b4ed79ed5d) + +### Changed + +- ⚠️ **IMPORTANT: Coordinated Update Required for Administrators** — This release includes a major overhaul of database connection handling in the backend that requires all instances in multi-worker, multi-server, or load-balanced deployments to be updated simultaneously; running mixed versions will cause failures due to incompatible database connection management between old and new instances. +- 📝 Administrators who previously used the standalone "Markdown (Header)" text splitter must now switch to "character" or "token" mode with the new "ENABLE_MARKDOWN_HEADER_TEXT_SPLITTER" toggle enabled, as document chunking now applies markdown header splitting as a preprocessing step before character or token splitting. [Commit](https://github.com/open-webui/open-webui/commit/d3a682759f375c6cb0bc8c170f62863a070f712e), [Commit](https://github.com/open-webui/open-webui/commit/18a33a079bf07487edffc421a721c86194cc90c9), [Commit](https://github.com/open-webui/open-webui/commit/08bf4670ec862018f9dc57296cb19fd5eab14ef6) +- 🖼️ Users no longer see the "Generate Image" action button in chat message interfaces. [Commit](https://github.com/open-webui/open-webui/commit/f0829ba6e6fd200702fb76efc43dd785cf87fec9) +- 🔗 Administrators will find the Admin Evaluations page at the new URL "/admin/evaluations/feedback" instead of "/admin/evaluations/feedbacks" to use the correct uncountable form of the word. [#20296](https://github.com/open-webui/open-webui/pull/20296) +- 🔐 Scripts or integrations that directly called Image Generation, Web Search, or Audio APIs while those features were disabled in the Admin UI will now receive 403 Forbidden errors, as backend permission enforcement has been added to match frontend restrictions. [#20471](https://github.com/open-webui/open-webui/pull/20471) +- 👥 The default group sharing permission changed from "Members" to "Anyone", meaning users can now share content to any group configured with "Anyone" permission regardless of their membership in that group. [Commit](https://github.com/open-webui/open-webui/commit/ca514cd3eda2524b8da472ef17c0ccb216bac2e8) + ## [0.6.43] - 2025-12-22 ### Fixed From 636ba171a4ae6aff43846acbb40c6fcf513219e2 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 19:46:32 +0400 Subject: [PATCH 206/254] chore: format --- src/lib/components/admin/Evaluations.svelte | 1 - .../admin/Evaluations/Leaderboard.svelte | 54 ++++++++++++------- .../chat/MessageInput/CallOverlay.svelte | 19 +++---- .../Markdown/MarkdownInlineTokens.svelte | 16 +++++- .../chat/Messages/ResponseMessage.svelte | 24 ++++----- src/lib/i18n/locales/ar-BH/translation.json | 4 +- src/lib/i18n/locales/ar/translation.json | 4 +- src/lib/i18n/locales/bg-BG/translation.json | 4 +- src/lib/i18n/locales/bn-BD/translation.json | 4 +- src/lib/i18n/locales/bo-TB/translation.json | 4 +- src/lib/i18n/locales/bs-BA/translation.json | 4 +- src/lib/i18n/locales/ca-ES/translation.json | 4 +- src/lib/i18n/locales/ceb-PH/translation.json | 4 +- src/lib/i18n/locales/cs-CZ/translation.json | 4 +- src/lib/i18n/locales/da-DK/translation.json | 4 +- src/lib/i18n/locales/de-DE/translation.json | 4 +- src/lib/i18n/locales/dg-DG/translation.json | 4 +- src/lib/i18n/locales/el-GR/translation.json | 4 +- src/lib/i18n/locales/en-GB/translation.json | 4 +- src/lib/i18n/locales/en-US/translation.json | 4 +- src/lib/i18n/locales/es-ES/translation.json | 4 +- src/lib/i18n/locales/et-EE/translation.json | 4 +- src/lib/i18n/locales/eu-ES/translation.json | 4 +- src/lib/i18n/locales/fa-IR/translation.json | 4 +- src/lib/i18n/locales/fi-FI/translation.json | 4 +- src/lib/i18n/locales/fr-CA/translation.json | 4 +- src/lib/i18n/locales/fr-FR/translation.json | 4 +- src/lib/i18n/locales/gl-ES/translation.json | 4 +- src/lib/i18n/locales/he-IL/translation.json | 4 +- src/lib/i18n/locales/hi-IN/translation.json | 4 +- src/lib/i18n/locales/hr-HR/translation.json | 4 +- src/lib/i18n/locales/hu-HU/translation.json | 4 +- src/lib/i18n/locales/id-ID/translation.json | 4 +- src/lib/i18n/locales/ie-GA/translation.json | 4 +- src/lib/i18n/locales/it-IT/translation.json | 4 +- src/lib/i18n/locales/ja-JP/translation.json | 4 +- src/lib/i18n/locales/ka-GE/translation.json | 4 +- src/lib/i18n/locales/kab-DZ/translation.json | 4 +- src/lib/i18n/locales/ko-KR/translation.json | 4 +- src/lib/i18n/locales/lt-LT/translation.json | 4 +- src/lib/i18n/locales/ms-MY/translation.json | 4 +- src/lib/i18n/locales/nb-NO/translation.json | 4 +- src/lib/i18n/locales/nl-NL/translation.json | 4 +- src/lib/i18n/locales/pa-IN/translation.json | 4 +- src/lib/i18n/locales/pl-PL/translation.json | 4 +- src/lib/i18n/locales/pt-BR/translation.json | 4 +- src/lib/i18n/locales/pt-PT/translation.json | 4 +- src/lib/i18n/locales/ro-RO/translation.json | 4 +- src/lib/i18n/locales/ru-RU/translation.json | 4 +- src/lib/i18n/locales/sk-SK/translation.json | 4 +- src/lib/i18n/locales/sr-RS/translation.json | 4 +- src/lib/i18n/locales/sv-SE/translation.json | 4 +- src/lib/i18n/locales/th-TH/translation.json | 4 +- src/lib/i18n/locales/tk-TM/translation.json | 4 +- src/lib/i18n/locales/tr-TR/translation.json | 4 +- src/lib/i18n/locales/ug-CN/translation.json | 4 +- src/lib/i18n/locales/uk-UA/translation.json | 4 +- src/lib/i18n/locales/ur-PK/translation.json | 4 +- .../i18n/locales/uz-Cyrl-UZ/translation.json | 4 +- .../i18n/locales/uz-Latn-Uz/translation.json | 4 +- src/lib/i18n/locales/vi-VN/translation.json | 4 +- src/lib/i18n/locales/zh-CN/translation.json | 4 +- src/lib/i18n/locales/zh-TW/translation.json | 4 +- src/routes/auth/+page.svelte | 8 ++- 64 files changed, 245 insertions(+), 109 deletions(-) diff --git a/src/lib/components/admin/Evaluations.svelte b/src/lib/components/admin/Evaluations.svelte index 89b7664d82..b55f096ee9 100644 --- a/src/lib/components/admin/Evaluations.svelte +++ b/src/lib/components/admin/Evaluations.svelte @@ -6,7 +6,6 @@ import Leaderboard from './Evaluations/Leaderboard.svelte'; import Feedbacks from './Evaluations/Feedbacks.svelte'; - const i18n = getContext('i18n'); let selectedTab; diff --git a/src/lib/components/admin/Evaluations/Leaderboard.svelte b/src/lib/components/admin/Evaluations/Leaderboard.svelte index 0fdfd6f68c..837400e007 100644 --- a/src/lib/components/admin/Evaluations/Leaderboard.svelte +++ b/src/lib/components/admin/Evaluations/Leaderboard.svelte @@ -45,9 +45,7 @@ loading = true; try { const result = await getLeaderboard(localStorage.token, searchQuery); - const statsMap = new Map( - (result?.entries ?? []).map((e) => [e.model_id, e]) - ); + const statsMap = new Map((result?.entries ?? []).map((e) => [e.model_id, e])); rankedModels = $models .filter((m) => m?.owned_by !== 'arena' && !m?.info?.meta?.hidden) @@ -106,7 +104,9 @@ -
+
{$i18n.t('Leaderboard')} {rankedModels.length} @@ -123,9 +123,13 @@
-
+
{#if loading} -
+
{/if} @@ -133,25 +137,27 @@ {#if !rankedModels.length && !loading}
{$i18n.t('No models found')}
{:else if rankedModels.length} -
setSortKey('rating')} - > -
- {$i18n.t('RK')} - {#if orderBy === 'rating'} - - {#if direction === 'asc'} - - {:else} - - {/if} - - {:else} - - {/if} -
-
setSortKey('name')} - > -
- {$i18n.t('Model')} - {#if orderBy === 'name'} - - {#if direction === 'asc'} - - {:else} - - {/if} - - {:else} - - {/if} -
-
setSortKey('rating')} - > -
- {$i18n.t('Rating')} - {#if orderBy === 'rating'} - - {#if direction === 'asc'} - - {:else} - - {/if} - - {:else} - - {/if} -
-
setSortKey('won')} - > -
- {$i18n.t('Won')} - {#if orderBy === 'won'} - - {#if direction === 'asc'} - - {:else} - - {/if} - - {:else} - - {/if} -
-
setSortKey('lost')} - > -
- {$i18n.t('Lost')} - {#if orderBy === 'lost'} - - {#if direction === 'asc'} - - {:else} - - {/if} - - {:else} - - {/if} -
-
toggleSort(col.key)} + > +
+ {$i18n.t(col.label)} + {#if orderBy === col.key} + {#if direction === 'asc'}{:else}{/if} + {:else} + + {/if} +
+
-
- {model?.rating !== '-' ? modelIdx + 1 : '-'} -
+
+ {model.rating !== '-' ? idx + 1 : '-'} +
-
- {model.name} -
- -
- {model.name} -
+ {model.name} + {model.name}
+ {model.rating} -
- {#if model.stats.won === '-'} - - - {:else} - - {model.stats.won} - {/if} -
+
+ {#if model.stats.won === '-'}-{:else} + + {model.stats.won} + {/if} -
- {#if model.stats.lost === '-'} - - - {:else} - - {model.stats.lost} - {/if} -
+
+ {#if model.stats.lost === '-'}-{:else} + + {model.stats.lost} + {/if}
+
- {#each [ - { key: 'rating', label: 'RK', class: 'w-3' }, - { key: 'name', label: 'Model', class: '' }, - { key: 'rating', label: 'Rating', class: 'text-right w-fit' }, - { key: 'won', label: 'Won', class: 'text-right w-5' }, - { key: 'lost', label: 'Lost', class: 'text-right w-5' } - ] as col} + {#each [{ key: 'rating', label: 'RK', class: 'w-3' }, { key: 'name', label: 'Model', class: '' }, { key: 'rating', label: 'Rating', class: 'text-right w-fit' }, { key: 'won', label: 'Won', class: 'text-right w-5' }, { key: 'lost', label: 'Lost', class: 'text-right w-5' }] as col} @@ -204,8 +214,12 @@
- ⓘ {$i18n.t('The evaluation leaderboard is based on the Elo rating system and is updated in real-time.')} + ⓘ {$i18n.t( + 'The evaluation leaderboard is based on the Elo rating system and is updated in real-time.' + )}
- {$i18n.t('The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.')} + {$i18n.t( + 'The leaderboard is currently in beta, and we may adjust the rating calculations as we refine the algorithm.' + )}
diff --git a/src/lib/components/chat/MessageInput/CallOverlay.svelte b/src/lib/components/chat/MessageInput/CallOverlay.svelte index da45336242..d5977c0eb0 100644 --- a/src/lib/components/chat/MessageInput/CallOverlay.svelte +++ b/src/lib/components/chat/MessageInput/CallOverlay.svelte @@ -386,10 +386,7 @@ clearInterval(getVoicesLoop); const voiceId = getVoiceId(); - const voice = - voices - ?.filter((v) => v.voiceURI === voiceId) - ?.at(0) ?? undefined; + const voice = voices?.filter((v) => v.voiceURI === voiceId)?.at(0) ?? undefined; currentUtterance = new SpeechSynthesisUtterance(content); currentUtterance.rate = $settings.audio?.tts?.playbackRate ?? 1; @@ -494,14 +491,12 @@ audioCache.set(content, new Audio(url)); } } else if ($config.audio.tts.engine !== '') { - const res = await synthesizeOpenAISpeech( - localStorage.token, - getVoiceId(), - content - ).catch((error) => { - console.error(error); - return null; - }); + const res = await synthesizeOpenAISpeech(localStorage.token, getVoiceId(), content).catch( + (error) => { + console.error(error); + return null; + } + ); if (res) { const blob = await res.blob(); diff --git a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte index b187ecfe2b..022bcfb2cb 100644 --- a/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte +++ b/src/lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte @@ -55,11 +55,23 @@ {:else if token.type === 'link'} {#if token.tokens} - handleLinkClick(e, token.href)}> + handleLinkClick(e, token.href)} + > {:else} - handleLinkClick(e, token.href)}>{token.text} + handleLinkClick(e, token.href)}>{token.text} {/if} {:else if token.type === 'image'} diff --git a/src/lib/components/chat/Messages/ResponseMessage.svelte b/src/lib/components/chat/Messages/ResponseMessage.svelte index bd085573f4..78575ba9ce 100644 --- a/src/lib/components/chat/Messages/ResponseMessage.svelte +++ b/src/lib/components/chat/Messages/ResponseMessage.svelte @@ -228,10 +228,7 @@ clearInterval(getVoicesLoop); const voiceId = getVoiceId(); - const voice = - voices - ?.filter((v) => v.voiceURI === voiceId) - ?.at(0) ?? undefined; + const voice = voices?.filter((v) => v.voiceURI === voiceId)?.at(0) ?? undefined; console.log(voice); @@ -312,17 +309,15 @@ } } else { for (const [idx, sentence] of messageContentParts.entries()) { - const res = await synthesizeOpenAISpeech( - localStorage.token, - voiceId, - sentence - ).catch((error) => { - console.error(error); - toast.error(`${error}`); + const res = await synthesizeOpenAISpeech(localStorage.token, voiceId, sentence).catch( + (error) => { + console.error(error); + toast.error(`${error}`); - speaking = false; - loadingSpeech = false; - }); + speaking = false; + loadingSpeech = false; + } + ); if (res && speaking) { const blob = await res.blob(); @@ -336,7 +331,6 @@ } }; - let preprocessedDetailsCache = []; function preprocessForEditing(content: string): string { diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index 60079fa69e..e61f7db2c5 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "وضع الملف", "File not found.": "لم يتم العثور على الملف.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1429,7 +1432,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "منصب", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ar/translation.json b/src/lib/i18n/locales/ar/translation.json index 0ba6bc1ec2..ab6f7c2260 100644 --- a/src/lib/i18n/locales/ar/translation.json +++ b/src/lib/i18n/locales/ar/translation.json @@ -519,6 +519,7 @@ "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. en": "", "e.g. My Filter": "مثال: مرشحي", "e.g. My Tools": "مثال: أدواتي", @@ -782,6 +783,7 @@ "File": "ملف", "File added successfully.": "تم إضافة الملف بنجاح.", "File content updated successfully.": "تم تحديث محتوى الملف بنجاح.", + "File Context": "", "File Mode": "وضع الملف", "File not found.": "لم يتم العثور على الملف.", "File removed successfully.": "تم حذف الملف بنجاح.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1429,7 +1432,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "إدخال نص منسق للمحادثة", - "RK": "RK", "Role": "منصب", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index 00c4073c09..40e4780d2d 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "напр. Филтър за премахване на нецензурни думи от текста", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "напр. Моят филтър", "e.g. My Tools": "напр. Моите инструменти", @@ -782,6 +783,7 @@ "File": "Файл", "File added successfully.": "Файлът е добавен успешно.", "File content updated successfully.": "Съдържанието на файла е актуализирано успешно.", + "File Context": "", "File Mode": "Файлов режим", "File not found.": "Файл не е намерен.", "File removed successfully.": "Файлът е премахнат успешно.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Богат текстов вход за чат", - "RK": "RK", "Role": "Роля", "Rosé Pine": "Rose pine", "Rosé Pine Dawn": "Rose pine Dawn", diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index dbad0fb1f6..6399f801d1 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "ফাইল মোড", "File not found.": "ফাইল পাওয়া যায়নি", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "পদবি", "Rosé Pine": "রোজ পাইন", "Rosé Pine Dawn": "ভোরের রোজ পাইন", diff --git a/src/lib/i18n/locales/bo-TB/translation.json b/src/lib/i18n/locales/bo-TB/translation.json index 064360fc82..256d089229 100644 --- a/src/lib/i18n/locales/bo-TB/translation.json +++ b/src/lib/i18n/locales/bo-TB/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "དཔེར་ན། ༦༠", "e.g. A filter to remove profanity from text": "དཔེར་ན། ཡིག་རྐྱང་ནས་ཚིག་རྩུབ་འདོར་བྱེད་ཀྱི་འཚག་མ།", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "དཔེར་ན། ངའི་འཚག་མ།", "e.g. My Tools": "དཔེར་ན། ངའི་ལག་ཆ།", @@ -782,6 +783,7 @@ "File": "ཡིག་ཆ།", "File added successfully.": "ཡིག་ཆ་ལེགས་པར་བསྣན་ཟིན།", "File content updated successfully.": "ཡིག་ཆའི་ནང་དོན་ལེགས་པར་གསར་སྒྱུར་བྱས་ཟིན།", + "File Context": "", "File Mode": "ཡིག་ཆའི་མ་དཔེ།", "File not found.": "ཡིག་ཆ་མ་རྙེད།", "File removed successfully.": "ཡིག་ཆ་ལེགས་པར་བསུབས་ཟིན།", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "ནང་དོན་ཆ་ཚང་དེ་ནང་དོན་དུ་བཅུག་ནས་སྒྲུབ་རིམ་ཆ་ཚང་བྱེད་པ། འདི་ནི་འདྲི་བ་རྙོག་འཛིང་ཅན་གྱི་ཆེད་དུ་འོས་སྦྱོར་བྱེད།", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "ཁ་བརྡའི་ཆེད་དུ་ཡིག་རྐྱང་ཕུན་སུམ་ཚོགས་པའི་ནང་འཇུག", - "RK": "RK", "Role": "གནས་ཚད།", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/bs-BA/translation.json b/src/lib/i18n/locales/bs-BA/translation.json index c4150297eb..80241060cb 100644 --- a/src/lib/i18n/locales/bs-BA/translation.json +++ b/src/lib/i18n/locales/bs-BA/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Način datoteke", "File not found.": "Datoteka nije pronađena.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "Informacije", "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)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Uloga", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index 0e98084397..7624e933a9 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "p. ex. 60", "e.g. A filter to remove profanity from text": "p. ex. Un filtre per eliminar paraules malsonants del text", "e.g. about the Roman Empire": "p. ex. sobre l'imperi Romà", + "e.g. alloy, echo, shimmer": "", "e.g. en": "p. ex. en", "e.g. My Filter": "p. ex. El meu filtre", "e.g. My Tools": "p. ex. Les meves eines", @@ -782,6 +783,7 @@ "File": "Arxiu", "File added successfully.": "L'arxiu s'ha afegit correctament.", "File content updated successfully.": "El contingut de l'arxiu s'ha actualitzat correctament.", + "File Context": "", "File Mode": "Mode d'arxiu", "File not found.": "No s'ha trobat l'arxiu.", "File removed successfully.": "Arxiu eliminat correctament.", @@ -937,6 +939,7 @@ "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.": "Influeix amb la rapidesa amb què l'algoritme respon als comentaris del text generat. Una taxa d'aprenentatge més baixa donarà lloc a ajustos més lents, mentre que una taxa d'aprenentatge més alta farà que l'algorisme sigui més sensible.", "Info": "Informació", "Initials": "Inicials", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injectar tot el contingut com a context per a un processament complet, això es recomana per a consultes complexes.", "Input": "Entrada", "Input Key (e.g. text, unet_name, steps)": "Entra la clau (p. ex. text, unet_name, steps)", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "S'han obtingut {{count}} sources_other", "Retrieved 1 source": "S'ha obtingut una font", "Rich Text Input for Chat": "Entrada de text ric per al xat", - "RK": "RK", "Role": "Rol", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Albada Rosé Pine", diff --git a/src/lib/i18n/locales/ceb-PH/translation.json b/src/lib/i18n/locales/ceb-PH/translation.json index 6f888c451f..94c6ded2dc 100644 --- a/src/lib/i18n/locales/ceb-PH/translation.json +++ b/src/lib/i18n/locales/ceb-PH/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "File mode", "File not found.": "Wala makit-an ang file.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Papel", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Aube Pine Rosé", diff --git a/src/lib/i18n/locales/cs-CZ/translation.json b/src/lib/i18n/locales/cs-CZ/translation.json index e9aa0809fa..ba0b661b24 100644 --- a/src/lib/i18n/locales/cs-CZ/translation.json +++ b/src/lib/i18n/locales/cs-CZ/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "např. 60", "e.g. A filter to remove profanity from text": "např. Filtr pro odstranění vulgarismů z textu", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "např. cs", "e.g. My Filter": "např. Můj filtr", "e.g. My Tools": "např. Moje nástroje", @@ -782,6 +783,7 @@ "File": "Soubor", "File added successfully.": "Soubor byl úspěšně přidán.", "File content updated successfully.": "Obsah souboru byl úspěšně aktualizován.", + "File Context": "", "File Mode": "Režim souboru", "File not found.": "Soubor nenalezen.", "File removed successfully.": "Soubor byl úspěšně odstraněn.", @@ -937,6 +939,7 @@ "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.": "Ovlivňuje, jak rychle algoritmus reaguje na zpětnou vazbu z generovaného textu. Nižší míra učení povede k pomalejším úpravám, zatímco vyšší míra učení učiní algoritmus citlivějším.", "Info": "Info", "Initials": "", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Vložit celý obsah jako kontext pro komplexní zpracování, doporučeno pro složité dotazy.", "Input": "Vstup", "Input Key (e.g. text, unet_name, steps)": "Vstupní klíč (např. text, unet_name, steps)", @@ -1427,7 +1430,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Pokročilé formátování vstupního pole konverzace", - "RK": "RK", "Role": "Role", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/da-DK/translation.json b/src/lib/i18n/locales/da-DK/translation.json index 36d87129aa..51d87c6159 100644 --- a/src/lib/i18n/locales/da-DK/translation.json +++ b/src/lib/i18n/locales/da-DK/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "f.eks. 60", "e.g. A filter to remove profanity from text": "f.eks. Et filter til at fjerne upassende ord fra tekst", "e.g. about the Roman Empire": "f.eks. om Romerriget", + "e.g. alloy, echo, shimmer": "", "e.g. en": "f.eks. en", "e.g. My Filter": "f.eks. Mit Filter", "e.g. My Tools": "f.eks. Mine Værktøjer", @@ -782,6 +783,7 @@ "File": "Fil", "File added successfully.": "Fil tilføjet.", "File content updated successfully.": "Filens indhold er opdateret.", + "File Context": "", "File Mode": "Filtilstand", "File not found.": "Filen blev ikke fundet.", "File removed successfully.": "Fil fjernet.", @@ -937,6 +939,7 @@ "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.": "Påvirker hvor hurtigt algoritmen reagerer på feedback fra den genererede tekst. En lavere indlæringshastighed vil resultere i langsommere justeringer, mens en højere indlæringshastighed vil gøre algoritmen mere responsiv.", "Info": "Info", "Initials": "Initialer", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injicer alt indhold som kontekst til omfattende behandling, dette anbefales til komplekse forespørgsler.", "Input": "Input", "Input Key (e.g. text, unet_name, steps)": "Inputnøgler (f.eks. text, unet_name, steps)", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "Fandt {{count}} kildehenvisninger", "Retrieved 1 source": "Fandt en kildehenvisning", "Rich Text Input for Chat": "Rich text input til chat", - "RK": "RK", "Role": "Rolle", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 5f0d709d5a..28c5c905fe 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "z. B. 60", "e.g. A filter to remove profanity from text": "z. B. Ein Filter zum Entfernen von Schimpfwörtern", "e.g. about the Roman Empire": "z. B. über das Römische Reich", + "e.g. alloy, echo, shimmer": "", "e.g. en": "z. B. de", "e.g. My Filter": "z. B. Mein Filter", "e.g. My Tools": "z. B. Meine Werkzeuge", @@ -782,6 +783,7 @@ "File": "Datei", "File added successfully.": "Datei erfolgreich hinzugefügt.", "File content updated successfully.": "Dateiinhalt erfolgreich aktualisiert.", + "File Context": "", "File Mode": "Datei-Modus", "File not found.": "Datei nicht gefunden.", "File removed successfully.": "Datei erfolgreich entfernt.", @@ -937,6 +939,7 @@ "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.": "Beeinflusst, wie schnell der Algorithmus auf Feedback aus dem generierten Text reagiert. Eine niedrigere Lernrate führt zu langsameren Anpassungen, während eine höhere Lernrate den Algorithmus reaktionsschneller macht.", "Info": "Info", "Initials": "Initialen", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Gesamten Inhalt als Kontext für umfassende Verarbeitung einfügen; dies wird für komplexe Abfragen empfohlen.", "Input": "Eingabe", "Input Key (e.g. text, unet_name, steps)": "Eingabeschlüssel (z. B. text, unet_name, steps)", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "{{count}} Quellen abgerufen", "Retrieved 1 source": "1 Quelle abgerufen", "Rich Text Input for Chat": "Rich-Text-Eingabe für Chat", - "RK": "RK", "Role": "Rolle", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index 28746b7505..e2843f3b2f 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Bark Mode", "File not found.": "Bark not found.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Role", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/el-GR/translation.json b/src/lib/i18n/locales/el-GR/translation.json index 12717f5818..558c5dbe3e 100644 --- a/src/lib/i18n/locales/el-GR/translation.json +++ b/src/lib/i18n/locales/el-GR/translation.json @@ -519,6 +519,7 @@ "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. en": "π.χ. en", "e.g. My Filter": "π.χ. Το Φίλτρο Μου", "e.g. My Tools": "π.χ. Τα Εργαλεία Μου", @@ -782,6 +783,7 @@ "File": "Αρχείο", "File added successfully.": "Το αρχείο προστέθηκε με επιτυχία.", "File content updated successfully.": "Το περιεχόμενο του αρχείου ενημερώθηκε με επιτυχία.", + "File Context": "", "File Mode": "Λειτουργία Αρχείου", "File not found.": "Αρχείο δεν βρέθηκε.", "File removed successfully.": "Το αρχείο αφαιρέθηκε με επιτυχία.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Εισάγετε ολόκληρο το περιεχόμενο ως συμφραζόμενο για ολοκληρωμένη επεξεργασία. Αυτό συνιστάται για σύνθετα ερωτήματα.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Πλούσιο Εισαγωγή Κειμένου για Συνομιλία", - "RK": "", "Role": "Ρόλος", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/en-GB/translation.json b/src/lib/i18n/locales/en-GB/translation.json index e00b31a705..3e3835527a 100644 --- a/src/lib/i18n/locales/en-GB/translation.json +++ b/src/lib/i18n/locales/en-GB/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "", "File not found.": "", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "", "Rosé Pine": "", "Rosé Pine Dawn": "", diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index 7ba5a1d5fa..773a11635b 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "", "File not found.": "", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "", "Rosé Pine": "", "Rosé Pine Dawn": "", diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 49aba73fb1..a974600c5b 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "p.ej. 60", "e.g. A filter to remove profanity from text": "p.ej. Un filtro para eliminar malas palabras del texto", "e.g. about the Roman Empire": "p.ej. sobre el imperio romano", + "e.g. alloy, echo, shimmer": "", "e.g. en": "p.ej. es", "e.g. My Filter": "p.ej. Mi Filtro", "e.g. My Tools": "p.ej. Mis Herramientas", @@ -782,6 +783,7 @@ "File": "Archivo", "File added successfully.": "Archivo añadido correctamente.", "File content updated successfully.": "Contenido del archivo actualizado correctamente.", + "File Context": "", "File Mode": "Modo de Archivo", "File not found.": "Archivo no encontrado.", "File removed successfully.": "Archivo eliminado correctamente.", @@ -937,6 +939,7 @@ "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.": "Influye en la rápidez de respuesta a la realimentación desde el texto generado. Una tasa de aprendizaje más baja resulta en un ajustado más lento, mientras que una tasa de aprendizaje más alta hará que el algoritmo sea más reactivo.", "Info": "Información", "Initials": "Iniciales", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Inyecta el contenido completo como contexto para un procesado comprensivo, recomendado para consultas complejas.", "Input": "Entrada", "Input Key (e.g. text, unet_name, steps)": "Ingresa Clave (ej. text, unet_name. steps)", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "Recuperadas {{count}} otras fuentes", "Retrieved 1 source": "Recuperada una fuente", "Rich Text Input for Chat": "Entrada de Texto Enriquecido para el Chat", - "RK": "RK", "Role": "Rol", "Rosé Pine": "Pino Rosa", "Rosé Pine Dawn": "Pino Rosa Amanecer", diff --git a/src/lib/i18n/locales/et-EE/translation.json b/src/lib/i18n/locales/et-EE/translation.json index 030ccfcdf1..ea3b2cc117 100644 --- a/src/lib/i18n/locales/et-EE/translation.json +++ b/src/lib/i18n/locales/et-EE/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "nt 60", "e.g. A filter to remove profanity from text": "nt filter, mis eemaldab tekstist roppused", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "nt en", "e.g. My Filter": "nt Minu Filter", "e.g. My Tools": "nt Minu Tööriistad", @@ -782,6 +783,7 @@ "File": "Fail", "File added successfully.": "Fail edukalt lisatud.", "File content updated successfully.": "Faili sisu edukalt uuendatud.", + "File Context": "", "File Mode": "Faili režiim", "File not found.": "Faili ei leitud.", "File removed successfully.": "Fail edukalt eemaldatud.", @@ -937,6 +939,7 @@ "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.": "Mõjutab, kui kiiresti algoritm reageerib genereeritud teksti tagasisidele. Madalam õppimiskiirus annab tulemuseks aeglasemad kohandused, samas kui kõrgem õppimiskiirus muudab algoritmi tundlikumaks.", "Info": "Info", "Initials": "Initsiaalid", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.", "Input": "Sisend", "Input Key (e.g. text, unet_name, steps)": "Input Võti (e.g. text, unet_name, steps)", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "Retrieved {{count}} allikad_other", "Retrieved 1 source": "Retrieved 1 allikas", "Rich Text Input for Chat": "Rikasteksti sisend vestluse jaoks", - "RK": "RK", "Role": "Roll", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/eu-ES/translation.json b/src/lib/i18n/locales/eu-ES/translation.json index 018d6d4c2b..e031b967f1 100644 --- a/src/lib/i18n/locales/eu-ES/translation.json +++ b/src/lib/i18n/locales/eu-ES/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "adib. Testutik lizunkeriak kentzeko iragazki bat", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "adib. Nire Iragazkia", "e.g. My Tools": "adib. Nire Tresnak", @@ -782,6 +783,7 @@ "File": "Fitxategia", "File added successfully.": "Fitxategia ongi gehitu da.", "File content updated successfully.": "Fitxategiaren edukia ongi eguneratu da.", + "File Context": "", "File Mode": "Fitxategi Modua", "File not found.": "Ez da fitxategia aurkitu.", "File removed successfully.": "Fitxategia ongi ezabatu da.", @@ -937,6 +939,7 @@ "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": "Informazioa", "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)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Testu aberastuko sarrera txaterako", - "RK": "RK", "Role": "Rola", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index 145410b25a..b2d76e2826 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -519,6 +519,7 @@ "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. en": "مثلاً en", "e.g. My Filter": "مثلا فیلتر من", "e.g. My Tools": "مثلا ابزارهای من", @@ -782,6 +783,7 @@ "File": "پرونده", "File added successfully.": "پرونده با موفقیت افزوده شد.", "File content updated successfully.": "محتوای پرونده با موفقیت به\u200cروز شد.", + "File Context": "", "File Mode": "حالت پرونده", "File not found.": "پرونده یافت نشد.", "File removed successfully.": "پرونده با موفقیت حذف شد.", @@ -937,6 +939,7 @@ "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.": "تأثیر می\u200cگذارد که الگوریتم چقدر سریع به بازخورد متن تولید شده پاسخ می\u200cدهد. نرخ یادگیری پایین\u200cتر منجر به تنظیمات کندتر می\u200cشود، در حالی که نرخ یادگیری بالاتر الگوریتم را پاسخگوتر می\u200cکند.", "Info": "اطلاعات", "Initials": "حروف اول", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "کل محتوا را به عنوان زمینه برای پردازش جامع تزریق کنید، این برای پرس\u200cوجوهای پیچیده توصیه می\u200cشود.", "Input": "ورودی", "Input Key (e.g. text, unet_name, steps)": "کلید ورودی (مثلاً text, unet_name, steps)", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "{{count}} منبع بازیابی شد", "Retrieved 1 source": "۱ منبع بازیابی شد", "Rich Text Input for Chat": "ورودی متن غنی برای چت", - "RK": "RK", "Role": "نقش", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index bd4397f7bb..06f45c2a18 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "esim. 60", "e.g. A filter to remove profanity from text": "esim. suodatin, joka poistaa kirosanoja tekstistä", "e.g. about the Roman Empire": "esim. Rooman valtakunta", + "e.g. alloy, echo, shimmer": "", "e.g. en": "esim. en", "e.g. My Filter": "esim. Oma suodatin", "e.g. My Tools": "esim. Omat työkalut", @@ -782,6 +783,7 @@ "File": "Tiedosto", "File added successfully.": "Tiedosto lisätty onnistuneesti.", "File content updated successfully.": "Tiedoston sisältö päivitetty onnistuneesti.", + "File Context": "", "File Mode": "Tiedostotila", "File not found.": "Tiedostoa ei löytynyt.", "File removed successfully.": "Tiedosto poistettu onnistuneesti.", @@ -937,6 +939,7 @@ "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.": "Kuinka nopeasti algoritmi mukautuu generoidun tekstin palautteeseen. Alempi oppimisnopeus hidastaa mukautumista, kun taas nopeampi oppimisnopeus tekee algoritmistä reagoivamman.", "Info": "Tiedot", "Initials": "Nimikirjaimet", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Upota koko sisältö kontekstiin kattavaa käsittelyä varten. Tätä suositellaan monimutkaisille kyselyille.", "Input": "Tekstikenttä", "Input Key (e.g. text, unet_name, steps)": "Syötteen arvo (esim. text, unet_namme, steps)", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "Noudettu {{count}} sources_other", "Retrieved 1 source": "1 lähde noudettu", "Rich Text Input for Chat": "Rikasteksti-kenttä chattiin", - "RK": "RK", "Role": "Rooli", "Rosé Pine": "Rosépuu", "Rosé Pine Dawn": "Rosépuu aamunkoitto", diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index d716d112bd..dea2622ff6 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "par ex. 60", "e.g. A filter to remove profanity from text": "par ex. un filtre pour retirer les vulgarités du texte", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "par ex. fr", "e.g. My Filter": "par ex. Mon Filtre", "e.g. My Tools": "par ex. Mes Outils", @@ -782,6 +783,7 @@ "File": "Fichier", "File added successfully.": "Fichier ajouté avec succès.", "File content updated successfully.": "Contenu du fichier mis à jour avec succès.", + "File Context": "", "File Mode": "Mode fichier", "File not found.": "Fichier introuvable.", "File removed successfully.": "Fichier supprimé avec succès.", @@ -937,6 +939,7 @@ "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.": "Influe sur la rapidité avec laquelle l'algorithme répond aux retours d'information du texte généré. Un taux d'apprentissage plus bas entraînera des ajustements plus lents, tandis qu'un taux d'apprentissage plus élevé rendra l'algorithme plus réactif.", "Info": "Info", "Initials": "", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injecter l'ensemble du contenu comme contexte pour un traitement complet, recommandé pour les requêtes complexes.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Saisie de texte enrichi pour la conversation", - "RK": "Rang", "Role": "Rôle", "Rosé Pine": "Pin rosé", "Rosé Pine Dawn": "Aube de Pin Rosé", diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 2cabdd9b6e..645eb83afe 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "par ex. 60", "e.g. A filter to remove profanity from text": "par ex. un filtre pour retirer les vulgarités du texte", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "par ex. fr", "e.g. My Filter": "par ex. Mon Filtre", "e.g. My Tools": "par ex. Mes Outils", @@ -782,6 +783,7 @@ "File": "Fichier", "File added successfully.": "Fichier ajouté avec succès.", "File content updated successfully.": "Contenu du fichier mis à jour avec succès.", + "File Context": "", "File Mode": "Mode fichier", "File not found.": "Fichier introuvable.", "File removed successfully.": "Fichier supprimé avec succès.", @@ -937,6 +939,7 @@ "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.": "Influe sur la rapidité avec laquelle l'algorithme répond aux retours d'information du texte généré. Un taux d'apprentissage plus bas entraînera des ajustements plus lents, tandis qu'un taux d'apprentissage plus élevé rendra l'algorithme plus réactif.", "Info": "Info", "Initials": "Initiales", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injecter l'ensemble du contenu comme contexte pour un traitement complet, recommandé pour les requêtes complexes.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "Une source récupérée", "Rich Text Input for Chat": "Saisie de texte enrichi pour la conversation", - "RK": "Rang", "Role": "Rôle", "Rosé Pine": "Pin rosé", "Rosé Pine Dawn": "Aube de Pin Rosé", diff --git a/src/lib/i18n/locales/gl-ES/translation.json b/src/lib/i18n/locales/gl-ES/translation.json index 983fa67301..ba1158c552 100644 --- a/src/lib/i18n/locales/gl-ES/translation.json +++ b/src/lib/i18n/locales/gl-ES/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "e.g. 60", "e.g. A filter to remove profanity from text": "p.ej. Un filtro para eliminar a profanidade do texto", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "p.ej. O meu Filtro", "e.g. My Tools": "p.ej. As miñas ferramentas", @@ -782,6 +783,7 @@ "File": "Arquivo", "File added successfully.": "Arquivo agregado correctamente.", "File content updated successfully.": "Contido do Arquivo actualizado correctamente.", + "File Context": "", "File Mode": "Modo de Arquivo", "File not found.": "Arquivo non encontrado.", "File removed successfully.": "Arquivo eliminado correctamente.", @@ -937,6 +939,7 @@ "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": "Información", "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)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Entrada de texto enriquecido para chat", - "RK": "RK", "Role": "Rol", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index be951d92e0..d1aab95ad6 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "מצב קובץ", "File not found.": "הקובץ לא נמצא.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "תפקיד", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index 1933dbcfac..329c16074d 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "फ़ाइल मोड", "File not found.": "फ़ाइल प्राप्त नहीं हुई।", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "भूमिका", "Rosé Pine": "रोसे पिन", "Rosé Pine Dawn": "रोसे पिन डेन", diff --git a/src/lib/i18n/locales/hr-HR/translation.json b/src/lib/i18n/locales/hr-HR/translation.json index f62ca9b71f..a4c1093700 100644 --- a/src/lib/i18n/locales/hr-HR/translation.json +++ b/src/lib/i18n/locales/hr-HR/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Način datoteke", "File not found.": "Datoteka nije pronađena.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "Informacije", "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)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Uloga", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/hu-HU/translation.json b/src/lib/i18n/locales/hu-HU/translation.json index 86e391fb69..ed39e0b2e5 100644 --- a/src/lib/i18n/locales/hu-HU/translation.json +++ b/src/lib/i18n/locales/hu-HU/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "pl. 60", "e.g. A filter to remove profanity from text": "pl. Egy szűrő a trágárság eltávolítására a szövegből", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "pl. Az én szűrőm", "e.g. My Tools": "pl. Az én eszközeim", @@ -782,6 +783,7 @@ "File": "Fájl", "File added successfully.": "Fájl sikeresen hozzáadva.", "File content updated successfully.": "Fájl tartalom sikeresen frissítve.", + "File Context": "", "File Mode": "Fájl mód", "File not found.": "Fájl nem található.", "File removed successfully.": "Fájl sikeresen eltávolítva.", @@ -937,6 +939,7 @@ "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.": "Befolyásolja, hogy az algoritmus milyen gyorsan reagál a generált szöveg visszajelzéseire. Alacsonyabb tanulási ráta lassabb调整okat eredményez, míg magasabb ráta gyorsabb reagálást biztosít.", "Info": "Információ", "Initials": "", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Az összes tartalom kontextusként való befecskendezése átfogó feldolgozáshoz, ez összetett lekérdezésekhez ajánlott.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Formázott szövegbevitel a chathez", - "RK": "RK", "Role": "Szerep", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/id-ID/translation.json b/src/lib/i18n/locales/id-ID/translation.json index 7e3ef2a1bd..238034fb63 100644 --- a/src/lib/i18n/locales/id-ID/translation.json +++ b/src/lib/i18n/locales/id-ID/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "Berkas", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Mode File", "File not found.": "File tidak ditemukan.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "Info", "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)": "", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Peran", "Rosé Pine": "Pinus Rosé", "Rosé Pine Dawn": "Rosé Pine Fajar", diff --git a/src/lib/i18n/locales/ie-GA/translation.json b/src/lib/i18n/locales/ie-GA/translation.json index 7e45c4f6ac..6aae744005 100644 --- a/src/lib/i18n/locales/ie-GA/translation.json +++ b/src/lib/i18n/locales/ie-GA/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "m.sh. 60", "e.g. A filter to remove profanity from text": "m.sh. Scagaire chun profanity a bhaint as téacs", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "m.sh. en", "e.g. My Filter": "m.sh. Mo Scagaire", "e.g. My Tools": "m.sh. Mo Uirlisí", @@ -782,6 +783,7 @@ "File": "Comhad", "File added successfully.": "D'éirigh leis an gcomhad a chur leis.", "File content updated successfully.": "D'éirigh le hábhar an chomhaid a nuashonrú.", + "File Context": "", "File Mode": "Mód Comhad", "File not found.": "Níor aimsíodh an comhad.", "File removed successfully.": "D'éirigh le baint an chomhaid.", @@ -937,6 +939,7 @@ "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.": "Bíonn tionchar aige ar chomh tapa agus a fhreagraíonn an t-algartam d'aiseolas ón téacs ginte. Beidh coigeartuithe níos moille mar thoradh ar ráta foghlama níos ísle, agus déanfaidh ráta foghlama níos airde an t-algartam níos freagraí.", "Info": "Eolas", "Initials": "Túslitreacha", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Instealladh an t-ábhar ar fad mar chomhthéacs do phróiseáil chuimsitheach, moltar é seo le haghaidh ceisteanna casta.", "Input": "Ionchur", "Input Key (e.g. text, unet_name, steps)": "Eochair Ionchuir (m.sh. téacs, unet_name, céimeanna)", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "Aisghafa {{count}} foinsí_eile", "Retrieved 1 source": "Aisghafa 1 fhoinse", "Rich Text Input for Chat": "Ionchur Saibhir Téacs don Chomhrá", - "RK": "RK", "Role": "Ról", "Rosé Pine": "Péine Rosé", "Rosé Pine Dawn": "Rosé Péine Breacadh an lae", diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index 8ff1475acd..d50438cd07 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "ad esempio 60", "e.g. A filter to remove profanity from text": "ad esempio un filtro per rimuovere le parolacce dal testo", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "ad esempio en", "e.g. My Filter": "ad esempio il Mio Filtro", "e.g. My Tools": "ad esempio i Miei Strumenti", @@ -782,6 +783,7 @@ "File": "File", "File added successfully.": "File aggiunto con successo.", "File content updated successfully.": "Contenuto del file aggiornato con successo.", + "File Context": "", "File Mode": "Modalità File", "File not found.": "File non trovato.", "File removed successfully.": "File rimosso con successo.", @@ -937,6 +939,7 @@ "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.": "Influenza la velocità con cui l'algoritmo risponde al feedback del testo generato. Un tasso di apprendimento più basso comporterà aggiustamenti più lenti, mentre un tasso di apprendimento più alto renderà l'algoritmo più reattivo.", "Info": "Informazioni", "Initials": "", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Inietta l'intero contenuto come contesto per un'elaborazione completa, questo è consigliato per query complesse.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Input di testo ricco per la chat", - "RK": "RK", "Role": "Ruolo", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index 2bf7307d4c..6b12d23f5a 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "例: テキストから不適切な表現を削除するフィルター", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "ファイル", "File added successfully.": "ファイル追加が成功しました。", "File content updated successfully.": "ファイルコンテンツ追加が成功しました。", + "File Context": "", "File Mode": "ファイルモード", "File not found.": "ファイルが見つかりません。", "File removed successfully.": "ファイル削除が成功しました。", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "全文を取り込むことで全体を処理します。複雑な問い合わせの場合に推奨されます。", "Input": "入力", "Input Key (e.g. text, unet_name, steps)": "入力キー", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "チャットのリッチテキスト入力", - "RK": "", "Role": "ロール", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index 6d6ebba9d0..77ebe19e4e 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -519,6 +519,7 @@ "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. en": "მაგ: en", "e.g. My Filter": "მაგ: ჩემი ფილტრი", "e.g. My Tools": "მაგ: ჩემი ხელსაწყოები", @@ -782,6 +783,7 @@ "File": "ფაილი", "File added successfully.": "ფაილი წარმატებით დაემატა.", "File content updated successfully.": "ფაილის შემცველობა წარმატებით განახლდა.", + "File Context": "", "File Mode": "ფაილის რეჟიმი", "File not found.": "ფაილი ნაპოვნი არაა.", "File removed successfully.": "ფაილი წარმატებით წაიშალა.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "შეყვანა", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "RK", "Role": "როლი", "Rosé Pine": "ვარდისფერი ფიჭვი", "Rosé Pine Dawn": "ვარდისფერი ფიჭვის გარიჟრაჟი", diff --git a/src/lib/i18n/locales/kab-DZ/translation.json b/src/lib/i18n/locales/kab-DZ/translation.json index 3365955ac2..494e3bdf07 100644 --- a/src/lib/i18n/locales/kab-DZ/translation.json +++ b/src/lib/i18n/locales/kab-DZ/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "amedya. 60", "e.g. A filter to remove profanity from text": "e.g. Imzizdig akken ad yekkes tukksa n sser seg uḍris", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "amedya kab", "e.g. My Filter": "amedya Imsizdeg-iw", "e.g. My Tools": "amedya ifecka-inu", @@ -782,6 +783,7 @@ "File": "Afaylu", "File added successfully.": "Afaylu yettwarna akken iwata.", "File content updated successfully.": "Agbur n ufaylu yettwaleqqem akken iwata.", + "File Context": "", "File Mode": "Askar n ufaylu", "File not found.": "Ur yettwaf ara ufaylu-nni.", "File removed successfully.": "Afaylu yettwakkes akken iwata.", @@ -937,6 +939,7 @@ "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": "Talɣut", "Initials": "Isekkilen imezwura", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "Anekcum", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "Yufa-d 1 n uɣbalu", "Rich Text Input for Chat": "Aḍris anesbaɣur", - "RK": "RK", "Role": "Tamlilt", "Rosé Pine": "Pin rosé", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 115921e3ed..229bef7304 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -519,6 +519,7 @@ "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. en": "예: en", "e.g. My Filter": "예: 내 필터", "e.g. My Tools": "예: 내 도구", @@ -782,6 +783,7 @@ "File": "파일", "File added successfully.": "파일이 성공적으로 추가되었습니다", "File content updated successfully.": "내용이 성공적으로 업데이트되었습니다", + "File Context": "", "File Mode": "파일 모드", "File not found.": "파일을 찾을 수 없습니다.", "File removed successfully.": "파일이 성공적으로 삭제되었습니다", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "전체 콘텐츠를 포괄적인 처리를 위해 컨텍스트로 삽입하세요. 이는 복잡한 쿼리에 권장됩니다.", "Input": "입력", "Input Key (e.g. text, unet_name, steps)": "", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "검색된 source 1개", "Rich Text Input for Chat": "다양한 텍스트 서식 사용", - "RK": "RK", "Role": "역할", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json index 901a032919..4de8c4cdb0 100644 --- a/src/lib/i18n/locales/lt-LT/translation.json +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "Rinkmena", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Rinkmenų rėžimas", "File not found.": "Failas nerastas.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "Informacija", "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)": "", @@ -1427,7 +1430,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Rolė", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ms-MY/translation.json b/src/lib/i18n/locales/ms-MY/translation.json index 5e0a0edfcd..b559447823 100644 --- a/src/lib/i18n/locales/ms-MY/translation.json +++ b/src/lib/i18n/locales/ms-MY/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "Fail", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Mod Fail", "File not found.": "Fail tidak dijumpai", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "Maklumat", "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)": "", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Peranan", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/nb-NO/translation.json b/src/lib/i18n/locales/nb-NO/translation.json index 9b8660244b..f997750a96 100644 --- a/src/lib/i18n/locales/nb-NO/translation.json +++ b/src/lib/i18n/locales/nb-NO/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "f.eks. 60", "e.g. A filter to remove profanity from text": "f.eks. et filter for å fjerne banning fra tekst", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "f.eks. Mitt filter", "e.g. My Tools": "f.eks. Mine verktøy", @@ -782,6 +783,7 @@ "File": "Fil", "File added successfully.": "Filen er lagt til.", "File content updated successfully.": "Filens innhold er oppdatert.", + "File Context": "", "File Mode": "Filmodus", "File not found.": "Finner ikke filen.", "File removed successfully.": "Filen er fjernet.", @@ -937,6 +939,7 @@ "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": "Info", "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)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Rik tekstinndata for chat", - "RK": "RK", "Role": "Rolle", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index 99af033bb1..a178e19c9f 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -519,6 +519,7 @@ "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. en": "", "e.g. My Filter": "bijv. Mijn filter", "e.g. My Tools": "bijv. Mijn gereedschappen", @@ -782,6 +783,7 @@ "File": "Bestand", "File added successfully.": "Bestand succesvol toegevoegd.", "File content updated successfully.": "Bestandsinhoud succesvol bijgewerkt.", + "File Context": "", "File Mode": "Bestandsmodus", "File not found.": "Bestand niet gevonden.", "File removed successfully.": "Bestand succesvol verwijderd.", @@ -937,6 +939,7 @@ "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": "", "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)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Rijke tekstinvoer voor chatten", - "RK": "RK", "Role": "Rol", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/pa-IN/translation.json b/src/lib/i18n/locales/pa-IN/translation.json index 24ca344728..41583cf061 100644 --- a/src/lib/i18n/locales/pa-IN/translation.json +++ b/src/lib/i18n/locales/pa-IN/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "ਫਾਈਲ ਮੋਡ", "File not found.": "ਫਾਈਲ ਨਹੀਂ ਮਿਲੀ।", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "ਭੂਮਿਕਾ", "Rosé Pine": "ਰੋਜ਼ ਪਾਈਨ", "Rosé Pine Dawn": "ਰੋਜ਼ ਪਾਈਨ ਡਾਨ", diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index 3c71be1cf5..f0fd30974c 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "np. 60", "e.g. A filter to remove profanity from text": "np. Filtr usuwający wulgaryzmy", "e.g. about the Roman Empire": "np. o Imperium Rzymskim", + "e.g. alloy, echo, shimmer": "", "e.g. en": "np. pl", "e.g. My Filter": "np. Mój Filtr", "e.g. My Tools": "np. Moje Narzędzia", @@ -782,6 +783,7 @@ "File": "Plik", "File added successfully.": "Plik dodany pomyślnie.", "File content updated successfully.": "Treść pliku zaktualizowana pomyślnie.", + "File Context": "", "File Mode": "Tryb pliku", "File not found.": "Plik nie znaleziony.", "File removed successfully.": "Plik usunięty pomyślnie.", @@ -937,6 +939,7 @@ "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.": "Wpływa na szybkość reakcji algorytmu na feedback. Niższy 'learning rate' to wolniejsze zmiany, wyższy to szybsza reakcja.", "Info": "Info", "Initials": "Inicjały", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Wstrzyknij całą treść jako kontekst (zalecane dla złożonych zapytań).", "Input": "Wejście", "Input Key (e.g. text, unet_name, steps)": "Klucz wejściowy (np. text, unet_name, steps)", @@ -1427,7 +1430,6 @@ "Retrieved {{count}} sources_other": "Pobrano {{count}} źródeł", "Retrieved 1 source": "Pobrano 1 źródło", "Rich Text Input for Chat": "Bogaty tekst w czacie", - "RK": "RK", "Role": "Rola", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index c361264998..fa137ec6d7 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "por exemplo, 60", "e.g. A filter to remove profanity from text": "Exemplo: Um filtro para remover palavrões do texto", "e.g. about the Roman Empire": "Por exemplo, sobre o Império Romano.", + "e.g. alloy, echo, shimmer": "", "e.g. en": "por exemplo, en", "e.g. My Filter": "Exemplo: Meu Filtro", "e.g. My Tools": "Exemplo: Minhas Ferramentas", @@ -782,6 +783,7 @@ "File": "Arquivo", "File added successfully.": "Arquivo adicionado com sucesso.", "File content updated successfully.": "Arquivo de conteúdo atualizado com sucesso.", + "File Context": "", "File Mode": "Modo de Arquivo", "File not found.": "Arquivo não encontrado.", "File removed successfully.": "Arquivo removido com sucesso.", @@ -937,6 +939,7 @@ "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.": "Influencia a rapidez com que o algoritmo responde ao feedback do texto gerado. Uma taxa de aprendizado menor resultará em ajustes mais lentos, enquanto uma taxa de aprendizado maior tornará o algoritmo mais responsivo.", "Info": "Informação", "Initials": "Iniciais", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injete todo o conteúdo como contexto para processamento abrangente; isso é recomendado para consultas complexas.", "Input": "Entrada", "Input Key (e.g. text, unet_name, steps)": "Chave de entrada (por exemplo, texto, unet_name, etapas)", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "1 fonte recuperada", "Rich Text Input for Chat": "Entrada de rich text para o chat", - "RK": "", "Role": "Função", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index 12794730fb..29e0e7047d 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Modo de Ficheiro", "File not found.": "Ficheiro não encontrado.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "Informação", "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)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Função", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ro-RO/translation.json b/src/lib/i18n/locales/ro-RO/translation.json index 7434edecd8..b108e398dd 100644 --- a/src/lib/i18n/locales/ro-RO/translation.json +++ b/src/lib/i18n/locales/ro-RO/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "Fișier", "File added successfully.": "Fișierul a fost adăugat cu succes.", "File content updated successfully.": "Conținutul fișierului a fost actualizat cu succes.", + "File Context": "", "File Mode": "Mod Fișier", "File not found.": "Fișierul nu a fost găsit.", "File removed successfully.": "Fișierul a fost eliminat cu succes.", @@ -937,6 +939,7 @@ "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": "Informații", "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)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Introducere text îmbogățit pentru chat", - "RK": "RK", "Role": "Rol", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index d8f4c95867..3c3596fb71 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -519,6 +519,7 @@ "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. en": "например, en", "e.g. My Filter": "например, мой фильтр", "e.g. My Tools": "например, мой инструмент", @@ -782,6 +783,7 @@ "File": "Файл", "File added successfully.": "Файл успешно добавлен.", "File content updated successfully.": "Содержимое файла успешно обновлено.", + "File Context": "", "File Mode": "Режим файла", "File not found.": "Файл не найден.", "File removed successfully.": "Файл успешно удален.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Использовать весь контент в качестве контекста для комплексной обработки, это рекомендуется для сложных запросов.", "Input": "Ввод", "Input Key (e.g. text, unet_name, steps)": "Введите ключ (например, text, unet_name, steps)", @@ -1427,7 +1430,6 @@ "Retrieved {{count}} sources_other": "Найдено {{count}} источников", "Retrieved 1 source": "Найден 1 источник", "Rich Text Input for Chat": "Ввод обогащённого текста (Rich text) в чат", - "RK": "RK", "Role": "Роль", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/sk-SK/translation.json b/src/lib/i18n/locales/sk-SK/translation.json index fda77c4f89..504fc32f80 100644 --- a/src/lib/i18n/locales/sk-SK/translation.json +++ b/src/lib/i18n/locales/sk-SK/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "Súbor", "File added successfully.": "Súbor bol úspešne pridaný.", "File content updated successfully.": "Obsah súboru bol úspešne aktualizovaný.", + "File Context": "", "File Mode": "Režim súboru", "File not found.": "Súbor nenájdený.", "File removed successfully.": "Súbor bol úspešne odstránený.", @@ -937,6 +939,7 @@ "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": "Info", "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)": "", @@ -1427,7 +1430,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Vstup pre chat vo formáte Rich Text", - "RK": "RK", "Role": "Funkcia", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/sr-RS/translation.json b/src/lib/i18n/locales/sr-RS/translation.json index c1063f479f..495d4daa10 100644 --- a/src/lib/i18n/locales/sr-RS/translation.json +++ b/src/lib/i18n/locales/sr-RS/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "Датотека", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "Режим датотеке", "File not found.": "Датотека није пронађена.", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1426,7 +1429,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Богат унос текста у ћаскању", - "RK": "", "Role": "Улога", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index 34bccc7c23..810ad46c92 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "t.ex. 60", "e.g. A filter to remove profanity from text": "t.ex. Ett filter för att ta bort svordomar från text", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "t.ex. en", "e.g. My Filter": "t.ex. Mitt filter", "e.g. My Tools": "t.ex. Mina verktyg", @@ -782,6 +783,7 @@ "File": "Fil", "File added successfully.": "Filen har lagts till.", "File content updated successfully.": "Filinnehållet har uppdaterats.", + "File Context": "", "File Mode": "Fil-läge", "File not found.": "Fil hittades inte.", "File removed successfully.": "Filen har tagits bort.", @@ -937,6 +939,7 @@ "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.": "Påverkar hur snabbt algoritmen svarar på feedback från den genererade texten. En lägre inlärningshastighet resulterar i långsammare justeringar, medan en högre inlärningshastighet gör algoritmen mer responsiv.", "Info": "Information", "Initials": "Initialer", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injicera hela innehållet som kontext för omfattande bearbetning, detta rekommenderas för komplexa frågor.", "Input": "Input", "Input Key (e.g. text, unet_name, steps)": "Inputnyckel (t.ex. text, unet_name, steps)", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "Hämtade från {{count}} källor", "Retrieved 1 source": "Hämtade från en källa", "Rich Text Input for Chat": "Rich Text-inmatning för chatt", - "RK": "RK", "Role": "Roll", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/th-TH/translation.json b/src/lib/i18n/locales/th-TH/translation.json index 0f1e88de14..96fdf940fb 100644 --- a/src/lib/i18n/locales/th-TH/translation.json +++ b/src/lib/i18n/locales/th-TH/translation.json @@ -519,6 +519,7 @@ "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. en": "เช่น en", "e.g. My Filter": "เช่น My Filter", "e.g. My Tools": "เช่น My Tools", @@ -782,6 +783,7 @@ "File": "ไฟล์", "File added successfully.": "เพิ่มไฟล์สำเร็จแล้ว", "File content updated successfully.": "อัปเดตเนื้อหาไฟล์สำเร็จแล้ว", + "File Context": "", "File Mode": "โหมดไฟล์", "File not found.": "ไม่พบไฟล์", "File removed successfully.": "ลบไฟล์สำเร็จแล้ว", @@ -937,6 +939,7 @@ "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.": "มีผลต่อความเร็วที่อัลกอริทึมตอบสนองต่อข้อเสนอแนะจากข้อความที่สร้างขึ้น ค่า Learning Rate ที่ต่ำจะทำให้การปรับเปลี่ยนช้าลง ในขณะที่ค่า Learning Rate ที่สูงจะทำให้อัลกอริทึมตอบสนองได้รวดเร็วขึ้น", "Info": "ข้อมูล", "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)": "คีย์อินพุต (เช่น text, unet_name, steps)", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "เรียกดูที่มา {{count}} รายการ (อื่นๆ)", "Retrieved 1 source": "ดึงมาแล้ว 1 แหล่งข้อมูล", "Rich Text Input for Chat": "ช่องป้อนข้อความแบบ Rich Text สำหรับแชท", - "RK": "RK", "Role": "บทบาท", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/tk-TM/translation.json b/src/lib/i18n/locales/tk-TM/translation.json index 32cdf8776f..5ce8725468 100644 --- a/src/lib/i18n/locales/tk-TM/translation.json +++ b/src/lib/i18n/locales/tk-TM/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "Faýl", "File added successfully.": "", "File content updated successfully.": "", + "File Context": "", "File Mode": "", "File not found.": "", "File removed successfully.": "", @@ -937,6 +939,7 @@ "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": "Maglumat", "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)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "", - "RK": "", "Role": "Roli", "Rosé Pine": "", "Rosé Pine Dawn": "", diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index ef6b70d923..1b2e3f67c4 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "örn. 60", "e.g. A filter to remove profanity from text": "örn. Metinden küfürleri kaldırmak için bir filtre", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "örn. Benim Filtrem", "e.g. My Tools": "örn. Benim Araçlarım", @@ -782,6 +783,7 @@ "File": "Dosya", "File added successfully.": "Dosya başarıyla eklendi.", "File content updated successfully.": "Dosya içeriği başarıyla güncellendi.", + "File Context": "", "File Mode": "Dosya Modu", "File not found.": "Dosya bulunamadı.", "File removed successfully.": "Dosya başarıyla kaldırıldı.", @@ -937,6 +939,7 @@ "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": "Bilgi", "Initials": "", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "Giriş", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Sohbet için Zengin Metin Girişi", - "RK": "RK", "Role": "Rol", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ug-CN/translation.json b/src/lib/i18n/locales/ug-CN/translation.json index c7120c2069..f25f88f063 100644 --- a/src/lib/i18n/locales/ug-CN/translation.json +++ b/src/lib/i18n/locales/ug-CN/translation.json @@ -519,6 +519,7 @@ "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. en": "مەسىلەن: en", "e.g. My Filter": "مەسىلەن: My Filter", "e.g. My Tools": "مەسىلەن: My Tools", @@ -782,6 +783,7 @@ "File": "ھۆججەت", "File added successfully.": "ھۆججەت مۇۋەپپەقىيەتلىك قوشۇلدى.", "File content updated successfully.": "ھۆججەت مەزمۇنى مۇۋەپپەقىيەتلىك يېڭىلاندى.", + "File Context": "", "File Mode": "ھۆججەت ھالىتى", "File not found.": "ھۆججەت تېپىلمىدى.", "File removed successfully.": "ھۆججەت مۇۋەپپەقىيەتلىك ئۆچۈرۈلدى.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "پۈتۈن مەزمۇننى مۇھىتقا قوشۇپ مول تەھلىل قىلىش، مۇرەككەپ سۇئاللار ئۈچۈن تەۋسىيە قىلىنىدۇ.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "سۆھبەت ئۈچۈن مول تېكست كىرگۈزۈش", - "RK": "RK", "Role": "رول", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/uk-UA/translation.json b/src/lib/i18n/locales/uk-UA/translation.json index 6fa3490470..cd863dc171 100644 --- a/src/lib/i18n/locales/uk-UA/translation.json +++ b/src/lib/i18n/locales/uk-UA/translation.json @@ -519,6 +519,7 @@ "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. en": "", "e.g. My Filter": "напр., Мій фільтр", "e.g. My Tools": "напр., Мої інструменти", @@ -782,6 +783,7 @@ "File": "Файл", "File added successfully.": "Файл успішно додано.", "File content updated successfully.": "Вміст файлу успішно оновлено.", + "File Context": "", "File Mode": "Файловий режим", "File not found.": "Файл не знайдено.", "File removed successfully.": "Файл успішно видалено.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Вставте весь вміст як контекст для всебічної обробки, це рекомендується для складних запитів.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1427,7 +1430,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Ввід тексту з форматуванням для чату", - "RK": "RK", "Role": "Роль", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/ur-PK/translation.json b/src/lib/i18n/locales/ur-PK/translation.json index 3ab7679b0d..ec058985a3 100644 --- a/src/lib/i18n/locales/ur-PK/translation.json +++ b/src/lib/i18n/locales/ur-PK/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "", "e.g. A filter to remove profanity from text": "", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "", "e.g. My Tools": "", @@ -782,6 +783,7 @@ "File": "فائل", "File added successfully.": "فائل کامیابی سے شامل ہو گئی", "File content updated successfully.": "فائل مواد کامیابی سے اپ ڈیٹ ہو گیا", + "File Context": "", "File Mode": "فائل موڈ", "File not found.": "فائل نہیں ملی", "File removed successfully.": "فائل کامیابی سے ہٹا دی گئی", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "چیٹ کے لیے رچ ٹیکسٹ ان پٹ", - "RK": "آر کے", "Role": "کردار", "Rosé Pine": "روزے پائن", "Rosé Pine Dawn": "روزے پائن ڈان", diff --git a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json index c984995705..3803fb924c 100644 --- a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json +++ b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json @@ -519,6 +519,7 @@ "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. en": "масалан, en", "e.g. My Filter": "масалан, Менинг филтрим", "e.g. My Tools": "масалан, Менинг асбобларим", @@ -782,6 +783,7 @@ "File": "Файл", "File added successfully.": "Файл муваффақиятли қўшилди.", "File content updated successfully.": "Файл мазмуни муваффақиятли янгиланди.", + "File Context": "", "File Mode": "Файл режими", "File not found.": "Файл топилмади.", "File removed successfully.": "Файл муваффақиятли олиб ташланди.", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Комплекс қайта ишлаш учун бутун таркибни контекст сифатида киритинг, бу мураккаб сўровлар учун тавсия этилади.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Чат учун бой матн киритиш", - "RK": "RK", "Role": "Рол", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/uz-Latn-Uz/translation.json b/src/lib/i18n/locales/uz-Latn-Uz/translation.json index 7719e61d88..a7c86a92b3 100644 --- a/src/lib/i18n/locales/uz-Latn-Uz/translation.json +++ b/src/lib/i18n/locales/uz-Latn-Uz/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "masalan. 60", "e.g. A filter to remove profanity from text": "masalan. Matndan haqoratli so'zlarni olib tashlash uchun filtr", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "masalan. uz", "e.g. My Filter": "masalan. Mening filtrim", "e.g. My Tools": "masalan. Mening asboblarim", @@ -782,6 +783,7 @@ "File": "Fayl", "File added successfully.": "Fayl muvaffaqiyatli qo'shildi.", "File content updated successfully.": "Fayl mazmuni muvaffaqiyatli yangilandi.", + "File Context": "", "File Mode": "Fayl rejimi", "File not found.": "Fayl topilmadi.", "File removed successfully.": "Fayl muvaffaqiyatli olib tashlandi.", @@ -937,6 +939,7 @@ "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.": "Algoritm yaratilgan matndan olingan fikr-mulohazaga qanchalik tez javob berishiga ta'sir qiladi. Pastroq o'rganish tezligi sozlashning sekinlashishiga olib keladi, yuqori o'rganish tezligi esa algoritmni yanada sezgir qiladi.", "Info": "Ma'lumot", "Initials": "", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Kompleks qayta ishlash uchun butun tarkibni kontekst sifatida kiriting, bu murakkab so'rovlar uchun tavsiya etiladi.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1425,7 +1428,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Chat uchun boy matn kiritish", - "RK": "RK", "Role": "Rol", "Rosé Pine": "Roze qarag'ay", "Rosé Pine Dawn": "Atirgul qarag'ay tong", diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index 7d2c83d123..bf7e675bf8 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -519,6 +519,7 @@ "e.g. 60": "vd: 60", "e.g. A filter to remove profanity from text": "vd: Bộ lọc để loại bỏ từ ngữ tục tĩu khỏi văn bản", "e.g. about the Roman Empire": "", + "e.g. alloy, echo, shimmer": "", "e.g. en": "", "e.g. My Filter": "vd: Bộ lọc của tôi", "e.g. My Tools": "vd: Công cụ của tôi", @@ -782,6 +783,7 @@ "File": "Tệp", "File added successfully.": "Thêm tệp thành công.", "File content updated successfully.": "Nội dung tệp được cập nhật thành công.", + "File Context": "", "File Mode": "Chế độ Tệp văn bản", "File not found.": "Không tìm thấy tệp.", "File removed successfully.": "Xóa tệp thành công.", @@ -937,6 +939,7 @@ "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.": "Ảnh hưởng đến tốc độ thuật toán phản hồi lại phản hồi từ văn bản được tạo. Tốc độ học thấp hơn sẽ dẫn đến các điều chỉnh chậm hơn, trong khi tốc độ học cao hơn sẽ làm cho thuật toán phản ứng nhanh hơn.", "Info": "Thông tin", "Initials": "", + "Inject file content into conversation context": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Đưa toàn bộ nội dung vào làm ngữ cảnh để xử lý toàn diện, điều này được khuyến nghị cho các truy vấn phức tạp.", "Input": "", "Input Key (e.g. text, unet_name, steps)": "", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "", "Retrieved 1 source": "", "Rich Text Input for Chat": "Nhập Văn bản Đa dạng cho Chat", - "RK": "RK", "Role": "Vai trò", "Rosé Pine": "Rosé Pine", "Rosé Pine Dawn": "Rosé Pine Dawn", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index 9a6341c89b..bb13c6b6e0 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -519,6 +519,7 @@ "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. en": "例如:en", "e.g. My Filter": "例如:我的过滤器", "e.g. My Tools": "例如:我的工具", @@ -782,6 +783,7 @@ "File": "文件", "File added successfully.": "文件成功添加", "File content updated successfully.": "文件内容成功更新", + "File Context": "", "File Mode": "文件模式", "File not found.": "文件未找到。", "File removed successfully.": "文件成功删除", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "注入整个内容作为上下文进行综合处理,适用于复杂查询", "Input": "输入", "Input Key (e.g. text, unet_name, steps)": "输入键名(例如:text, unet_name, steps)", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "检索到 {{count}} 个引用来源", "Retrieved 1 source": "检索到 1 个引用来源", "Rich Text Input for Chat": "富文本对话框", - "RK": "排名", "Role": "角色", "Rosé Pine": "玫瑰松木", "Rosé Pine Dawn": "玫瑰松木·晨曦", diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index 8cbdc55679..912c17e46e 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -519,6 +519,7 @@ "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. en": "例如:en", "e.g. My Filter": "例如:我的篩選器", "e.g. My Tools": "例如:我的工具", @@ -782,6 +783,7 @@ "File": "檔案", "File added successfully.": "成功新增檔案。", "File content updated successfully.": "成功更新檔案內容。", + "File Context": "", "File Mode": "檔案模式", "File not found.": "未找到檔案。", "File removed successfully.": "成功移除檔案。", @@ -937,6 +939,7 @@ "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": "", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "將完整內容注入為上下文以進行全面處理,建議用於複雜查詢。", "Input": "輸入", "Input Key (e.g. text, unet_name, steps)": "輸入鍵名(例如:text, unet_name, steps)", @@ -1424,7 +1427,6 @@ "Retrieved {{count}} sources_other": "搜索到 {{count}} 個來源", "Retrieved 1 source": "搜索到 1 個來源", "Rich Text Input for Chat": "使用富文字輸入對話", - "RK": "RK", "Role": "角色", "Rosé Pine": "玫瑰松", "Rosé Pine Dawn": "黎明玫瑰松", diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte index 660a7b3a72..9de2d8dce5 100644 --- a/src/routes/auth/+page.svelte +++ b/src/routes/auth/+page.svelte @@ -9,7 +9,13 @@ import { page } from '$app/stores'; import { getBackendConfig } from '$lib/apis'; - import { ldapUserSignIn, getSessionUser, userSignIn, userSignUp, updateUserTimezone } from '$lib/apis/auths'; + import { + ldapUserSignIn, + getSessionUser, + userSignIn, + userSignUp, + updateUserTimezone + } from '$lib/apis/auths'; import { WEBUI_API_BASE_URL, WEBUI_BASE_URL } from '$lib/constants'; import { WEBUI_NAME, config, user, socket } from '$lib/stores'; From 9496e8f7b5ff64a93167f928a9f49bf752b08880 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 20:19:51 +0400 Subject: [PATCH 207/254] feat: model evaluation activity chart --- backend/open_webui/models/feedbacks.py | 78 +++++++ backend/open_webui/routers/evaluations.py | 18 ++ src/lib/apis/evaluations/index.ts | 38 ++++ .../admin/Evaluations/LeaderboardModal.svelte | 83 +++++++- .../Evaluations/ModelActivityChart.svelte | 195 ++++++++++++++++++ 5 files changed, 407 insertions(+), 5 deletions(-) create mode 100644 src/lib/components/admin/Evaluations/ModelActivityChart.svelte diff --git a/backend/open_webui/models/feedbacks.py b/backend/open_webui/models/feedbacks.py index 1e807ac8d9..66037e4865 100644 --- a/backend/open_webui/models/feedbacks.py +++ b/backend/open_webui/models/feedbacks.py @@ -127,6 +127,17 @@ class FeedbackListResponse(BaseModel): total: int +class ModelHistoryEntry(BaseModel): + date: str + won: int + lost: int + + +class ModelHistoryResponse(BaseModel): + model_id: str + history: list[ModelHistoryEntry] + + class FeedbackTable: def insert_new_feedback( self, user_id: str, form_data: FeedbackForm, db: Optional[Session] = None @@ -288,6 +299,73 @@ class FeedbackTable: for row in db.query(Feedback.id, Feedback.data).all() ] + def get_model_evaluation_history( + self, model_id: str, days: int = 30, db: Optional[Session] = None + ) -> list[ModelHistoryEntry]: + """ + Get daily wins/losses for a specific model over the past N days. + If days=0, returns all time data starting from first feedback. + Returns: [{"date": "2026-01-08", "won": 5, "lost": 2}, ...] + """ + from datetime import datetime, timedelta + from collections import defaultdict + + with get_db_context(db) as db: + if days == 0: + # All time - no cutoff + rows = db.query(Feedback.created_at, Feedback.data).all() + else: + cutoff = int(time.time()) - (days * 86400) + rows = ( + db.query(Feedback.created_at, Feedback.data) + .filter(Feedback.created_at >= cutoff) + .all() + ) + + daily_counts = defaultdict(lambda: {"won": 0, "lost": 0}) + first_date = None + + for created_at, data in rows: + if not data: + continue + if data.get("model_id") != model_id: + continue + + rating_str = str(data.get("rating", "")) + if rating_str not in ("1", "-1"): + continue + + date_str = datetime.fromtimestamp(created_at).strftime("%Y-%m-%d") + if rating_str == "1": + daily_counts[date_str]["won"] += 1 + else: + daily_counts[date_str]["lost"] += 1 + + # Track first date for this model + if first_date is None or date_str < first_date: + first_date = date_str + + # Generate date range + result = [] + today = datetime.now().date() + + if days == 0 and first_date: + # All time: start from first feedback date + start_date = datetime.strptime(first_date, "%Y-%m-%d").date() + num_days = (today - start_date).days + 1 + else: + # Fixed range + num_days = days + start_date = today - timedelta(days=days - 1) + + for i in range(num_days): + d = start_date + timedelta(days=i) + date_str = d.strftime("%Y-%m-%d") + counts = daily_counts.get(date_str, {"won": 0, "lost": 0}) + result.append(ModelHistoryEntry(date=date_str, won=counts["won"], lost=counts["lost"])) + + return result + def get_feedbacks_by_type( self, type: str, db: Optional[Session] = None ) -> list[FeedbackModel]: diff --git a/backend/open_webui/routers/evaluations.py b/backend/open_webui/routers/evaluations.py index 86fe022241..3beea54f39 100644 --- a/backend/open_webui/routers/evaluations.py +++ b/backend/open_webui/routers/evaluations.py @@ -13,6 +13,8 @@ from open_webui.models.feedbacks import ( FeedbackUserResponse, FeedbackListResponse, LeaderboardFeedbackData, + ModelHistoryEntry, + ModelHistoryResponse, Feedbacks, ) @@ -254,6 +256,22 @@ async def get_leaderboard( return LeaderboardResponse(entries=entries) + + +@router.get("/leaderboard/{model_id}/history", response_model=ModelHistoryResponse) +async def get_model_history( + model_id: str, + days: int = 30, + user=Depends(get_admin_user), + db: Session = Depends(get_session), +): + """Get daily win/loss history for a specific model.""" + history = Feedbacks.get_model_evaluation_history( + model_id=model_id, days=days, db=db + ) + return ModelHistoryResponse(model_id=model_id, history=history) + + ############################ # GetConfig ############################ diff --git a/src/lib/apis/evaluations/index.ts b/src/lib/apis/evaluations/index.ts index 315315fb03..318e766e50 100644 --- a/src/lib/apis/evaluations/index.ts +++ b/src/lib/apis/evaluations/index.ts @@ -127,6 +127,44 @@ export const getLeaderboard = async (token: string = '', query: string = '') => return res; }; +export const getModelHistory = async ( + token: string = '', + modelId: string, + days: number = 30 +) => { + let error = null; + + const searchParams = new URLSearchParams(); + searchParams.append('days', days.toString()); + + const res = await fetch( + `${WEBUI_API_BASE_URL}/evaluations/leaderboard/${encodeURIComponent(modelId)}/history?${searchParams.toString()}`, + { + method: 'GET', + 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; +}; + export const getFeedbackItems = async (token: string = '', orderBy, direction, page) => { let error = null; diff --git a/src/lib/components/admin/Evaluations/LeaderboardModal.svelte b/src/lib/components/admin/Evaluations/LeaderboardModal.svelte index 0b82f9a6fc..2a19fd6af1 100644 --- a/src/lib/components/admin/Evaluations/LeaderboardModal.svelte +++ b/src/lib/components/admin/Evaluations/LeaderboardModal.svelte @@ -1,22 +1,63 @@ - + {#if model}
@@ -27,9 +68,40 @@
-
+ +
+
+
+ {$i18n.t('Activity')} +
+
+ {#each TIME_RANGES as range} + + {/each} +
+
+ +
+ +
+
+ {$i18n.t('Tags')} +
{#if topTags.length} -
+
{#each topTags as tagInfo} {tagInfo.tag} {tagInfo.count} @@ -37,9 +109,10 @@ {/each}
{:else} - - + - {/if}
+
- {#if total > 0 && $config?.features?.enable_community_sharing} -
-
- {$i18n.t('Help us create the best community leaderboard by sharing your feedback history!')} -
- -
- - - -
-
- {/if} - {#if total > 30} {/if} From 592a6213b9981883755dcf8b16c9f952b4d350c8 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 21:00:30 +0400 Subject: [PATCH 211/254] doc: changelog --- CHANGELOG.md | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f3e60909..0ddf463f29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,24 +5,23 @@ 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.7] - 2026-01-09 +## [0.7.0] - 2026-01-09 ### Added -- 🤖 When configured for agentic mode, AI models independently research topics by searching the web multiple times, fetching and analyzing web pages, managing their own memory, and generating images without waiting for user prompts, transforming conversations from simple Q&A into dynamic research sessions where the AI proactively investigates and synthesizes information across multiple sources. [#19397](https://github.com/open-webui/open-webui/issues/19397), [Commit](https://github.com/open-webui/open-webui/commit/5c1d52231a3997a17381c48639bd7e339262cf7c) -- 🧠 Models in agentic mode autonomously search through your notes, past conversations, channels, and messages to find relevant context, calculate timestamps for temporal queries, and access your complete communication history without explicit commands, turning AI into a self-sufficient research assistant that knows when and where to look for information. [Commit](https://github.com/open-webui/open-webui/commit/646835d76744ad9b2e67ede0407a61d62e969aab) -- 📚 Models in agentic mode proactively list accessible knowledge bases, search files by name, retrieve full document contents, and perform semantic vector searches across your entire knowledge repository to find relevant information autonomously, eliminating the need to manually specify which documents to reference. [Commit](https://github.com/open-webui/open-webui/commit/c8622adcb01f3091b17ca50f8c8e2f20c7b9cd2a) -- 💭 Models with interleaved thinking support can now reason and reflect between tool calls, analyzing search results before deciding what to search for next, leading to dramatically more focused and effective multi-step research as the AI refines its strategy based on what it learns. -- 🔍 When AI models autonomously search the web in agentic mode, users see every search result as clickable citations in real-time, making the AI's research process completely transparent and allowing full verification of sources even when the model initiates searches independently. [Commit](https://github.com/open-webui/open-webui/commit/2789f6a24d8405c30cd48ae460071f6a4f2c35f9) -- 📖 When AI models autonomously query knowledge bases in agentic mode, every retrieved file and content chunk appears as grouped, clickable citations showing exactly which documents informed the response, with sources automatically organized by origin for easy verification. [#20380](https://github.com/open-webui/open-webui/pull/20380), [Commit](https://github.com/open-webui/open-webui/commit/ab400e3eae569a5e09fe391d4b4bab104423bb0b) -- 🎚️ Users can now selectively disable built-in agentic tools for individual models through the model editor's capabilities settings, allowing precise control over which models can autonomously access timestamps, memory, chat history, notes, web search, and knowledge bases. [Commit](https://github.com/open-webui/open-webui/commit/60e916d6c0c5f7db9e6d670e12be2d1d4abc2dd6) -- 👁️ Users now see exactly which agentic tools are being invoked as AI models work, with pending tool calls displayed during response generation so it's always clear the system is actively researching rather than frozen or stuck. [Commit](https://github.com/open-webui/open-webui/commit/1d08376860e775049abd1dd5f568ac0c6466c944) +- 🤖 **Native Function Calling with Built-in Tools.** Models with native function calling support can now use a suite of built-in tools when function calling mode is set to "Native" in Chat Controls—including web search, web page fetching, memory management, and image generation—enabling multi-step research workflows where the model autonomously decides which tools to invoke. [#19397](https://github.com/open-webui/open-webui/issues/19397), [Commit](https://github.com/open-webui/open-webui/commit/5c1d52231a3997a17381c48639bd7e339262cf7c) +- 🧠 Built-in tools for native function calling now include access to notes, past conversations, channels, and messages, allowing models to search your communication history and retrieve relevant context when needed. [Commit](https://github.com/open-webui/open-webui/commit/646835d76744ad9b2e67ede0407a61d62e969aab) +- 📚 Built-in tools for native function calling now include knowledge base access—models can list available knowledge bases, search files by name, retrieve document contents, and perform semantic vector searches without requiring you to manually attach files. [Commit](https://github.com/open-webui/open-webui/commit/c8622adcb01f3091b17ca50f8c8e2f20c7b9cd2a) +- 💭 Users with models that support interleaved thinking now get more refined results from native function calling workflows with built-in tools, as the model can analyze each tool's output before deciding what to do next instead of executing all tools blindly. +- 🔍 When models invoke web search via native function calling, search results appear as clickable citations in real-time for full source verification. [Commit](https://github.com/open-webui/open-webui/commit/2789f6a24d8405c30cd48ae460071f6a4f2c35f9) +- 🎚️ Users can selectively disable specific built-in tools (timestamps, memory, chat history, notes, web search, knowledge bases) per model via the model editor's capabilities settings. [Commit](https://github.com/open-webui/open-webui/commit/60e916d6c0c5f7db9e6d670e12be2d1d4abc2dd6) +- 👁️ Pending tool calls are now displayed during response generation, showing which tools are being invoked so users know the system is working. [Commit](https://github.com/open-webui/open-webui/commit/1d08376860e775049abd1dd5f568ac0c6466c944) +- 📁 Administrators can now limit the number of files that can be uploaded to folders using the "FOLDER_MAX_FILE_COUNT" setting, preventing resource exhaustion from bulk uploads. [#19810](https://github.com/open-webui/open-webui/issues/19810), [Commit](https://github.com/open-webui/open-webui/commit/a1036e544d573e3d35e05c1c2472ba762c32431b), [Commit](https://github.com/open-webui/open-webui/commit/d3ee3fd23e762c9d83fe1da5636d03259e186e57) - ⚡ Users experience transformative speed improvements across the entire application through completely reengineered database connection handling, delivering noticeably faster page loads, butter-smooth interactions, and rock-solid stability during intensive operations like user management and bulk data processing. [Commit](https://github.com/open-webui/open-webui/commit/2041ab483e21b3a757baa25c47dc2fa29018674f), [Commit](https://github.com/open-webui/open-webui/commit/145c7516f227ce56fd52373cee86217fadf16181), [Commit](https://github.com/open-webui/open-webui/commit/475dd91ed798f2efcdf27799d5c5cae3f0e6e847), [Commit](https://github.com/open-webui/open-webui/commit/5d1459df166cce8445eb1556cc26abbd65a3f9f4), [Commit](https://github.com/open-webui/open-webui/commit/2453b75ff0fb2dc75b929d96f417d84e332922d9), [Commit](https://github.com/open-webui/open-webui/commit/5649a668fad15393a52c27a2f188841af8b66989) - 🚀 Users experience significantly faster initial page load times through dynamic loading of document processing libraries, reducing the initial bundle size. [#20200](https://github.com/open-webui/open-webui/pull/20200), [#20202](https://github.com/open-webui/open-webui/pull/20202), [#20203](https://github.com/open-webui/open-webui/pull/20203), [#20204](https://github.com/open-webui/open-webui/pull/20204) - 💨 Administrators experience dramatically faster user list loading through optimized database queries that eliminate N+1 query patterns, reducing query count from 1+N to just 2 total queries regardless of user count. [#20427](https://github.com/open-webui/open-webui/pull/20427) - 📋 Notes now load faster through optimized database queries that batch user lookups instead of fetching each note's author individually. [Commit](https://github.com/open-webui/open-webui/commit/084f0ef6a5491e186bf6b71c6386973ba18ef2fa) - 💬 Channel messages, pinned messages, and thread replies now load faster through batched user lookups instead of individual queries per message. [#20458](https://github.com/open-webui/open-webui/pull/20458), [#20459](https://github.com/open-webui/open-webui/pull/20459), [#20460](https://github.com/open-webui/open-webui/pull/20460) -- 📊 Users can now sync their chat statistics to create public profile pages on the Open WebUI Community website or download them as JSON files, with incremental synchronization by default and an administrator option to disable the feature. [Commit](https://github.com/open-webui/open-webui/commit/4be99174be505b187812e0b48b9f9f7bf6897c52), [Commit](https://github.com/open-webui/open-webui/commit/df106099a159f8cf7910a89c50338ec045a78e61), [Commit](https://github.com/open-webui/open-webui/commit/9c61e95ecba071f5a99d93d1b1c5d17b80159329), [Commit](https://github.com/open-webui/open-webui/commit/85bbed3ec539dc958d306117f97d6be977b7253b), [Commit](https://github.com/open-webui/open-webui/commit/459cfde1f80e76618fb7fb75318d8daf2ccf1590), [Commit](https://github.com/open-webui/open-webui/commit/37b15604de0eaa5bfde378f12ac2d94c7aab60b9), [Commit](https://github.com/open-webui/open-webui/commit/71ca25c8ac4ad97b5a52016a5b2f385b333bd480) - 🔗 Users can now click citation content links to jump directly to the relevant portion of source documents with automatic text highlighting, making it easier to verify AI responses against their original sources. [#20116](https://github.com/open-webui/open-webui/pull/20116), [Commit](https://github.com/open-webui/open-webui/commit/40c45ffe1f9b45538d32c8ecba8cac62c6eca503) - 📌 Users can now pin or hide models directly from the Workspace Models page and Admin Settings Models page, making it easier to manage which models appear in the sidebar without switching to the chat interface. [#20176](https://github.com/open-webui/open-webui/pull/20176) - 🔎 Administrators can now quickly find settings using the new search bar in the Admin Settings sidebar, which supports fuzzy filtering by category names and related keywords like "whisper" for Audio or "rag" for Documents. [#20434](https://github.com/open-webui/open-webui/pull/20434) @@ -31,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🔧 Users can now view read-only tools in the workspace tools list, with clear "Read Only" badges indicating when editing is restricted. [#20243](https://github.com/open-webui/open-webui/issues/20243), [#20370](https://github.com/open-webui/open-webui/pull/20370) - 📂 Searching for files is now significantly faster, especially for users with large file collections. [Commit](https://github.com/open-webui/open-webui/commit/a9a979fb3db1743553ca0705f571c0b9c252841f) - 🏆 The Evaluations leaderboard now calculates Elo ratings on the backend instead of in the browser, improving performance and enabling topic-based model ranking through semantic search. [#15392](https://github.com/open-webui/open-webui/pull/15392), [#20476](https://github.com/open-webui/open-webui/issues/20476), [Commit](https://github.com/open-webui/open-webui/commit/10838b3654bf6fdef02d57311f7f1c01df4cd033) +- 📊 The Evaluations leaderboard now includes a per-model activity chart displaying daily wins and losses as a diverging bar chart, with 30-day, 1-year, and all-time views using weekly aggregation for longer timeframes. - 🎞️ Users can now upload animated GIF and WebP formats as model profile images, with animation preserved by skipping resize processing for these file types. [Commit](https://github.com/open-webui/open-webui/commit/00af37bb4ed1ea0957c7c84a6a8def3a7998b8ca) - 📸 Users uploading profile images for users, models, and arena models now benefit from WebP compression at 80% quality instead of JPEG, resulting in significantly smaller file sizes and faster uploads while maintaining visual quality. [Commit](https://github.com/open-webui/open-webui/commit/b1d30673b69571e081abb881d34944cf33cdc67e) - ⭐ Action Function developers can now update message favorite status using the new "chat:message:favorite" event, enabling the development of pin/unpin message actions without race conditions from frontend auto-save. [#20375](https://github.com/open-webui/open-webui/pull/20375) @@ -41,7 +41,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🧩 Administrators can now set a minimum chunk size target using the "CHUNK_MIN_SIZE_TARGET" setting to merge small markdown header chunks with neighbors, which improves retrieval quality by eliminating tiny meaningless fragments, significantly speeds up document processing and embedding, reduces storage costs, and lowers embedding API costs or local compute requirements. [#19595](https://github.com/open-webui/open-webui/issues/19595), [#20314](https://github.com/open-webui/open-webui/pull/20314), [Commit](https://github.com/open-webui/open-webui/commit/c32435958073cf002d87e78544baa88bc4e15d7f) - 💨 Administrators can now enable KV prefix caching optimization by setting "RAG_SYSTEM_CONTEXT" to true, which injects RAG context into the system message instead of user messages, enabling models to reuse cached tokens for follow-up questions instead of reprocessing the entire context on each turn, significantly improving response times and reducing costs for cloud-based models. [#20301](https://github.com/open-webui/open-webui/discussions/20301), [#20317](https://github.com/open-webui/open-webui/pull/20317) - 🖼️ Administrators and Action developers can now control image generation denoising steps per-request using a steps parameter, allowing Actions and API calls to override the global IMAGE_STEPS configuration for both ComfyUI and Automatic1111 engines. [#20337](https://github.com/open-webui/open-webui/pull/20337) -- 📁 Administrators can now limit the number of files that can be uploaded to folders using the "FOLDER_MAX_FILE_COUNT" setting, preventing resource exhaustion from bulk uploads. [#19810](https://github.com/open-webui/open-webui/issues/19810), [Commit](https://github.com/open-webui/open-webui/commit/a1036e544d573e3d35e05c1c2472ba762c32431b), [Commit](https://github.com/open-webui/open-webui/commit/d3ee3fd23e762c9d83fe1da5636d03259e186e57) - 🗄️ Administrators running multi-pod deployments can now designate a master pod to handle database migrations using the "ENABLE_DB_MIGRATIONS" environment variable. [Commit](https://github.com/open-webui/open-webui/commit/9824f0e33359a917ac07b60bf1f972074d5c8203) - 🎙️ Administrators can now configure Whisper's compute type using the "WHISPER_COMPUTE_TYPE" environment variable to fix compatibility issues with CUDA/GPU deployments. [Commit](https://github.com/open-webui/open-webui/commit/26af1f92e21ddfd08348570bf54a6f345ac69648) - 🔍 Administrators can now control sigmoid normalization for CrossEncoder reranking models using the "SENTENCE_TRANSFORMERS_CROSS_ENCODER_SIGMOID_ACTIVATION_FUNCTION" environment variable, enabled by default for proper relevance threshold behavior with MS MARCO models. [#20228](https://github.com/open-webui/open-webui/pull/20228) @@ -53,7 +52,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🪝 Channel managers can now create webhooks to allow external services to post messages to channels without authentication. [Commit](https://github.com/open-webui/open-webui/commit/cd296fcf0d79cecd1a6a3ee4e492c6b5246ca7ae) - 📄 In the model editor users can now disable the "File Context" capability to skip automatic file content extraction and injection, forwarding raw messages with file attachment metadata instead for use with custom tools or future built-in file access tools. [Commit](https://github.com/open-webui/open-webui/commit/daccf0713e3ecd6d24f003a87b5f8b3c61852958), [Docs:Commit](https://github.com/open-webui/docs/commit/18ec6eaefc071a278ec57d4d1b8d66d686af0870) - 🔊 In the model editor users can now configure a specific TTS voice for each model, overriding user preferences and global defaults to give different AI personas distinct voices. [#3097](https://github.com/open-webui/open-webui/issues/3097), [Commit](https://github.com/open-webui/open-webui/commit/bb6188abf04302f79d80b0d6cc42c232624b5757) -- 🕐 User timezones are now automatically detected and stored on login, enabling accurate timestamp handling for time-sensitive features. [Commit](https://github.com/open-webui/open-webui/commit/401c1949a04dfd1bcc3c8b9a4f77b73beb78b818) - 👥 Administrators now have three granular group sharing permission options instead of a simple on/off toggle, allowing them to choose between "No one", "Members", or "Anyone" for who can share content to each group. [Commit](https://github.com/open-webui/open-webui/commit/ca514cd3eda2524b8da472ef17c0ccb216bac2e8) - 📦 Administrators can now export knowledge bases as zip files containing text files for backup and archival purposes. [#20120](https://github.com/open-webui/open-webui/issues/20120), [Commit](https://github.com/open-webui/open-webui/commit/c1147578c073a8c7fa7e7f836149e1cdfec8f18d) - 🚀 Administrators can now create an admin account automatically at startup via "WEBUI_ADMIN_EMAIL", "WEBUI_ADMIN_PASSWORD", and "WEBUI_ADMIN_NAME" environment variables, enabling headless and automated deployments without exposing the signup page. [#17654](https://github.com/open-webui/open-webui/issues/17654), [Commit](https://github.com/open-webui/open-webui/commit/1138929f4d083931305f1f925899971b190562ae) @@ -62,6 +60,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - 🔥 Administrators can now configure Firecrawl timeout values using the "FIRECRAWL_TIMEOUT" environment variable to control web scraping wait times. [#19973](https://github.com/open-webui/open-webui/pull/19973), [Commit](https://github.com/open-webui/open-webui/commit/89ad1c68d1aadf849960b5e202aa4651096b05f5) - 💾 Administrators can now use openGauss as the vector database backend for knowledge base document storage and retrieval. [#20179](https://github.com/open-webui/open-webui/pull/20179) - 🔄 Various improvements were implemented across the application to enhance performance, stability, and security. +- 📊 Users can now sync their anonymous usage statistics to the Open WebUI Community platform to power community leaderboards, drive model evaluations, and contribute to open-source AI research that benefits everyone, all while keeping conversations completely private (only metadata like model names, message counts, and ratings are shared). By sharing your stats, you're helping the community identify which models perform best, contributing to transparent AI benchmarking, and supporting the collective effort to make AI better for all. You can also download your stats as JSON for personal analysis. - 🌐 Translations for German, Portuguese (Brazil), Spanish, Simplified Chinese, Traditional Chinese, and Polish were enhanced and expanded. ### Fixed From 7bb11f9ef076791b6f8bf215ceae461208b0b662 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 21:05:37 +0400 Subject: [PATCH 212/254] refac: wording --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ddf463f29..0fdcde5afb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,13 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- 🤖 **Native Function Calling with Built-in Tools.** Models with native function calling support can now use a suite of built-in tools when function calling mode is set to "Native" in Chat Controls—including web search, web page fetching, memory management, and image generation—enabling multi-step research workflows where the model autonomously decides which tools to invoke. [#19397](https://github.com/open-webui/open-webui/issues/19397), [Commit](https://github.com/open-webui/open-webui/commit/5c1d52231a3997a17381c48639bd7e339262cf7c) -- 🧠 Built-in tools for native function calling now include access to notes, past conversations, channels, and messages, allowing models to search your communication history and retrieve relevant context when needed. [Commit](https://github.com/open-webui/open-webui/commit/646835d76744ad9b2e67ede0407a61d62e969aab) -- 📚 Built-in tools for native function calling now include knowledge base access—models can list available knowledge bases, search files by name, retrieve document contents, and perform semantic vector searches without requiring you to manually attach files. [Commit](https://github.com/open-webui/open-webui/commit/c8622adcb01f3091b17ca50f8c8e2f20c7b9cd2a) -- 💭 Users with models that support interleaved thinking now get more refined results from native function calling workflows with built-in tools, as the model can analyze each tool's output before deciding what to do next instead of executing all tools blindly. -- 🔍 When models invoke web search via native function calling, search results appear as clickable citations in real-time for full source verification. [Commit](https://github.com/open-webui/open-webui/commit/2789f6a24d8405c30cd48ae460071f6a4f2c35f9) +- 🤖 **Native Function Calling with Built-in Tools.** Users can now ask models to perform multi-step tasks that combine web research, knowledge base queries, note-taking, and image generation in a single conversation—for example, "research the latest on X, save key findings to a note, and generate an infographic." Requires models with native function calling support and function calling mode set to "Native" in Chat Controls. [#19397](https://github.com/open-webui/open-webui/issues/19397), [Commit](https://github.com/open-webui/open-webui/commit/5c1d52231a3997a17381c48639bd7e339262cf7c) +- 🧠 Users can now ask the model to find relevant context from their notes, past chats, and channel messages—for example, "what did I discuss about project X last week?" or "find the conversation where I brainstormed ideas for Y." [Commit](https://github.com/open-webui/open-webui/commit/646835d76744ad9b2e67ede0407a61d62e969aab) +- 📚 Users can now ask the model to search their knowledge bases and retrieve documents without manually attaching files—for example, "find the section about authentication in our API docs" or "what do our internal guidelines say about X?" [Commit](https://github.com/open-webui/open-webui/commit/c8622adcb01f3091b17ca50f8c8e2f20c7b9cd2a) +- 💭 Users with models that support interleaved thinking now get more refined results from multi-step workflows, as the model can analyze each tool's output before deciding what to do next. +- 🔍 When models invoke web search, search results appear as clickable citations in real-time for full source verification. [Commit](https://github.com/open-webui/open-webui/commit/2789f6a24d8405c30cd48ae460071f6a4f2c35f9) - 🎚️ Users can selectively disable specific built-in tools (timestamps, memory, chat history, notes, web search, knowledge bases) per model via the model editor's capabilities settings. [Commit](https://github.com/open-webui/open-webui/commit/60e916d6c0c5f7db9e6d670e12be2d1d4abc2dd6) -- 👁️ Pending tool calls are now displayed during response generation, showing which tools are being invoked so users know the system is working. [Commit](https://github.com/open-webui/open-webui/commit/1d08376860e775049abd1dd5f568ac0c6466c944) +- 👁️ Pending tool calls are now displayed during response generation, so users know which tools are being invoked. [Commit](https://github.com/open-webui/open-webui/commit/1d08376860e775049abd1dd5f568ac0c6466c944) - 📁 Administrators can now limit the number of files that can be uploaded to folders using the "FOLDER_MAX_FILE_COUNT" setting, preventing resource exhaustion from bulk uploads. [#19810](https://github.com/open-webui/open-webui/issues/19810), [Commit](https://github.com/open-webui/open-webui/commit/a1036e544d573e3d35e05c1c2472ba762c32431b), [Commit](https://github.com/open-webui/open-webui/commit/d3ee3fd23e762c9d83fe1da5636d03259e186e57) - ⚡ Users experience transformative speed improvements across the entire application through completely reengineered database connection handling, delivering noticeably faster page loads, butter-smooth interactions, and rock-solid stability during intensive operations like user management and bulk data processing. [Commit](https://github.com/open-webui/open-webui/commit/2041ab483e21b3a757baa25c47dc2fa29018674f), [Commit](https://github.com/open-webui/open-webui/commit/145c7516f227ce56fd52373cee86217fadf16181), [Commit](https://github.com/open-webui/open-webui/commit/475dd91ed798f2efcdf27799d5c5cae3f0e6e847), [Commit](https://github.com/open-webui/open-webui/commit/5d1459df166cce8445eb1556cc26abbd65a3f9f4), [Commit](https://github.com/open-webui/open-webui/commit/2453b75ff0fb2dc75b929d96f417d84e332922d9), [Commit](https://github.com/open-webui/open-webui/commit/5649a668fad15393a52c27a2f188841af8b66989) - 🚀 Users experience significantly faster initial page load times through dynamic loading of document processing libraries, reducing the initial bundle size. [#20200](https://github.com/open-webui/open-webui/pull/20200), [#20202](https://github.com/open-webui/open-webui/pull/20202), [#20203](https://github.com/open-webui/open-webui/pull/20203), [#20204](https://github.com/open-webui/open-webui/pull/20204) From eff772562b4dca5a585ca2851e8828592c53a9cf Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 21:19:27 +0400 Subject: [PATCH 213/254] chore: format --- src/lib/i18n/locales/ar-BH/translation.json | 2 -- src/lib/i18n/locales/ar/translation.json | 2 -- src/lib/i18n/locales/bg-BG/translation.json | 2 -- src/lib/i18n/locales/bn-BD/translation.json | 2 -- src/lib/i18n/locales/bo-TB/translation.json | 2 -- src/lib/i18n/locales/bs-BA/translation.json | 2 -- src/lib/i18n/locales/ca-ES/translation.json | 2 -- src/lib/i18n/locales/ceb-PH/translation.json | 2 -- src/lib/i18n/locales/cs-CZ/translation.json | 2 -- src/lib/i18n/locales/da-DK/translation.json | 2 -- src/lib/i18n/locales/de-DE/translation.json | 2 -- src/lib/i18n/locales/dg-DG/translation.json | 2 -- src/lib/i18n/locales/el-GR/translation.json | 2 -- src/lib/i18n/locales/en-GB/translation.json | 2 -- src/lib/i18n/locales/en-US/translation.json | 2 -- src/lib/i18n/locales/es-ES/translation.json | 2 -- src/lib/i18n/locales/et-EE/translation.json | 2 -- src/lib/i18n/locales/eu-ES/translation.json | 2 -- src/lib/i18n/locales/fa-IR/translation.json | 2 -- src/lib/i18n/locales/fi-FI/translation.json | 2 -- src/lib/i18n/locales/fr-CA/translation.json | 2 -- src/lib/i18n/locales/fr-FR/translation.json | 2 -- src/lib/i18n/locales/gl-ES/translation.json | 2 -- src/lib/i18n/locales/he-IL/translation.json | 2 -- src/lib/i18n/locales/hi-IN/translation.json | 2 -- src/lib/i18n/locales/hr-HR/translation.json | 2 -- src/lib/i18n/locales/hu-HU/translation.json | 2 -- src/lib/i18n/locales/id-ID/translation.json | 2 -- src/lib/i18n/locales/ie-GA/translation.json | 2 -- src/lib/i18n/locales/it-IT/translation.json | 2 -- src/lib/i18n/locales/ja-JP/translation.json | 2 -- src/lib/i18n/locales/ka-GE/translation.json | 2 -- src/lib/i18n/locales/kab-DZ/translation.json | 2 -- src/lib/i18n/locales/ko-KR/translation.json | 2 -- src/lib/i18n/locales/lt-LT/translation.json | 2 -- src/lib/i18n/locales/ms-MY/translation.json | 2 -- src/lib/i18n/locales/nb-NO/translation.json | 2 -- src/lib/i18n/locales/nl-NL/translation.json | 2 -- src/lib/i18n/locales/pa-IN/translation.json | 2 -- src/lib/i18n/locales/pl-PL/translation.json | 2 -- src/lib/i18n/locales/pt-BR/translation.json | 2 -- src/lib/i18n/locales/pt-PT/translation.json | 2 -- src/lib/i18n/locales/ro-RO/translation.json | 2 -- src/lib/i18n/locales/ru-RU/translation.json | 2 -- src/lib/i18n/locales/sk-SK/translation.json | 2 -- src/lib/i18n/locales/sr-RS/translation.json | 2 -- src/lib/i18n/locales/sv-SE/translation.json | 2 -- src/lib/i18n/locales/th-TH/translation.json | 2 -- src/lib/i18n/locales/tk-TM/translation.json | 2 -- src/lib/i18n/locales/tr-TR/translation.json | 2 -- src/lib/i18n/locales/ug-CN/translation.json | 2 -- src/lib/i18n/locales/uk-UA/translation.json | 2 -- src/lib/i18n/locales/ur-PK/translation.json | 2 -- src/lib/i18n/locales/uz-Cyrl-UZ/translation.json | 2 -- src/lib/i18n/locales/uz-Latn-Uz/translation.json | 2 -- src/lib/i18n/locales/vi-VN/translation.json | 2 -- src/lib/i18n/locales/zh-CN/translation.json | 2 -- src/lib/i18n/locales/zh-TW/translation.json | 2 -- 58 files changed, 116 deletions(-) diff --git a/src/lib/i18n/locales/ar-BH/translation.json b/src/lib/i18n/locales/ar-BH/translation.json index f2dabb6eaa..d45938957c 100644 --- a/src/lib/i18n/locales/ar-BH/translation.json +++ b/src/lib/i18n/locales/ar-BH/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": " {{name}} مرحبا", "Help": "مساعدة", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "أخفاء", @@ -1716,7 +1715,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "اليوم", diff --git a/src/lib/i18n/locales/ar/translation.json b/src/lib/i18n/locales/ar/translation.json index da28fb85b2..76303233d0 100644 --- a/src/lib/i18n/locales/ar/translation.json +++ b/src/lib/i18n/locales/ar/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": " {{name}} مرحبا", "Help": "مساعدة", - "Help us create the best community leaderboard by sharing your feedback history!": "ساعدنا في إنشاء أفضل قائمة للمتصدرين من خلال مشاركة سجل ملاحظاتك!", "Hex Color": "لون سداسي", "Hex Color - Leave empty for default color": "اللون السداسي - اتركه فارغًا لاستخدام اللون الافتراضي", "Hide": "أخفاء", @@ -1716,7 +1715,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "لإرفاق قاعدة المعرفة هنا، أضفها أولاً إلى مساحة العمل \"المعرفة\".", "To learn more about available endpoints, visit our documentation.": "لمعرفة المزيد حول نقاط النهاية المتاحة، قم بزيارة الوثائق الخاصة بنا.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "لحماية خصوصيتك، يتم مشاركة التقييمات ومعرّفات النماذج والوسوم والبيانات الوصفية فقط من ملاحظاتك—سجلات الدردشة تظل خاصة ولا تُدرج.", "To select toolkits here, add them to the \"Tools\" workspace first.": "لاختيار الأدوات هنا، أضفها أولاً إلى مساحة العمل \"الأدوات\".", "Toast notifications for new updates": "إشعارات منبثقة للتحديثات الجديدة", "Today": "اليوم", diff --git a/src/lib/i18n/locales/bg-BG/translation.json b/src/lib/i18n/locales/bg-BG/translation.json index b44b8336d6..601ed32a74 100644 --- a/src/lib/i18n/locales/bg-BG/translation.json +++ b/src/lib/i18n/locales/bg-BG/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Здравей, {{name}}", "Help": "Помощ", - "Help us create the best community leaderboard by sharing your feedback history!": "Помогнете ни да създадем най-добрата класация на общността, като споделите историята на вашата обратна връзка!", "Hex Color": "Hex цвят", "Hex Color - Leave empty for default color": "Hex цвят - Оставете празно за цвят по подразбиране", "Hide": "Скрий", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "За да прикачите база знания тук, първо ги добавете към работното пространство \"Знания\".", "To learn more about available endpoints, visit our documentation.": "За да научите повече за наличните крайни точки, посетете нашата документация.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "За да защитим вашата поверителност, от вашата обратна връзка се споделят само оценки, идентификатори на модели, тагове и метаданни-вашите чат логове остават лични и не са включени.", "To select toolkits here, add them to the \"Tools\" workspace first.": "За да изберете инструменти тук, първо ги добавете към работното пространство \"Инструменти\".", "Toast notifications for new updates": "Изскачащи известия за нови актуализации", "Today": "Днес", diff --git a/src/lib/i18n/locales/bn-BD/translation.json b/src/lib/i18n/locales/bn-BD/translation.json index 76ac814168..4ea5b9671e 100644 --- a/src/lib/i18n/locales/bn-BD/translation.json +++ b/src/lib/i18n/locales/bn-BD/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "হ্যালো, {{name}}", "Help": "সহায়তা", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "লুকান", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "আজ", diff --git a/src/lib/i18n/locales/bo-TB/translation.json b/src/lib/i18n/locales/bo-TB/translation.json index 6a5d50f2cc..ef4315d89d 100644 --- a/src/lib/i18n/locales/bo-TB/translation.json +++ b/src/lib/i18n/locales/bo-TB/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "བཀྲ་ཤིས་བདེ་ལེགས། {{name}}", "Help": "རོགས་རམ།", - "Help us create the best community leaderboard by sharing your feedback history!": "ཁྱེད་ཀྱི་བསམ་འཆར་ལོ་རྒྱུས་མཉམ་སྤྱོད་བྱས་ནས་ང་ཚོས་སྤྱི་ཚོགས་ཀྱི་འགྲན་རེས་རེའུ་མིག་ཡག་ཤོས་བཟོ་བར་རོགས་པ་བྱེད་རོགས།", "Hex Color": "Hex ཚོན་མདོག", "Hex Color - Leave empty for default color": "Hex ཚོན་མདོག - སྔོན་སྒྲིག་ཚོན་མདོག་གི་ཆེད་དུ་སྟོང་པ་བཞག་པ།", "Hide": "སྦ་བ།", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "ཤེས་བྱའི་རྟེན་གཞི་འདིར་འཇོག་པར། ཐོག་མར་དེ་དག་ \"ཤེས་བྱའི་\" ལས་ཡུལ་དུ་སྣོན་པ།", "To learn more about available endpoints, visit our documentation.": "ཡོད་པའི་མཇུག་མཐུད་སྐོར་མང་ཙམ་ཤེས་པར། ང་ཚོའི་ཡིག་ཆ་ལ་ལྟ་བ།", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "ཁྱེད་ཀྱི་སྒེར་དོན་སྲུང་སྐྱོབ་བྱེད་པར། ཁྱེད་ཀྱི་བསམ་འཆར་ནས་སྐར་མ། དཔེ་དབྱིབས་ཀྱི་ IDs། རྟགས། དང་ metadata ཁོ་ན་མཉམ་སྤྱོད་བྱེད།—ཁྱེད་ཀྱི་ཁ་བརྡའི་ཟིན་ཐོ་སྒེར་དོན་དུ་གནས་པ་དང་ཚུད་མེད།", "To select toolkits here, add them to the \"Tools\" workspace first.": "ལག་ཆའི་ཚོགས་སྡེ་འདིར་གདམ་ག་བྱེད་པར། ཐོག་མར་དེ་དག་ \"ལག་ཆའི་\" ལས་ཡུལ་དུ་སྣོན་པ།", "Toast notifications for new updates": "གསར་སྒྱུར་གསར་པའི་ཆེད་དུ་ Toast བརྡ་ཁྱབ།", "Today": "དེ་རིང་།", diff --git a/src/lib/i18n/locales/bs-BA/translation.json b/src/lib/i18n/locales/bs-BA/translation.json index 17b2f85f1e..0de018ace9 100644 --- a/src/lib/i18n/locales/bs-BA/translation.json +++ b/src/lib/i18n/locales/bs-BA/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Bok, {{name}}", "Help": "Pomoć", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Sakrij", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "Danas", diff --git a/src/lib/i18n/locales/ca-ES/translation.json b/src/lib/i18n/locales/ca-ES/translation.json index 4d8ae93b86..edefcb6e9a 100644 --- a/src/lib/i18n/locales/ca-ES/translation.json +++ b/src/lib/i18n/locales/ca-ES/translation.json @@ -886,7 +886,6 @@ "Height": "Alçada", "Hello, {{name}}": "Hola, {{name}}", "Help": "Ajuda", - "Help us create the best community leaderboard by sharing your feedback history!": "Ajuda'ns a crear la millor taula de classificació de la comunitat compartint el teu historial de comentaris!", "Hex Color": "Color hexadecimal", "Hex Color - Leave empty for default color": "Color hexadecimal - Deixar buit per a color per defecte", "Hide": "Amaga", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Per adjuntar la base de coneixement aquí, afegiu-la primer a l'espai de treball \"Coneixement\".", "To learn more about available endpoints, visit our documentation.": "Per obtenir més informació sobre els punts d'accés disponibles, visiteu la nostra documentació.", "To learn more about powerful prompt variables, click here": "Per obtenir més informació sobre les variables de prompt potents, fes clic aquí", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Per protegir la privadesa, només es comparteixen puntuacions, identificadors de models, etiquetes i metadades dels comentaris; els registres de xat romanen privats i no s'inclouen.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Per seleccionar kits d'eines aquí, afegeix-los primer a l'espai de treball \"Eines\".", "Toast notifications for new updates": "Notificacions Toast de noves actualitzacions", "Today": "Avui", diff --git a/src/lib/i18n/locales/ceb-PH/translation.json b/src/lib/i18n/locales/ceb-PH/translation.json index 853abdc7ab..eae1d83171 100644 --- a/src/lib/i18n/locales/ceb-PH/translation.json +++ b/src/lib/i18n/locales/ceb-PH/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Maayong buntag, {{name}}", "Help": "", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Tagoa", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "", diff --git a/src/lib/i18n/locales/cs-CZ/translation.json b/src/lib/i18n/locales/cs-CZ/translation.json index 66fefd0cb1..faad1714de 100644 --- a/src/lib/i18n/locales/cs-CZ/translation.json +++ b/src/lib/i18n/locales/cs-CZ/translation.json @@ -886,7 +886,6 @@ "Height": "Výška", "Hello, {{name}}": "Dobrý den, {{name}}", "Help": "Nápověda", - "Help us create the best community leaderboard by sharing your feedback history!": "Pomozte nám vytvořit nejlepší komunitní žebříček sdílením historie vaší zpětné vazby!", "Hex Color": "Hex barva", "Hex Color - Leave empty for default color": "Hex barva - pro výchozí barvu ponechte prázdné", "Hide": "Skrýt", @@ -1714,7 +1713,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Pro připojení znalostní báze sem ji nejprve přidejte do pracovního prostoru \"Znalosti\".", "To learn more about available endpoints, visit our documentation.": "Pro více informací o dostupných koncových bodech navštivte naši dokumentaci.", "To learn more about powerful prompt variables, click here": "Pro více informací o mocných proměnných v instrukcích klikněte zde", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Pro ochranu vašeho soukromí jsou z vaší zpětné vazby sdílena pouze hodnocení, ID modelů, štítky a metadata – vaše záznamy konverzací zůstávají soukromé a nejsou zahrnuty.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Pro výběr sad nástrojů zde je nejprve přidejte do pracovního prostoru \"Nástroje\".", "Toast notifications for new updates": "Vyskakovací oznámení o nových aktualizacích", "Today": "Dnes", diff --git a/src/lib/i18n/locales/da-DK/translation.json b/src/lib/i18n/locales/da-DK/translation.json index 6a0aeef06b..b8d972885f 100644 --- a/src/lib/i18n/locales/da-DK/translation.json +++ b/src/lib/i18n/locales/da-DK/translation.json @@ -886,7 +886,6 @@ "Height": "Højde", "Hello, {{name}}": "Hej {{name}}", "Help": "Hjælp", - "Help us create the best community leaderboard by sharing your feedback history!": "Hjælp os med at oprette det bedste community-lederboard ved at dele din feedback-historik!", "Hex Color": "Hex farve", "Hex Color - Leave empty for default color": "Hex farve - Lad stå tomt for standard farve", "Hide": "Skjul", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "For at vedhæfte vidensbase her skal du først tilføje dem til \"Viden\"-arbejdsområdet.", "To learn more about available endpoints, visit our documentation.": "For at lære mere om tilgængelige endpoints, besøg vores dokumentation.", "To learn more about powerful prompt variables, click here": "For at lære mere om kraftfulde prompt-variabler, klik her", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "For at beskytte dit privatliv deles kun vurderinger, model-ID'er, tags og metadata fra din feedback - dine chatlogfiler forbliver private og er ikke inkluderet.", "To select toolkits here, add them to the \"Tools\" workspace first.": "For at vælge værktøjssæt her skal du først tilføje dem til \"Værktøjer\"-arbejdsområdet.", "Toast notifications for new updates": "Toast-notifikationer for nye opdateringer", "Today": "I dag", diff --git a/src/lib/i18n/locales/de-DE/translation.json b/src/lib/i18n/locales/de-DE/translation.json index 6fe704342c..44c689640e 100644 --- a/src/lib/i18n/locales/de-DE/translation.json +++ b/src/lib/i18n/locales/de-DE/translation.json @@ -886,7 +886,6 @@ "Height": "Höhe", "Hello, {{name}}": "Hallo, {{name}}", "Help": "Hilfe", - "Help us create the best community leaderboard by sharing your feedback history!": "Helfen Sie uns, die beste Community-Bestenliste zu erstellen, indem Sie Ihren Feedback-Verlauf teilen!", "Hex Color": "Hex-Farbe", "Hex Color - Leave empty for default color": "Hex-Farbe - Leer lassen für Standard", "Hide": "Verbergen", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Um einen Wissensspeicher hier anzuhängen, fügen Sie sie zuerst dem Arbeitsbereich \"Wissen\" hinzu.", "To learn more about available endpoints, visit our documentation.": "Um mehr über verfügbare Endpunkte zu erfahren, besuchen Sie unsere Dokumentation.", "To learn more about powerful prompt variables, click here": "Um mehr über mächtige Prompt-Variablen zu erfahren, klicken Sie hier", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Zum Schutz Ihrer Privatsphäre werden nur Bewertungen, Modell-IDs, Tags und Metadaten aus Ihrem Feedback geteilt – Ihre Chat-Protokolle bleiben privat und sind nicht enthalten.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Um Toolkits auszuwählen, fügen Sie sie zuerst dem Arbeitsbereich \"Werkzeuge\" hinzu.", "Toast notifications for new updates": "Toast-Benachrichtigungen für neue Updates", "Today": "Heute", diff --git a/src/lib/i18n/locales/dg-DG/translation.json b/src/lib/i18n/locales/dg-DG/translation.json index 681541c6b1..0a512dd6cd 100644 --- a/src/lib/i18n/locales/dg-DG/translation.json +++ b/src/lib/i18n/locales/dg-DG/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Much helo, {{name}}", "Help": "", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Hide", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "", diff --git a/src/lib/i18n/locales/el-GR/translation.json b/src/lib/i18n/locales/el-GR/translation.json index 8500fe2bdd..53f7442a07 100644 --- a/src/lib/i18n/locales/el-GR/translation.json +++ b/src/lib/i18n/locales/el-GR/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Γειά σου, {{name}}", "Help": "Βοήθεια", - "Help us create the best community leaderboard by sharing your feedback history!": "Βοηθήστε μας να δημιουργήσουμε την καλύτερη κατάταξη κοινότητας μοιράζοντας το ιστορικό ανατροφοδότησής σας!", "Hex Color": "Χρώμα Hex", "Hex Color - Leave empty for default color": "Χρώμα Hex - Αφήστε κενό για προεπιλεγμένο χρώμα", "Hide": "Απόκρυψη", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Για να επισυνάψετε τη βάση γνώσης εδώ, προσθέστε τα πρώτα στον χώρο εργασίας \"Γνώση\".", "To learn more about available endpoints, visit our documentation.": "Για να μάθετε περισσότερα για τα διαθέσιμα endpoints, δείτε την τεκμηρίωσή μας.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Για να προστατεύσετε την ιδιωτικότητά σας, μόνο οι βαθμολογίες, τα IDs μοντέλων, οι ετικέτες και τα μεταδεδομένα μοιράζονται από την ανατροφοδότησή σας—τα αρχεία συνομιλιών σας παραμένουν ιδιωτικά και δεν περιλαμβάνονται.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Για να επιλέξετε toolkits εδώ, προσθέστε τα πρώτα στον χώρο εργασίας \"Εργαλεία\".", "Toast notifications for new updates": "Ειδοποιήσεις Toast για νέες ενημερώσεις", "Today": "Σήμερα", diff --git a/src/lib/i18n/locales/en-GB/translation.json b/src/lib/i18n/locales/en-GB/translation.json index bb97030b9b..4792c28500 100644 --- a/src/lib/i18n/locales/en-GB/translation.json +++ b/src/lib/i18n/locales/en-GB/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "", "Help": "", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "Hex Colour", "Hex Color - Leave empty for default color": "Hex Colour - Leave empty for default colour", "Hide": "", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "", diff --git a/src/lib/i18n/locales/en-US/translation.json b/src/lib/i18n/locales/en-US/translation.json index fe5ec7699a..c7065457fd 100644 --- a/src/lib/i18n/locales/en-US/translation.json +++ b/src/lib/i18n/locales/en-US/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "", "Help": "", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "", diff --git a/src/lib/i18n/locales/es-ES/translation.json b/src/lib/i18n/locales/es-ES/translation.json index 80435c0f14..6eaacc5177 100644 --- a/src/lib/i18n/locales/es-ES/translation.json +++ b/src/lib/i18n/locales/es-ES/translation.json @@ -886,7 +886,6 @@ "Height": "Altura", "Hello, {{name}}": "Hola, {{name}}", "Help": "Ayuda", - "Help us create the best community leaderboard by sharing your feedback history!": "¡Ayúdanos a crear la mejor tabla clasificatoria comunitaria compartiendo tus comentarios!", "Hex Color": "Color Hex", "Hex Color - Leave empty for default color": "Color Hex - Deja vacío para el color predeterminado", "Hide": "Esconder", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Para adjuntar la base de conocimientos aquí, primero añadirla a \"Conocimiento\" en el área de trabajo.", "To learn more about available endpoints, visit our documentation.": "Para aprender más sobre los endpoints disponibles, visite nuestra documentación.", "To learn more about powerful prompt variables, click here": "Para saber más sobre las variables de indicador potenciadas, pulse aquí", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Para proteger tu privacidad, de tus comentarios solo se comparten las calificaciones, IDs de modelo, etiquetas y metadatos; tus chat guardados permanecen privados y no se incluyen.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Para seleccionar herramientas aquí, primero añadelas a \"Herramientas\" en el área de trabajo.", "Toast notifications for new updates": "Notificaciones emergentes para nuevas actualizaciones", "Today": "Hoy", diff --git a/src/lib/i18n/locales/et-EE/translation.json b/src/lib/i18n/locales/et-EE/translation.json index 54d3b5236d..93bb5def35 100644 --- a/src/lib/i18n/locales/et-EE/translation.json +++ b/src/lib/i18n/locales/et-EE/translation.json @@ -886,7 +886,6 @@ "Height": "Kõrgus", "Hello, {{name}}": "Tere, {{name}}", "Help": "Abi", - "Help us create the best community leaderboard by sharing your feedback history!": "Aidake meil luua parim kogukonna edetabel, jagades oma tagasiside ajalugu!", "Hex Color": "Hex värv", "Hex Color - Leave empty for default color": "Hex värv - jätke tühjaks vaikevärvi jaoks", "Hide": "Peida", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Teadmiste baasi siia lisamiseks lisage need esmalt \"Teadmiste\" tööalale.", "To learn more about available endpoints, visit our documentation.": "Saadaolevate lõpp-punktide kohta rohkem teada saamiseks külastage meie dokumentatsiooni.", "To learn more about powerful prompt variables, click here": "Kuni learn more about powerful prompt variables, click here", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Teie privaatsuse kaitsmiseks jagatakse teie tagasisidest ainult hinnanguid, mudeli ID-sid, silte ja metaandmeid - teie vestluslogi jääb privaatseks ja neid ei kaasata.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Tööriistakomplektide siit valimiseks lisage need esmalt \"Tööriistade\" tööalale.", "Toast notifications for new updates": "Hüpikmärguanded uuenduste kohta", "Today": "Täna", diff --git a/src/lib/i18n/locales/eu-ES/translation.json b/src/lib/i18n/locales/eu-ES/translation.json index a95d022384..4857b5458b 100644 --- a/src/lib/i18n/locales/eu-ES/translation.json +++ b/src/lib/i18n/locales/eu-ES/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Kaixo, {{name}}", "Help": "Laguntza", - "Help us create the best community leaderboard by sharing your feedback history!": "Lagundu komunitatearen sailkapen onena sortzen zure feedback historia partekatuz!", "Hex Color": "Hex Kolorea", "Hex Color - Leave empty for default color": "Hex Kolorea - Utzi hutsik kolore lehenetsia erabiltzeko", "Hide": "Ezkutatu", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Ezagutza-basea hemen eransteko, gehitu ezazu lehenik \"Ezagutza\" lan-eremura.", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Zure pribatutasuna babesteko, zure feedbacketik bakarrik partekatzen dira balorazioak, modelo IDak, etiketak eta metadatuak—zure txat erregistroak pribatuak dira eta ez dira sartzen.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Tresna-multzoak hemen hautatzeko, gehitu itzazu lehenik \"Tresnak\" lan-eremura.", "Toast notifications for new updates": "Toast jakinarazpenak eguneraketa berrientzat", "Today": "Gaur", diff --git a/src/lib/i18n/locales/fa-IR/translation.json b/src/lib/i18n/locales/fa-IR/translation.json index 1a75c640e8..d29f2b92cc 100644 --- a/src/lib/i18n/locales/fa-IR/translation.json +++ b/src/lib/i18n/locales/fa-IR/translation.json @@ -886,7 +886,6 @@ "Height": "ارتفاع", "Hello, {{name}}": "سلام، {{name}}", "Help": "کمک", - "Help us create the best community leaderboard by sharing your feedback history!": "با به اشتراک گذاشتن تاریخچه بازخورد خود به ما در ایجاد بهترین تابلوی امتیازات جامعه کمک کنید!", "Hex Color": "رنگ هگز", "Hex Color - Leave empty for default color": "رنگ هگز - برای رنگ پیش\u200cفرض خالی بگذارید", "Hide": "پنهان\u200cسازی", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "برای اتصال پایگاه دانش در اینجا، ابتدا آنها را به فضای کاری \"دانش\" اضافه کنید.", "To learn more about available endpoints, visit our documentation.": "برای کسب اطلاعات بیشتر در مورد نقاط پایانی موجود، به مستندات ما مراجعه کنید.", "To learn more about powerful prompt variables, click here": "برای کسب اطلاعات بیشتر در مورد متغیرهای قدرتمند پرامپت، اینجا کلیک کنید", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "برای حفظ حریم خصوصی شما، فقط امتیازات، شناسه\u200cهای مدل، برچسب\u200cها و متادیتا از بازخورد شما به اشتراک گذاشته می\u200cشود - گفتگوهای شما خصوصی باقی می\u200cماند و شامل نمی\u200cشود.", "To select toolkits here, add them to the \"Tools\" workspace first.": "برای انتخاب ابزارها در اینجا، ابتدا آنها را به فضای کاری \"ابزارها\" اضافه کنید.", "Toast notifications for new updates": "اعلان\u200cهای پاپ\u200cآپ برای به\u200cروزرسانی\u200cهای جدید", "Today": "امروز", diff --git a/src/lib/i18n/locales/fi-FI/translation.json b/src/lib/i18n/locales/fi-FI/translation.json index af53b16598..488e0086ec 100644 --- a/src/lib/i18n/locales/fi-FI/translation.json +++ b/src/lib/i18n/locales/fi-FI/translation.json @@ -886,7 +886,6 @@ "Height": "Korkeus", "Hello, {{name}}": "Hei, {{name}}", "Help": "Ohje", - "Help us create the best community leaderboard by sharing your feedback history!": "Auta meitä luomaan paras yhteisön tulosluettelo jakamalla palautehistoriasi!", "Hex Color": "Heksadesimaaliväri", "Hex Color - Leave empty for default color": "Heksadesimaaliväri - Jätä tyhjäksi, jos haluat oletusvärin", "Hide": "Piilota", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Liittääksesi tietokantasi tähän, lisää ne ensin \"Tietämys\"-työtilaan.", "To learn more about available endpoints, visit our documentation.": "Jos haluat lisätietoja käytettävissä olevista päätepisteistä, tutustu dokumentaatioomme.", "To learn more about powerful prompt variables, click here": "Lisätietoja tehokkaista kehotemuuttujista saat napsauttamalla tästä", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Yksityisyydensuojasi vuoksi palautteestasi jaetaan vain arvostelut, mallitunnukset, tagit ja metadata - keskustelulokisi pysyvät yksityisinä eikä niitä sisällytetä.", "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", diff --git a/src/lib/i18n/locales/fr-CA/translation.json b/src/lib/i18n/locales/fr-CA/translation.json index 44c68b5d9e..708c5a9e98 100644 --- a/src/lib/i18n/locales/fr-CA/translation.json +++ b/src/lib/i18n/locales/fr-CA/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Bonjour, {{name}}.", "Help": "Aide", - "Help us create the best community leaderboard by sharing your feedback history!": "Aidez-nous à créer le meilleur classement communautaire en partageant votre historique des avis !", "Hex Color": "Couleur Hex", "Hex Color - Leave empty for default color": "Couleur Hex - Laissez vide pour la couleur par défaut", "Hide": "Cacher", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Pour attacher une base de connaissances ici, ajoutez-les d'abord à l'espace de travail « Connaissances ».", "To learn more about available endpoints, visit our documentation.": "Pour en savoir plus sur les points de terminaison disponibles, consultez notre documentation.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Pour protéger votre confidentialité, seules les notes, les identifiants de modèle, les tags et les métadonnées de vos commentaires sont partagés. Vos journaux de discussion restent privés et ne sont pas inclus.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Pour sélectionner des outils ici, ajoutez-les d'abord à l'espace de travail « Outils ». ", "Toast notifications for new updates": "Notifications toast pour les nouvelles mises à jour", "Today": "Aujourd'hui", diff --git a/src/lib/i18n/locales/fr-FR/translation.json b/src/lib/i18n/locales/fr-FR/translation.json index 02a397c1da..1dfc87b1a7 100644 --- a/src/lib/i18n/locales/fr-FR/translation.json +++ b/src/lib/i18n/locales/fr-FR/translation.json @@ -886,7 +886,6 @@ "Height": "Hauteur", "Hello, {{name}}": "Bonjour, {{name}}.", "Help": "Aide", - "Help us create the best community leaderboard by sharing your feedback history!": "Aidez-nous à créer le meilleur classement communautaire en partageant votre historique des avis !", "Hex Color": "Couleur Hex", "Hex Color - Leave empty for default color": "Couleur Hex - Laissez vide pour la couleur par défaut", "Hide": "Cacher", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Pour attacher une base de connaissances ici, ajoutez-les d'abord à l'espace de travail « Connaissances ».", "To learn more about available endpoints, visit our documentation.": "Pour en savoir plus sur les points de terminaison disponibles, consultez notre documentation.", "To learn more about powerful prompt variables, click here": "Pour en savoir plus sur les variables de prompt puissantes, cliquez ici", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Pour protéger votre confidentialité, seules les notes, les identifiants de modèle, les tags et les métadonnées de vos commentaires sont partagés. Vos journaux de discussion restent privés et ne sont pas inclus.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Pour sélectionner des outils ici, ajoutez-les d'abord à l'espace de travail « Outils ». ", "Toast notifications for new updates": "Notifications toast pour les nouvelles mises à jour", "Today": "Aujourd'hui", diff --git a/src/lib/i18n/locales/gl-ES/translation.json b/src/lib/i18n/locales/gl-ES/translation.json index b4e289e06e..b7c637db33 100644 --- a/src/lib/i18n/locales/gl-ES/translation.json +++ b/src/lib/i18n/locales/gl-ES/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Hola, {{name}}", "Help": "axuda", - "Help us create the best community leaderboard by sharing your feedback history!": "¡Axudanos a xerar o mejor tablero de líderes da comunidad compartindo o teu historial de retroalimentación!", "Hex Color": "Cor Hex", "Hex Color - Leave empty for default color": "Cor Hex - deixa vacío para o color predeterminado", "Hide": "Esconder", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Para adjuntar la base de coñecementos aquí, agreguelas al área de trabajo \"coñecemento\" primeiro.", "To learn more about available endpoints, visit our documentation.": "Para obter mais información sobre os endpoints disponibles, visite nuestra documentación.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Para protexer a sua privacidade, solo compartense as calificacions, IDs dos modelos, etiquetas e metadatos da sua retroalimentación; os seus rexistros de chat permanecen privados e non se incluen.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Para seleccionar ferramentas aquí, agreguelas al área de trabajo \"Ferramentas\" primeiro.", "Toast notifications for new updates": "Notificacions emergentes para novas actualizacions", "Today": "Hoxe", diff --git a/src/lib/i18n/locales/he-IL/translation.json b/src/lib/i18n/locales/he-IL/translation.json index 5074de52a9..dbe61461c9 100644 --- a/src/lib/i18n/locales/he-IL/translation.json +++ b/src/lib/i18n/locales/he-IL/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "שלום, {{name}}", "Help": "עזרה", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "הסתר", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "היום", diff --git a/src/lib/i18n/locales/hi-IN/translation.json b/src/lib/i18n/locales/hi-IN/translation.json index 04b04a51f7..1a69ba9051 100644 --- a/src/lib/i18n/locales/hi-IN/translation.json +++ b/src/lib/i18n/locales/hi-IN/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "नमस्ते, {{name}}", "Help": "मदद", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "छुपाएं", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "आज", diff --git a/src/lib/i18n/locales/hr-HR/translation.json b/src/lib/i18n/locales/hr-HR/translation.json index e9b738ad48..9777efe394 100644 --- a/src/lib/i18n/locales/hr-HR/translation.json +++ b/src/lib/i18n/locales/hr-HR/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Bok, {{name}}", "Help": "Pomoć", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Sakrij", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "Danas", diff --git a/src/lib/i18n/locales/hu-HU/translation.json b/src/lib/i18n/locales/hu-HU/translation.json index 31b31c9827..da642c91cd 100644 --- a/src/lib/i18n/locales/hu-HU/translation.json +++ b/src/lib/i18n/locales/hu-HU/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Helló, {{name}}", "Help": "Segítség", - "Help us create the best community leaderboard by sharing your feedback history!": "Segíts nekünk a legjobb közösségi ranglista létrehozásában a visszajelzési előzményeid megosztásával!", "Hex Color": "Hexa szín", "Hex Color - Leave empty for default color": "Hexa szín - Hagyd üresen az alapértelmezett színhez", "Hide": "Elrejtés", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "A tudásbázis csatolásához először adja hozzá őket a \"Knowledge\" munkaterülethez.", "To learn more about available endpoints, visit our documentation.": "Az elérhető végpontokról további információért látogassa meg dokumentációnkat.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Adatai védelme érdekében a visszajelzésből csak az értékelések, modell azonosítók, címkék és metaadatok kerülnek megosztásra - a csevegési előzményei privátak maradnak és nem kerülnek megosztásra.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Az eszközkészletek kiválasztásához először adja hozzá őket a \"Tools\" munkaterülethez.", "Toast notifications for new updates": "Felugró értesítések az új frissítésekről", "Today": "Ma", diff --git a/src/lib/i18n/locales/id-ID/translation.json b/src/lib/i18n/locales/id-ID/translation.json index ad4518fc8a..25809d6daa 100644 --- a/src/lib/i18n/locales/id-ID/translation.json +++ b/src/lib/i18n/locales/id-ID/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Halo, {{name}}", "Help": "Bantuan", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Sembunyikan", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "Untuk memilih perangkat di sini, tambahkan ke ruang kerja \"Alat\" terlebih dahulu.", "Toast notifications for new updates": "", "Today": "Hari ini", diff --git a/src/lib/i18n/locales/ie-GA/translation.json b/src/lib/i18n/locales/ie-GA/translation.json index 794ac5ad10..2f92ed6b6b 100644 --- a/src/lib/i18n/locales/ie-GA/translation.json +++ b/src/lib/i18n/locales/ie-GA/translation.json @@ -886,7 +886,6 @@ "Height": "Airde", "Hello, {{name}}": "Dia duit, {{name}}", "Help": "Cabhair", - "Help us create the best community leaderboard by sharing your feedback history!": "Cabhraigh linn an clár ceannairí pobail is fearr a chruthú trí do stair aiseolais a roinnt!", "Hex Color": "Dath Heics", "Hex Color - Leave empty for default color": "Dath Heics - Fág folamh don dath réamhshocraithe", "Hide": "Folaigh", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Chun an bonn eolais a cheangal anseo, cuir leis an spás oibre \"Eolas\" iad ar dtús.", "To learn more about available endpoints, visit our documentation.": "Chun tuilleadh a fhoghlaim faoi na críochphointí atá ar fáil, tabhair cuairt ar ár gcáipéisíocht.", "To learn more about powerful prompt variables, click here": "Chun tuilleadh eolais a fháil faoi athróga leid chumhachtacha, cliceáil anseo", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Chun do phríobháideacht a chosaint, ní roinntear ach rátálacha, aitheantóirí samhail, clibeanna agus meiteashonraí ó d’aiseolas—fanann do logaí comhrá príobháideach agus níl siad san áireamh.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Chun trealamh uirlisí a roghnú anseo, cuir iad leis an spás oibre \"Uirlisí\" ar dtús.", "Toast notifications for new updates": "Fógraí tósta le haghaidh nuashonruithe nua", "Today": "Inniu", diff --git a/src/lib/i18n/locales/it-IT/translation.json b/src/lib/i18n/locales/it-IT/translation.json index 4d46fa69fe..2885a16d2e 100644 --- a/src/lib/i18n/locales/it-IT/translation.json +++ b/src/lib/i18n/locales/it-IT/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Ciao, {{name}}", "Help": "Aiuto", - "Help us create the best community leaderboard by sharing your feedback history!": "Aiutaci a creare la migliore classifica della community condividendo la tua cronologia feedback!", "Hex Color": "Colore Esadecimale", "Hex Color - Leave empty for default color": "Colore esadecimale - Lascia vuoto per il colore predefinito", "Hide": "Nascondi", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Per allegare la base di conoscenza qui, aggiungili prima allo spazio di lavoro \"Conoscenza\".", "To learn more about available endpoints, visit our documentation.": "Per saperne di più sugli endpoint disponibili, visita la nostra documentazione.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Per proteggere la tua privacy, solo le valutazioni, gli ID dei modelli, i tag e i metadati vengono condivisi dal tuo feedback: i registri della chat rimangono privati e non sono inclusi.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Per selezionare i toolkit qui, aggiungili prima allo spazio di lavoro \"Strumenti\".", "Toast notifications for new updates": "Notifiche toast per nuovi aggiornamenti", "Today": "Oggi", diff --git a/src/lib/i18n/locales/ja-JP/translation.json b/src/lib/i18n/locales/ja-JP/translation.json index b878f072c6..6bcde89795 100644 --- a/src/lib/i18n/locales/ja-JP/translation.json +++ b/src/lib/i18n/locales/ja-JP/translation.json @@ -886,7 +886,6 @@ "Height": "高さ", "Hello, {{name}}": "こんにちは、{{name}} さん", "Help": "ヘルプ", - "Help us create the best community leaderboard by sharing your feedback history!": "フィードバック履歴を共有して、最高のコミュニティリーダーボードの作成を手伝ってください!", "Hex Color": "16進数の色", "Hex Color - Leave empty for default color": "16進数の色 - デフォルトの色を使用する場合は空白のままにします", "Hide": "非表示", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "ここにナレッジベースを追加するには、まず \"Knowledge\" ワークスペースに追加してください。", "To learn more about available endpoints, visit our documentation.": "利用可能なエンドポイントについては、ドキュメントを参照してください。", "To learn more about powerful prompt variables, click here": "プロンプト変数についてさらに詳しく知るには、ここをクリックしてください", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "プライバシーを保護するため、評価、モデル ID、タグ、およびメタデータのみがフィードバックから共有されます。— チャットログはプライバシーを保護され、含まれません。", "To select toolkits here, add them to the \"Tools\" workspace first.": "ここでツールキットを選択するには、まず \"Tools\" ワークスペースに追加してください。", "Toast notifications for new updates": "新しい更新のトースト通知", "Today": "今日", diff --git a/src/lib/i18n/locales/ka-GE/translation.json b/src/lib/i18n/locales/ka-GE/translation.json index b063916715..15980356b6 100644 --- a/src/lib/i18n/locales/ka-GE/translation.json +++ b/src/lib/i18n/locales/ka-GE/translation.json @@ -886,7 +886,6 @@ "Height": "სიმაღლე", "Hello, {{name}}": "გამარჯობა, {{name}}", "Help": "დახმარება", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "თექვსმეტობითი ფერი", "Hex Color - Leave empty for default color": "", "Hide": "დამალვა", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "დღეს", diff --git a/src/lib/i18n/locales/kab-DZ/translation.json b/src/lib/i18n/locales/kab-DZ/translation.json index 4e6ffa9c72..77337c3c0c 100644 --- a/src/lib/i18n/locales/kab-DZ/translation.json +++ b/src/lib/i18n/locales/kab-DZ/translation.json @@ -886,7 +886,6 @@ "Height": "Teɣzi", "Hello, {{name}}": "Azul a {{name}}", "Help": "Tallalt", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "Ini Hex", "Hex Color - Leave empty for default color": "", "Hide": "Seggelmes", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Akken ad teqqneḍ taffa n tmessunin da, rnu-tent ɣer \"Timessunin\" n temnaḍṭ n umahil, di tazwara.", "To learn more about available endpoints, visit our documentation.": "Akken ad tissineḍ ugar ɣef wagazen n taggara yellan, rzu ɣer warrat-nneɣ.", "To learn more about powerful prompt variables, click here": "I wakken ad tissineḍ ugar ɣef yimuttiyen n ineftaɣen iǧehden, sit da", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Akken ad tḥerzeḍ tudert-ik tabaḍnit, ala ṭṭubbat, isulayen n tmudemt, tibzimin, akked metadata ttwabḍant ɣef tikti-k — iɣmisen-ik n udiwenni qqimen d usligen, ur d-ddan ara.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Akken ad tferneḍ ifecka da, rnu-ten, di tazwara, ɣer tallunt n umahil \"Ifecka\".", "Toast notifications for new updates": "Ssurfet ilɣa i yileqman imaynuten", "Today": "Ass-a", diff --git a/src/lib/i18n/locales/ko-KR/translation.json b/src/lib/i18n/locales/ko-KR/translation.json index 327af7772c..24162115e4 100644 --- a/src/lib/i18n/locales/ko-KR/translation.json +++ b/src/lib/i18n/locales/ko-KR/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "안녕하세요, {{name}}", "Help": "도움말", - "Help us create the best community leaderboard by sharing your feedback history!": "당신의 피드백 기록을 공유함으로서 최고의 커뮤니티 리더보드를 만드는데 도와주세요!", "Hex Color": "Hex 색상", "Hex Color - Leave empty for default color": "Hex 색상 - 기본 색상의 경우 빈 상태로 유지", "Hide": "숨기기", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "지식 기반을 여기에 첨부하려면. \"지식 기반\" 워크스페이스에 먼저 추가하세요", "To learn more about available endpoints, visit our documentation.": "사용 가능한 엔드포인트에 대해 자세히 알아보려면 문서를 방문하세요.", "To learn more about powerful prompt variables, click here": "강력한 프롬프트 변수에 대해 자세히 알아보려면 여기를 클릭하세요.", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "개인정보를 보호하기 위해, 당신의 채팅 로그는 비공개로 유지되고, 오직 당신의 피드백에서 평가, 모델 ID, 태그, 그리고 메타데이타만 공유됩니다", "To select toolkits here, add them to the \"Tools\" workspace first.": "여기서 도구를 선택하려면, \"도구\" 워크스페이스에 먼저 추가하세요.", "Toast notifications for new updates": "새 업데이트 알림", "Today": "오늘", diff --git a/src/lib/i18n/locales/lt-LT/translation.json b/src/lib/i18n/locales/lt-LT/translation.json index 60514221c5..a7f82db415 100644 --- a/src/lib/i18n/locales/lt-LT/translation.json +++ b/src/lib/i18n/locales/lt-LT/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Sveiki, {{name}}", "Help": "Pagalba", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Paslėpti", @@ -1714,7 +1713,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "Norėdami pasirinkti įrankius, pirmiausia pridėkite juos prie įrankių nuostatuose", "Toast notifications for new updates": "", "Today": "Šiandien", diff --git a/src/lib/i18n/locales/ms-MY/translation.json b/src/lib/i18n/locales/ms-MY/translation.json index d56e487335..8999c5dc68 100644 --- a/src/lib/i18n/locales/ms-MY/translation.json +++ b/src/lib/i18n/locales/ms-MY/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Hello, {{name}}", "Help": "Bantuan", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Sembunyi", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "Untuk memilih kit alatan di sini, tambahkannya pada ruang kerja \"Tools\" dahulu.", "Toast notifications for new updates": "", "Today": "Hari Ini", diff --git a/src/lib/i18n/locales/nb-NO/translation.json b/src/lib/i18n/locales/nb-NO/translation.json index 8eaf0e0875..014d7aad3f 100644 --- a/src/lib/i18n/locales/nb-NO/translation.json +++ b/src/lib/i18n/locales/nb-NO/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Hei, {{name}}!", "Help": "Hjelp", - "Help us create the best community leaderboard by sharing your feedback history!": "Hjelp oss med å skape den beste fellesskapsledertavlen ved å dele tilbakemeldingshistorikken din.", "Hex Color": "Hex-farge", "Hex Color - Leave empty for default color": "Hex-farge – la stå tom for standard farge", "Hide": "Skjul", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Hvis du vil legge til kunnskapsbaser her, må du først legge dem til i arbeidsområdet \"Kunnskap\".", "To learn more about available endpoints, visit our documentation.": "Hvis du vil finne ut mer om tilgjengelige endepunkter, kan du gå til dokumentasjonen vår.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "For å beskytte personvernet ditt deles bare vurderinger, modell-ID-er, etiketter og metadata fra dine tilbakemeldinger. Chattelogger forblir private og inkluderes ikke.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Hvis du vil velge verktøysett her, må du først legge dem til i arbeidsområdet \"Verktøy\".", "Toast notifications for new updates": "Hurtigmelding-notifikasjon for nye oppdateringer", "Today": "I dag", diff --git a/src/lib/i18n/locales/nl-NL/translation.json b/src/lib/i18n/locales/nl-NL/translation.json index dab860d6e0..ed3f52573f 100644 --- a/src/lib/i18n/locales/nl-NL/translation.json +++ b/src/lib/i18n/locales/nl-NL/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Hallo, {{name}}", "Help": "Help", - "Help us create the best community leaderboard by sharing your feedback history!": "Help ons het beste community leaderboard te maken door je feedbackgeschiedenis te delen!", "Hex Color": "Hex-kleur", "Hex Color - Leave empty for default color": "Hex-kleur - laat leeg voor standaardkleur", "Hide": "Verberg", @@ -1712,7 +1711,6 @@ "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 learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Om je privacy te beschermen, worden alleen beoordelingen, model-ID's, tags en metadata van je feedback gedeeld - je chatlogs blijven privé en worden niet opgenomen.", "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", diff --git a/src/lib/i18n/locales/pa-IN/translation.json b/src/lib/i18n/locales/pa-IN/translation.json index 6fbb1b0546..1bdf0ec1dc 100644 --- a/src/lib/i18n/locales/pa-IN/translation.json +++ b/src/lib/i18n/locales/pa-IN/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "ਸਤ ਸ੍ਰੀ ਅਕਾਲ, {{name}}", "Help": "ਮਦਦ", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "ਲੁਕਾਓ", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "ਅੱਜ", diff --git a/src/lib/i18n/locales/pl-PL/translation.json b/src/lib/i18n/locales/pl-PL/translation.json index 4f0b0c8987..213d1cab5a 100644 --- a/src/lib/i18n/locales/pl-PL/translation.json +++ b/src/lib/i18n/locales/pl-PL/translation.json @@ -886,7 +886,6 @@ "Height": "Wysokość", "Hello, {{name}}": "Witaj, {{name}}", "Help": "Pomoc", - "Help us create the best community leaderboard by sharing your feedback history!": "Pomóż nam tworzyć ranking społeczności, udostępniając historię swoich opinii!", "Hex Color": "Kolor Hex", "Hex Color - Leave empty for default color": "Kolor Hex - zostaw puste dla domyślnego", "Hide": "Ukryj", @@ -1714,7 +1713,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Aby dołączyć Bazę wiedzy, dodaj ją najpierw w obszarze \"Knowledge\".", "To learn more about available endpoints, visit our documentation.": "Odwiedź dokumentację, aby poznać dostępne endpointy.", "To learn more about powerful prompt variables, click here": "Kliknij tutaj, aby poznać zmienne promptów", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Chronimy Twoją prywatność: udostępniane są tylko oceny i metadane, treść czatu pozostaje prywatna.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Aby wybrać narzędzia, dodaj je najpierw w obszarze \"Narzędzia\".", "Toast notifications for new updates": "Powiadomienia o aktualizacjach", "Today": "Dzisiaj", diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index af9b49dd12..550f3b8dbc 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -886,7 +886,6 @@ "Height": "Altura", "Hello, {{name}}": "Olá, {{name}}", "Help": "Ajuda", - "Help us create the best community leaderboard by sharing your feedback history!": "Ajude-nos a criar o melhor ranking da comunidade compartilhando sua historia de comentários!", "Hex Color": "Cor hexadecimal", "Hex Color - Leave empty for default color": "Cor Hexadecimal - Deixe em branco para a cor padrão", "Hide": "Ocultar", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Para anexar a base de conhecimento aqui, adicione-os ao espaço de trabalho \"Conhecimento\" primeiro.", "To learn more about available endpoints, visit our documentation.": "Para saber mais sobre os endpoints disponíveis, visite nossa documentação.", "To learn more about powerful prompt variables, click here": "Para saber mais sobre variáveis de prompt poderosas, clique aqui", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Para proteger sua privacidade, apenas classificações, IDs de modelo, tags e metadados são compartilhados a partir de seus comentários – seus registros de bate-papo permanecem privados e não são incluídos.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Para selecionar kits de ferramentas aqui, adicione-os ao espaço de trabalho \"Ferramentas\" primeiro.", "Toast notifications for new updates": "Notificações de alerta para novas atualizações", "Today": "Hoje", diff --git a/src/lib/i18n/locales/pt-PT/translation.json b/src/lib/i18n/locales/pt-PT/translation.json index 7bc804fef5..97abe8c3e5 100644 --- a/src/lib/i18n/locales/pt-PT/translation.json +++ b/src/lib/i18n/locales/pt-PT/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Olá, {{name}}", "Help": "Ajuda", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Ocultar", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "Hoje", diff --git a/src/lib/i18n/locales/ro-RO/translation.json b/src/lib/i18n/locales/ro-RO/translation.json index 697e344a84..b793b49a80 100644 --- a/src/lib/i18n/locales/ro-RO/translation.json +++ b/src/lib/i18n/locales/ro-RO/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Salut, {{name}}", "Help": "Ajutor", - "Help us create the best community leaderboard by sharing your feedback history!": "Ajută-ne să creăm cel mai bun clasament al comunității împărtășind istoricul tău de feedback!", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Ascunde", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Pentru a atașa baza de cunoștințe aici, adăugați-o mai întâi în spațiul de lucru \"Knowledge\".", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Pentru a vă proteja confidențialitatea, doar evaluările, ID-urile modelelor, etichetele și metadatele sunt partajate din feedback-ul dumneavoastră—jurnalele de chat rămân private și nu sunt incluse.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Pentru a selecta kiturile de instrumente aici, adăugați-le mai întâi în spațiul de lucru \"Instrumente\".", "Toast notifications for new updates": "Notificări toast pentru actualizări noi", "Today": "Astăzi", diff --git a/src/lib/i18n/locales/ru-RU/translation.json b/src/lib/i18n/locales/ru-RU/translation.json index 3285fbee40..a51c01eb29 100644 --- a/src/lib/i18n/locales/ru-RU/translation.json +++ b/src/lib/i18n/locales/ru-RU/translation.json @@ -886,7 +886,6 @@ "Height": "Высота", "Hello, {{name}}": "Привет, {{name}}", "Help": "Помощь", - "Help us create the best community leaderboard by sharing your feedback history!": "Помогите нам создать лучшую таблицу лидеров сообщества, поделившись историей своих отзывов!", "Hex Color": "Цвет Hex", "Hex Color - Leave empty for default color": "Цвет Hex - оставьте пустым значение цвета по умолчанию", "Hide": "Скрыть", @@ -1714,7 +1713,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Чтобы прикрепить сюда базу знаний, сначала добавьте её в \"Знания\" рабочего пространства.", "To learn more about available endpoints, visit our documentation.": "Чтобы узнать больше о доступных энд-поинтах, ознакомьтесь с нашей документацией.", "To learn more about powerful prompt variables, click here": "Чтобы узнать больше о мощных переменных промпта, нажмите сюда", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Чтобы защитить вашу конфиденциальность, из ваших отзывов публикуются только оценки, идентификаторы моделей, теги и метаданные — ваши журналы чата остаются конфиденциальными и не публикуются.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Чтобы выбрать инструменты, сначала добавьте их в \"Инструменты\" рабочего пространства.", "Toast notifications for new updates": "Уведомления о обновлениях", "Today": "Сегодня", diff --git a/src/lib/i18n/locales/sk-SK/translation.json b/src/lib/i18n/locales/sk-SK/translation.json index 560e3cca0a..36754d6ed0 100644 --- a/src/lib/i18n/locales/sk-SK/translation.json +++ b/src/lib/i18n/locales/sk-SK/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Ahoj, {{name}}", "Help": "Pomoc", - "Help us create the best community leaderboard by sharing your feedback history!": "Pomôžte nám vytvoriť najlepší komunitný rebríček zdieľaním histórie vašej spätnej väzby!", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Skryť", @@ -1714,7 +1713,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Ak chcete tu pripojiť znalostnú databázu, najprv ju pridajte do pracovného priestoru \"Knowledge\".", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Na ochranu vášho súkromia sú z vašej spätnej väzby zdieľané iba hodnotenia, ID modelov, značky a metadáta – vaše záznamy chatu zostávajú súkromné a nie sú zahrnuté.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Ak chcete tu vybrať nástroje, pridajte ich najprv do pracovného priestoru \"Tools\".", "Toast notifications for new updates": "Oznámenia vo forme toastov pre nové aktualizácie", "Today": "Dnes", diff --git a/src/lib/i18n/locales/sr-RS/translation.json b/src/lib/i18n/locales/sr-RS/translation.json index e2d48b524c..f9d9c95248 100644 --- a/src/lib/i18n/locales/sr-RS/translation.json +++ b/src/lib/i18n/locales/sr-RS/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Здраво, {{name}}", "Help": "Помоћ", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "Хекс боја", "Hex Color - Leave empty for default color": "Хекс боја (празно за подразумевано)", "Hide": "Сакриј", @@ -1713,7 +1712,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "Тост-обавештења за нове исправке", "Today": "Данас", diff --git a/src/lib/i18n/locales/sv-SE/translation.json b/src/lib/i18n/locales/sv-SE/translation.json index 51aecae427..9bb111835f 100644 --- a/src/lib/i18n/locales/sv-SE/translation.json +++ b/src/lib/i18n/locales/sv-SE/translation.json @@ -886,7 +886,6 @@ "Height": "Höjd", "Hello, {{name}}": "Hej, {{name}}", "Help": "Hjälp", - "Help us create the best community leaderboard by sharing your feedback history!": "Hjälp oss att skapa den bästa community-topplistan genom att dela din feedbackhistorik!", "Hex Color": "Hexfärg", "Hex Color - Leave empty for default color": "Hexfärg - Lämna tomt för standardfärg", "Hide": "Dölj", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "För att bifoga kunskapsbas här, lägg till dem i arbetsytan \"Kunskap\" först.", "To learn more about available endpoints, visit our documentation.": "För att lära dig mer om tillgängliga endpoints, besök vår dokumentation", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "För att skydda din integritet delas endast betyg, modell-ID:n, taggar och metadata från din feedback - dina chattloggar förblir privata och skickas inte med.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Om du vill välja verktygslådor här måste du först lägga till dem i arbetsytan \"Verktyg\".", "Toast notifications for new updates": "Toast-aviseringar för nya uppdateringar", "Today": "Idag", diff --git a/src/lib/i18n/locales/th-TH/translation.json b/src/lib/i18n/locales/th-TH/translation.json index 145dbd12ee..2143ce164d 100644 --- a/src/lib/i18n/locales/th-TH/translation.json +++ b/src/lib/i18n/locales/th-TH/translation.json @@ -886,7 +886,6 @@ "Height": "ความสูง", "Hello, {{name}}": "สวัสดี {{name}}", "Help": "ช่วยเหลือ", - "Help us create the best community leaderboard by sharing your feedback history!": "ช่วยเราสร้างกระดานจัดอันดับชุมชนที่ดีที่สุดด้วยการแชร์ประวัติคำติชมของคุณ!", "Hex Color": "ค่าสี Hex", "Hex Color - Leave empty for default color": "สี Hex - เว้นว่างไว้เพื่อใช้ค่าสีเริ่มต้น", "Hide": "ซ่อน", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "หากต้องการแนบฐานความรู้ที่นี่ โปรดเพิ่มไปที่ Workspace \"Knowledge\" ก่อน", "To learn more about available endpoints, visit our documentation.": "หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ Endpoints ที่มีอยู่ โปรดดูที่เอกสารของเรา", "To learn more about powerful prompt variables, click here": "หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับตัวแปรพรอมต์ที่ทรงพลัง คลิกที่นี่", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "เพื่อปกป้องความเป็นส่วนตัวของคุณ จะมีการส่งต่อเฉพาะคะแนน ID โมเดล แท็ก และเมทาดาทาจากความคิดเห็นของคุณเท่านั้น โดยบันทึกการแชทของคุณจะยังเป็นความลับและจะไม่ถูกรวมไปด้วย", "To select toolkits here, add them to the \"Tools\" workspace first.": "ในการเลือกชุดเครื่องมือที่นี่ ให้เพิ่มไปยังพื้นที่ทำงาน \"Tools\" ก่อน", "Toast notifications for new updates": "การแจ้งเตือนแบบ Toast สำหรับอัปเดตใหม่", "Today": "วันนี้", diff --git a/src/lib/i18n/locales/tk-TM/translation.json b/src/lib/i18n/locales/tk-TM/translation.json index ddb5fb6dca..9ac6e6251c 100644 --- a/src/lib/i18n/locales/tk-TM/translation.json +++ b/src/lib/i18n/locales/tk-TM/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "", "Help": "Kömek", - "Help us create the best community leaderboard by sharing your feedback history!": "", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Gizle", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "", "Toast notifications for new updates": "", "Today": "Şu gün", diff --git a/src/lib/i18n/locales/tr-TR/translation.json b/src/lib/i18n/locales/tr-TR/translation.json index 7e41581a3a..e5d7326822 100644 --- a/src/lib/i18n/locales/tr-TR/translation.json +++ b/src/lib/i18n/locales/tr-TR/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Merhaba, {{name}}", "Help": "Yardım", - "Help us create the best community leaderboard by sharing your feedback history!": "En iyi topluluk lider tablosunu oluşturmamıza yardımcı olun, geri bildirim geçmişinizi paylaşın!", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "Gizle", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Bilgi tabanını buraya eklemek için önce bunları \"Bilgi\" çalışma alanına ekleyin.", "To learn more about available endpoints, visit our documentation.": "Mevcut uç noktalar hakkında daha fazla bilgi edinmek için belgelerimize göz atın.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "", "To select toolkits here, add them to the \"Tools\" workspace first.": "Araçları burada seçmek için öncelikle bunları \"Araçlar\" çalışma alanına ekleyin.", "Toast notifications for new updates": "", "Today": "Bugün", diff --git a/src/lib/i18n/locales/ug-CN/translation.json b/src/lib/i18n/locales/ug-CN/translation.json index e73a90aa27..c0ebe2ceab 100644 --- a/src/lib/i18n/locales/ug-CN/translation.json +++ b/src/lib/i18n/locales/ug-CN/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "ياخشىمۇسىز، {{name}}", "Help": "ياردەم", - "Help us create the best community leaderboard by sharing your feedback history!": "تەكلىپ-پىكىرلىرىڭىزنى ئورتاقلىشىش ئارقىلىق ئەڭ ياخشى مەھەللە رەھبەرلىك تاختىسى قۇرۇشىمىزغا ياردەم قىلىڭ!", "Hex Color": "Hex رەڭ", "Hex Color - Leave empty for default color": "Hex رەڭ - كۆڭۈلدىكى رەڭ ئۈچۈن بوش قالدۇرۇڭ", "Hide": "يوشۇرۇش", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "بۇ يەرگە بىلىم ئاساسى ئۇلاش ئۈچۈن ئالدى بىلەن \"بىلىم\" ئىشخانىغا قوشۇڭ.", "To learn more about available endpoints, visit our documentation.": "ئىشلىتىشكە بولىدىغان ئۇلانمىلار ھەققىدە تېخىمۇ كۆپ بىلىش ئۈچۈن قوللانمىمىزغا قاراڭ.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "شەخسىيلىقىڭىزنى قوغداش ئۈچۈن، پەقەت باھا، مودېل ID، تەغ ۋە مېتا ئۇچۇرلىرىلا باشقىلارغا ھەمبەھىرلىنىدۇ؛ سۆھبەت خاتىرىسىڭىز شەخسىي بولۇپ قالىدۇ.", "To select toolkits here, add them to the \"Tools\" workspace first.": "بۇ يەردىن قورال تاللاش ئۈچۈن ئالدى بىلەن \"قورال\" ئىشخانىغا قوشۇڭ.", "Toast notifications for new updates": "يېڭىلىق ئۇقتۇرۇشى (toast)", "Today": "بۈگۈن", diff --git a/src/lib/i18n/locales/uk-UA/translation.json b/src/lib/i18n/locales/uk-UA/translation.json index 4d6fcec735..3d16ce0489 100644 --- a/src/lib/i18n/locales/uk-UA/translation.json +++ b/src/lib/i18n/locales/uk-UA/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Привіт, {{name}}", "Help": "Допоможіть", - "Help us create the best community leaderboard by sharing your feedback history!": "Допоможіть нам створити найкращу таблицю лідерів спільноти, поділившись історією своїх відгуків!", "Hex Color": "Шістнадцятковий колір", "Hex Color - Leave empty for default color": "Шістнадцятковий колір — залиште порожнім для кольору за замовчуванням", "Hide": "Приховати", @@ -1714,7 +1713,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Щоб прикріпити базу знань тут, спочатку додайте їх до робочого простору \"Знання\".", "To learn more about available endpoints, visit our documentation.": "Щоб дізнатися більше про доступні кінцеві точки, відвідайте нашу документацію.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Для захисту вашої конфіденційності з вашими відгуками діляться лише оцінками, ID моделей, тегами та метаданими — ваші журнали чату залишаються приватними і не включаються.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Щоб обрати тут набори інструментів, спочатку додайте їх до робочої області \"Інструменти\".", "Toast notifications for new updates": "Сповіщення Toast про нові оновлення", "Today": "Сьогодні", diff --git a/src/lib/i18n/locales/ur-PK/translation.json b/src/lib/i18n/locales/ur-PK/translation.json index e002ba2471..4ea9186f9b 100644 --- a/src/lib/i18n/locales/ur-PK/translation.json +++ b/src/lib/i18n/locales/ur-PK/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "ہیلو، {{name}}", "Help": "مدد", - "Help us create the best community leaderboard by sharing your feedback history!": "ہمیں بہترین کمیونٹی لیڈر بورڈ بنانے میں مدد کریں، اپنی رائے کی تاریخ شیئر کر کے!", "Hex Color": "", "Hex Color - Leave empty for default color": "", "Hide": "چھپائیں", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "یہاں معلوماتی بنیاد منسلک کرنے کے لیے، پہلے انہیں \"معلومات\" ورک اسپیس میں شامل کریں", "To learn more about available endpoints, visit our documentation.": "", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "آپ کی رازداری کے تحفظ کے لئے، صرف درجہ بندی، ماڈل IDs، ٹیگز، اور میٹا ڈیٹا آپ کے فیڈ بیک سے شیئر کیے جاتے ہیں - آپ کی چیٹ کی تفصیلات نجی رہتی ہیں اور شامل نہیں کی جاتیں ", "To select toolkits here, add them to the \"Tools\" workspace first.": "یہاں ٹول کٹس منتخب کرنے کے لیے، پہلے انہیں \"ٹولز\" ورک اسپیس میں شامل کریں", "Toast notifications for new updates": "نئے اپڈیٹس کے لئے ٹوسٹ نوٹیفیکیشنز", "Today": "آج", diff --git a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json index b5a169355d..0f7305316f 100644 --- a/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json +++ b/src/lib/i18n/locales/uz-Cyrl-UZ/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Салом, {{name}}", "Help": "Ёрдам", - "Help us create the best community leaderboard by sharing your feedback history!": "Фикр-мулоҳазаларингиз тарихини баҳам кўриш орқали энг яхши ҳамжамият етакчилари жадвалини яратишга ёрдам беринг!", "Hex Color": "Олти бурчакли ранг", "Hex Color - Leave empty for default color": "Ҳех Cолор - стандарт ранг учун бўш қолдиринг", "Hide": "Яшириш", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Бу ерда билимлар базасини бириктириш учун аввал уларни “Билим” иш майдонига қўшинг.", "To learn more about available endpoints, visit our documentation.": "Мавжуд сўнгги нуқталар ҳақида кўпроқ билиш учун ҳужжатларимизга ташриф буюринг.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Махфийлигингизни ҳимоя қилиш учун фикр-мулоҳазаларингиздан фақат рейтинглар, модел идентификаторлари, теглар ва мета-маълумотлар баҳам кўрилади — чат журналларингиз шахсий бўлиб қолади ва уларга киритилмайди.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Бу ерда асбоблар тўпламини танлаш учун аввал уларни “Асбоблар” иш майдонига қўшинг.", "Toast notifications for new updates": "Янги янгиланишлар ҳақида билдиришномалар", "Today": "Бугун", diff --git a/src/lib/i18n/locales/uz-Latn-Uz/translation.json b/src/lib/i18n/locales/uz-Latn-Uz/translation.json index 470b3b111d..73bb2d6558 100644 --- a/src/lib/i18n/locales/uz-Latn-Uz/translation.json +++ b/src/lib/i18n/locales/uz-Latn-Uz/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Salom, {{name}}", "Help": "Yordam", - "Help us create the best community leaderboard by sharing your feedback history!": "Fikr-mulohazalaringiz tarixini baham ko‘rish orqali eng yaxshi hamjamiyat yetakchilari jadvalini yaratishga yordam bering!", "Hex Color": "Olti burchakli rang", "Hex Color - Leave empty for default color": "Hex Color - standart rang uchun bo'sh qoldiring", "Hide": "Yashirish", @@ -1712,7 +1711,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Bu yerda bilimlar bazasini biriktirish uchun avval ularni “Bilim” ish maydoniga qo‘shing.", "To learn more about available endpoints, visit our documentation.": "Mavjud so'nggi nuqtalar haqida ko'proq bilish uchun hujjatlarimizga tashrif buyuring.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Maxfiyligingizni himoya qilish uchun fikr-mulohazalaringizdan faqat reytinglar, model identifikatorlari, teglar va meta-maʼlumotlar baham koʻriladi — chat jurnallaringiz shaxsiy boʻlib qoladi va ularga kiritilmaydi.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Bu yerda asboblar to‘plamini tanlash uchun avval ularni “Asboblar” ish maydoniga qo‘shing.", "Toast notifications for new updates": "Yangi yangilanishlar haqida bildirishnomalar", "Today": "Bugun", diff --git a/src/lib/i18n/locales/vi-VN/translation.json b/src/lib/i18n/locales/vi-VN/translation.json index c12453f312..18c98c7efe 100644 --- a/src/lib/i18n/locales/vi-VN/translation.json +++ b/src/lib/i18n/locales/vi-VN/translation.json @@ -886,7 +886,6 @@ "Height": "", "Hello, {{name}}": "Xin chào {{name}}", "Help": "Trợ giúp", - "Help us create the best community leaderboard by sharing your feedback history!": "Giúp chúng tôi tạo bảng xếp hạng cộng đồng tốt nhất bằng cách chia sẻ lịch sử phản hồi của bạn!", "Hex Color": "Màu Hex", "Hex Color - Leave empty for default color": "Màu Hex - Để trống để dùng màu mặc định", "Hide": "Ẩn", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "Để đính kèm cơ sở kiến thức tại đây, trước tiên hãy thêm chúng vào không gian làm việc \"Kiến thức\".", "To learn more about available endpoints, visit our documentation.": "Để tìm hiểu thêm về các điểm cuối có sẵn, hãy truy cập tài liệu của chúng tôi.", "To learn more about powerful prompt variables, click here": "", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "Để bảo vệ quyền riêng tư của bạn, chỉ có xếp hạng, ID mô hình, thẻ và siêu dữ liệu được chia sẻ từ phản hồi của bạn—nhật ký trò chuyện của bạn vẫn ở chế độ riêng tư và không được bao gồm.", "To select toolkits here, add them to the \"Tools\" workspace first.": "Để chọn các tookits, bạn phải thêm chúng vào workspace \"Tools\" trước.", "Toast notifications for new updates": "Thông báo nhanh cho các cập nhật mới", "Today": "Hôm nay", diff --git a/src/lib/i18n/locales/zh-CN/translation.json b/src/lib/i18n/locales/zh-CN/translation.json index c43816db43..8a5fee37ab 100644 --- a/src/lib/i18n/locales/zh-CN/translation.json +++ b/src/lib/i18n/locales/zh-CN/translation.json @@ -886,7 +886,6 @@ "Height": "高度", "Hello, {{name}}": "您好,{{name}}", "Help": "帮助", - "Help us create the best community leaderboard by sharing your feedback history!": "分享您的反馈历史记录,共建最佳模型社区排行榜!", "Hex Color": "十六进制颜色代码", "Hex Color - Leave empty for default color": "十六进制颜色代码 - 留空使用默认颜色", "Hide": "隐藏", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "如需在此处附加知识库,请先将其添加到工作空间中的“知识库”中", "To learn more about available endpoints, visit our documentation.": "如需了解更多关于可用端点的信息,请访问我们的文档", "To learn more about powerful prompt variables, click here": "如需了解更多关于强大的提示词变量的信息,请点击此处", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "为了保护您的隐私,只有评分、模型 ID、标签和元数据会从您的反馈中分享——您的对话记录将保持私密,不会被包含在内。", "To select toolkits here, add them to the \"Tools\" workspace first.": "如需在这里选择工具包,请先将其添加到工作空间中的“工具”", "Toast notifications for new updates": "检测到新版本时显示更新通知", "Today": "今天", diff --git a/src/lib/i18n/locales/zh-TW/translation.json b/src/lib/i18n/locales/zh-TW/translation.json index f06b4d6c8f..5331509efb 100644 --- a/src/lib/i18n/locales/zh-TW/translation.json +++ b/src/lib/i18n/locales/zh-TW/translation.json @@ -886,7 +886,6 @@ "Height": "高度", "Hello, {{name}}": "您好,{{name}}", "Help": "說明", - "Help us create the best community leaderboard by sharing your feedback history!": "透過分享您的回饋歷史,幫助我們建立最佳的社群排行榜!", "Hex Color": "Hex 顔色", "Hex Color - Leave empty for default color": "Hex 顔色 —— 留空以使用預設顔色", "Hide": "隱藏", @@ -1711,7 +1710,6 @@ "To attach knowledge base here, add them to the \"Knowledge\" workspace first.": "若要在此處附加知識庫,請先將它們新增到「知識」工作區。", "To learn more about available endpoints, visit our documentation.": "若要進一步了解可用的端點,請參閱我們的檔案。", "To learn more about powerful prompt variables, click here": "要了解更多關於強大的提示詞變數的資訊,請點擊此處", - "To protect your privacy, only ratings, model IDs, tags, and metadata are shared from your feedback—your chat logs remain private and are not included.": "為了保護您的隱私,只會分享您回饋中的評分、模型 ID、標籤和中繼資料 —— 您的對話紀錄仍然是私密的,不會被包含在內。", "To select toolkits here, add them to the \"Tools\" workspace first.": "若要在此選擇工具包,請先將它們新增到「工具」工作區。", "Toast notifications for new updates": "快顯通知新的更新", "Today": "今天", From 3c986adeda2efa9b6f4b4f62acb43fd4e573ad7e Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 22:21:00 +0400 Subject: [PATCH 214/254] enh: kb metadata search --- .../open_webui/retrieval/vector/dbs/chroma.py | 3 +- .../retrieval/vector/dbs/elasticsearch.py | 2 +- .../open_webui/retrieval/vector/dbs/milvus.py | 2 +- .../vector/dbs/milvus_multitenancy.py | 2 +- .../retrieval/vector/dbs/opengauss.py | 3 +- .../retrieval/vector/dbs/opensearch.py | 2 +- .../retrieval/vector/dbs/oracle23ai.py | 2 +- .../retrieval/vector/dbs/pgvector.py | 36 +++++- .../retrieval/vector/dbs/pinecone.py | 2 +- .../open_webui/retrieval/vector/dbs/qdrant.py | 2 +- .../vector/dbs/qdrant_multitenancy.py | 2 +- .../retrieval/vector/dbs/s3vector.py | 2 +- .../retrieval/vector/dbs/weaviate.py | 2 +- backend/open_webui/retrieval/vector/main.py | 6 +- backend/open_webui/routers/knowledge.py | 90 +++++++++++++++ backend/open_webui/tools/builtin.py | 105 +++++++++++++++++- backend/open_webui/utils/middleware.py | 6 +- backend/open_webui/utils/tools.py | 14 ++- 18 files changed, 257 insertions(+), 26 deletions(-) diff --git a/backend/open_webui/retrieval/vector/dbs/chroma.py b/backend/open_webui/retrieval/vector/dbs/chroma.py index 69d894afde..67268e9dca 100755 --- a/backend/open_webui/retrieval/vector/dbs/chroma.py +++ b/backend/open_webui/retrieval/vector/dbs/chroma.py @@ -69,7 +69,7 @@ class ChromaClient(VectorDBBase): return self.client.delete_collection(name=collection_name) def search( - self, collection_name: str, vectors: list[list[float | int]], limit: int + self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: # Search for the nearest neighbor items based on the vectors and return 'limit' number of results. try: @@ -78,6 +78,7 @@ class ChromaClient(VectorDBBase): result = collection.query( query_embeddings=vectors, n_results=limit, + where=filter, ) # chromadb has cosine distance, 2 (worst) -> 0 (best). Re-odering to 0 -> 1 diff --git a/backend/open_webui/retrieval/vector/dbs/elasticsearch.py b/backend/open_webui/retrieval/vector/dbs/elasticsearch.py index 6de0d859f8..46cd1ad920 100644 --- a/backend/open_webui/retrieval/vector/dbs/elasticsearch.py +++ b/backend/open_webui/retrieval/vector/dbs/elasticsearch.py @@ -153,7 +153,7 @@ class ElasticsearchClient(VectorDBBase): # Status: works def search( - self, collection_name: str, vectors: list[list[float]], limit: int + self, collection_name: str, vectors: list[list[float]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: query = { "size": limit, diff --git a/backend/open_webui/retrieval/vector/dbs/milvus.py b/backend/open_webui/retrieval/vector/dbs/milvus.py index 23e4bbd03e..69ca3988d9 100644 --- a/backend/open_webui/retrieval/vector/dbs/milvus.py +++ b/backend/open_webui/retrieval/vector/dbs/milvus.py @@ -179,7 +179,7 @@ class MilvusClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: list[list[float | int]], limit: int + self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: # Search for the nearest neighbor items based on the vectors and return 'limit' number of results. collection_name = collection_name.replace("-", "_") diff --git a/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py b/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py index 203a36141e..5dfad33de5 100644 --- a/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py +++ b/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py @@ -157,7 +157,7 @@ class MilvusClient(VectorDBBase): collection.insert(entities) def search( - self, collection_name: str, vectors: List[List[float]], limit: int + self, collection_name: str, vectors: List[List[float]], filter: Optional[Dict] = None, limit: int = 10 ) -> Optional[SearchResult]: if not vectors: return None diff --git a/backend/open_webui/retrieval/vector/dbs/opengauss.py b/backend/open_webui/retrieval/vector/dbs/opengauss.py index 056a8a61cc..7d4f9ea092 100644 --- a/backend/open_webui/retrieval/vector/dbs/opengauss.py +++ b/backend/open_webui/retrieval/vector/dbs/opengauss.py @@ -233,7 +233,8 @@ class OpenGaussClient(VectorDBBase): self, collection_name: str, vectors: List[List[float]], - limit: Optional[int] = None, + filter: Optional[Dict[str, Any]] = None, + limit: int = 10, ) -> Optional[SearchResult]: try: if not vectors: diff --git a/backend/open_webui/retrieval/vector/dbs/opensearch.py b/backend/open_webui/retrieval/vector/dbs/opensearch.py index 2e946710e2..e6bd99b976 100644 --- a/backend/open_webui/retrieval/vector/dbs/opensearch.py +++ b/backend/open_webui/retrieval/vector/dbs/opensearch.py @@ -113,7 +113,7 @@ class OpenSearchClient(VectorDBBase): self.client.indices.delete(index=self._get_index_name(collection_name)) def search( - self, collection_name: str, vectors: list[list[float | int]], limit: int + self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: try: if not self.has_collection(collection_name): diff --git a/backend/open_webui/retrieval/vector/dbs/oracle23ai.py b/backend/open_webui/retrieval/vector/dbs/oracle23ai.py index 3f5c3463f0..db7b869439 100644 --- a/backend/open_webui/retrieval/vector/dbs/oracle23ai.py +++ b/backend/open_webui/retrieval/vector/dbs/oracle23ai.py @@ -521,7 +521,7 @@ class Oracle23aiClient(VectorDBBase): raise def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int + self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: """ Search for similar vectors in the database. diff --git a/backend/open_webui/retrieval/vector/dbs/pgvector.py b/backend/open_webui/retrieval/vector/dbs/pgvector.py index b9b1dba07b..6ae09cf05f 100644 --- a/backend/open_webui/retrieval/vector/dbs/pgvector.py +++ b/backend/open_webui/retrieval/vector/dbs/pgvector.py @@ -427,7 +427,8 @@ class PgvectorClient(VectorDBBase): self, collection_name: str, vectors: List[List[float]], - limit: Optional[int] = None, + filter: Optional[Dict[str, Any]] = None, + limit: int = 10, ) -> Optional[SearchResult]: try: if not vectors: @@ -475,9 +476,40 @@ class PgvectorClient(VectorDBBase): ) # Build the lateral subquery for each query vector + where_clauses = [DocumentChunk.collection_name == collection_name] + + # Apply metadata filter if provided + if filter: + for key, value in filter.items(): + if isinstance(value, dict) and "$in" in value: + # Handle $in operator: {"field": {"$in": [values]}} + in_values = value["$in"] + if PGVECTOR_PGCRYPTO: + where_clauses.append( + pgcrypto_decrypt( + DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB + )[key].astext.in_([str(v) for v in in_values]) + ) + else: + where_clauses.append( + DocumentChunk.vmetadata[key].astext.in_([str(v) for v in in_values]) + ) + else: + # Handle simple equality: {"field": "value"} + if PGVECTOR_PGCRYPTO: + where_clauses.append( + pgcrypto_decrypt( + DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB + )[key].astext == str(value) + ) + else: + where_clauses.append( + DocumentChunk.vmetadata[key].astext == str(value) + ) + subq = ( select(*result_fields) - .where(DocumentChunk.collection_name == collection_name) + .where(*where_clauses) .order_by( (DocumentChunk.vector.cosine_distance(query_vectors.c.q_vector)) ) diff --git a/backend/open_webui/retrieval/vector/dbs/pinecone.py b/backend/open_webui/retrieval/vector/dbs/pinecone.py index 94d09dabf5..22b9cb98b1 100644 --- a/backend/open_webui/retrieval/vector/dbs/pinecone.py +++ b/backend/open_webui/retrieval/vector/dbs/pinecone.py @@ -391,7 +391,7 @@ class PineconeClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int + self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: """Search for similar vectors in a collection.""" if not vectors or not vectors[0]: diff --git a/backend/open_webui/retrieval/vector/dbs/qdrant.py b/backend/open_webui/retrieval/vector/dbs/qdrant.py index ce7095bea2..efa33a681d 100644 --- a/backend/open_webui/retrieval/vector/dbs/qdrant.py +++ b/backend/open_webui/retrieval/vector/dbs/qdrant.py @@ -145,7 +145,7 @@ class QdrantClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: list[list[float | int]], limit: int + self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: # Search for the nearest neighbor items based on the vectors and return 'limit' number of results. if limit is None: diff --git a/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py b/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py index fdc8f9d897..70ec6d6068 100644 --- a/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py +++ b/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py @@ -254,7 +254,7 @@ class QdrantClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: List[List[float | int]], limit: int + self, collection_name: str, vectors: List[List[float | int]], filter: Optional[Dict] = None, limit: int = 10 ) -> Optional[SearchResult]: """ Search for the nearest neighbor items based on the vectors with tenant isolation. diff --git a/backend/open_webui/retrieval/vector/dbs/s3vector.py b/backend/open_webui/retrieval/vector/dbs/s3vector.py index 95fc5d3f24..d6784f9f26 100644 --- a/backend/open_webui/retrieval/vector/dbs/s3vector.py +++ b/backend/open_webui/retrieval/vector/dbs/s3vector.py @@ -295,7 +295,7 @@ class S3VectorClient(VectorDBBase): raise def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int + self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: """ Search for similar vectors in a collection using multiple query vectors. diff --git a/backend/open_webui/retrieval/vector/dbs/weaviate.py b/backend/open_webui/retrieval/vector/dbs/weaviate.py index 6bb8a1ecb4..680a6c9730 100644 --- a/backend/open_webui/retrieval/vector/dbs/weaviate.py +++ b/backend/open_webui/retrieval/vector/dbs/weaviate.py @@ -159,7 +159,7 @@ class WeaviateClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int + self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 ) -> Optional[SearchResult]: sane_collection_name = self._sanitize_collection_name(collection_name) if not self.client.collections.exists(sane_collection_name): diff --git a/backend/open_webui/retrieval/vector/main.py b/backend/open_webui/retrieval/vector/main.py index 53f752f579..a76fec9956 100644 --- a/backend/open_webui/retrieval/vector/main.py +++ b/backend/open_webui/retrieval/vector/main.py @@ -53,7 +53,11 @@ class VectorDBBase(ABC): @abstractmethod def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], limit: int + self, + collection_name: str, + vectors: List[List[Union[float, int]]], + filter: Optional[Dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: """Search for similar vectors in a collection.""" pass diff --git a/backend/open_webui/routers/knowledge.py b/backend/open_webui/routers/knowledge.py index c671759303..9fc30424ca 100644 --- a/backend/open_webui/routers/knowledge.py +++ b/backend/open_webui/routers/knowledge.py @@ -46,6 +46,54 @@ router = APIRouter() PAGE_ITEM_COUNT = 30 +############################ +# Knowledge Base Embedding +############################ + +KNOWLEDGE_BASES_COLLECTION = "knowledge-bases" + + +async def embed_knowledge_base_metadata( + request: Request, + knowledge_base_id: str, + name: str, + description: str, +) -> bool: + """Generate and store embedding for knowledge base.""" + try: + content = f"{name}\n\n{description}" if description else name + embedding = await request.app.state.EMBEDDING_FUNCTION(content) + VECTOR_DB_CLIENT.upsert( + collection_name=KNOWLEDGE_BASES_COLLECTION, + items=[ + { + "id": knowledge_base_id, + "text": content, + "vector": embedding, + "metadata": { + "knowledge_base_id": knowledge_base_id, + }, + } + ], + ) + return True + except Exception as e: + log.error(f"Failed to embed knowledge base {knowledge_base_id}: {e}") + return False + + +def remove_knowledge_base_metadata_embedding(knowledge_base_id: str) -> bool: + """Remove knowledge base embedding.""" + try: + VECTOR_DB_CLIENT.delete( + collection_name=KNOWLEDGE_BASES_COLLECTION, + ids=[knowledge_base_id], + ) + return True + except Exception as e: + log.debug(f"Failed to remove embedding for {knowledge_base_id}: {e}") + return False + class KnowledgeAccessResponse(KnowledgeUserResponse): write_access: Optional[bool] = False @@ -205,6 +253,13 @@ async def create_new_knowledge( knowledge = Knowledges.insert_new_knowledge(user.id, form_data, db=db) if knowledge: + # Embed knowledge base for semantic search + await embed_knowledge_base_metadata( + request, + knowledge.id, + knowledge.name, + knowledge.description, + ) return knowledge else: raise HTTPException( @@ -281,6 +336,30 @@ async def reindex_knowledge_files( return True +############################ +# ReindexKnowledgeBases +############################ + + +@router.post("/metadata/reindex", response_model=dict) +async def reindex_knowledge_base_metadata_embeddings( + request: Request, + user=Depends(get_admin_user), + db: Session = Depends(get_session), +): + """Batch embed all existing knowledge bases. Admin only.""" + knowledge_bases = Knowledges.get_knowledge_bases(db=db) + log.info(f"Reindexing embeddings for {len(knowledge_bases)} knowledge bases") + + success_count = 0 + for kb in knowledge_bases: + if await embed_knowledge_base_metadata(request, kb.id, kb.name, kb.description): + success_count += 1 + + log.info(f"Embedding reindex complete: {success_count}/{len(knowledge_bases)}") + return {"total": len(knowledge_bases), "success": success_count} + + ############################ # GetKnowledgeById ############################ @@ -369,6 +448,13 @@ async def update_knowledge_by_id( knowledge = Knowledges.update_knowledge_by_id(id=id, form_data=form_data, db=db) if knowledge: + # Re-embed knowledge base for semantic search + await embed_knowledge_base_metadata( + request, + knowledge.id, + knowledge.name, + knowledge.description, + ) return KnowledgeFilesResponse( **knowledge.model_dump(), files=Knowledges.get_file_metadatas_by_id(knowledge.id, db=db), @@ -718,6 +804,10 @@ async def delete_knowledge_by_id( except Exception as e: log.debug(e) pass + + # Remove knowledge base embedding + remove_knowledge_base_metadata_embedding(id) + result = Knowledges.delete_knowledge_by_id(id=id, db=db) return result diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 2f57986184..7c691f2e29 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -39,6 +39,8 @@ from open_webui.models.groups import Groups log = logging.getLogger(__name__) +MAX_KNOWLEDGE_BASE_SEARCH_ITEMS = 10_000 + # ============================================================================= # TIME UTILITIES # ============================================================================= @@ -1413,7 +1415,7 @@ async def view_knowledge_file( return json.dumps({"error": str(e)}) -async def query_knowledge_bases( +async def query_knowledge_files( query: str, knowledge_ids: Optional[list[str]] = None, count: int = 5, @@ -1422,7 +1424,7 @@ async def query_knowledge_bases( __model_knowledge__: list[dict] = None, ) -> str: """ - Search internal knowledge bases using semantic/vector search. This should be your first + Search knowledge base files using semantic/vector search. This should be your first choice for finding information before searching the web. Searches across collections (KBs), individual files, and notes that the user has access to. @@ -1558,6 +1560,105 @@ async def query_knowledge_bases( chunks = chunks[:count] return json.dumps(chunks, ensure_ascii=False) + except Exception as e: + log.exception(f"query_knowledge_files error: {e}") + return json.dumps({"error": str(e)}) + + +async def query_knowledge_bases( + query: str, + count: int = 5, + __request__: Request = None, + __user__: dict = None, +) -> str: + """ + Search knowledge bases by semantic similarity to query. + Finds KBs whose name/description match the meaning of your query. + Use this to discover relevant knowledge bases before querying their files. + + :param query: Natural language query describing what you're looking for + :param count: Maximum results (default: 5) + :return: JSON with matching KBs (id, name, description, similarity) + """ + if __request__ is None: + return json.dumps({"error": "Request context not available"}) + + if not __user__: + return json.dumps({"error": "User context not available"}) + + try: + import heapq + from open_webui.models.knowledge import Knowledges + from open_webui.routers.knowledge import KNOWLEDGE_BASES_COLLECTION + from open_webui.retrieval.vector.factory import VECTOR_DB_CLIENT + + user_id = __user__.get("id") + user_group_ids = [group.id for group in Groups.get_groups_by_member_id(user_id)] + query_embedding = await __request__.app.state.EMBEDDING_FUNCTION(query) + + # Min-heap of (distance, knowledge_base_id) - only holds top `count` results + top_results_heap = [] + seen_ids = set() + page_offset = 0 + page_size = 100 + + while True: + accessible_knowledge_bases = Knowledges.search_knowledge_bases( + user_id, + filter={"user_id": user_id, "group_ids": user_group_ids}, + skip=page_offset, + limit=page_size, + ) + + if not accessible_knowledge_bases.items: + break + + accessible_ids = [kb.id for kb in accessible_knowledge_bases.items] + + search_results = VECTOR_DB_CLIENT.search( + collection_name=KNOWLEDGE_BASES_COLLECTION, + vectors=[query_embedding], + filter={"knowledge_base_id": {"$in": accessible_ids}}, + limit=count, + ) + + if search_results and search_results.ids and search_results.ids[0]: + result_ids = search_results.ids[0] + result_distances = search_results.distances[0] if search_results.distances else [0] * len(result_ids) + + for knowledge_base_id, distance in zip(result_ids, result_distances): + if knowledge_base_id in seen_ids: + continue + seen_ids.add(knowledge_base_id) + + if len(top_results_heap) < count: + heapq.heappush(top_results_heap, (distance, knowledge_base_id)) + elif distance > top_results_heap[0][0]: + heapq.heapreplace(top_results_heap, (distance, knowledge_base_id)) + + page_offset += page_size + if len(accessible_knowledge_bases.items) < page_size: + break + if page_offset >= MAX_KNOWLEDGE_BASE_SEARCH_ITEMS: + break + + # Sort by distance descending (best first) and fetch KB details + sorted_results = sorted(top_results_heap, key=lambda x: x[0], reverse=True) + + matching_knowledge_bases = [] + for distance, knowledge_base_id in sorted_results: + knowledge_base = Knowledges.get_knowledge_by_id(knowledge_base_id) + if knowledge_base: + matching_knowledge_bases.append({ + "id": knowledge_base.id, + "name": knowledge_base.name, + "description": knowledge_base.description or "", + "similarity": round(distance, 4), + }) + + return json.dumps(matching_knowledge_bases, ensure_ascii=False) + except Exception as e: log.exception(f"query_knowledge_bases 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 35a0e42b5c..fe2d7e5dc1 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -157,7 +157,7 @@ def get_citation_source_from_tool_result( - document: list of document contents - metadata: list of metadata objects with source, file_id, name fields - Returns a list of sources (usually one, but query_knowledge_bases may return multiple). + Returns a list of sources (usually one, but query_knowledge_files may return multiple). """ try: if tool_name == "search_web": @@ -217,7 +217,7 @@ def get_citation_source_from_tool_result( } ] - elif tool_name == "query_knowledge_bases": + elif tool_name == "query_knowledge_files": chunks = json.loads(tool_result) # Group chunks by source for better citation display @@ -3343,7 +3343,7 @@ async def process_chat_response( in [ "search_web", "view_knowledge_file", - "query_knowledge_bases", + "query_knowledge_files", ] and tool_result ): diff --git a/backend/open_webui/utils/tools.py b/backend/open_webui/utils/tools.py index 700b4c6765..6cb6c4b856 100644 --- a/backend/open_webui/utils/tools.py +++ b/backend/open_webui/utils/tools.py @@ -68,9 +68,10 @@ from open_webui.tools.builtin import ( write_note, list_knowledge_bases, search_knowledge_bases, - search_knowledge_files, - view_knowledge_file, query_knowledge_bases, + search_knowledge_files, + query_knowledge_files, + view_knowledge_file, ) import copy @@ -406,21 +407,22 @@ def get_builtin_tools( builtin_functions.extend([get_current_timestamp, calculate_timestamp]) # Knowledge base tools - conditional injection based on model knowledge - # If model has attached knowledge (any type), only provide query_knowledge_bases + # If model has attached knowledge (any type), only provide query_knowledge_files # Otherwise, provide all KB browsing tools model_knowledge = model.get("info", {}).get("meta", {}).get("knowledge", []) if model_knowledge: # Model has attached knowledge - only allow semantic search within it - builtin_functions.append(query_knowledge_bases) + builtin_functions.append(query_knowledge_files) else: # No model knowledge - allow full KB browsing builtin_functions.extend( [ list_knowledge_bases, search_knowledge_bases, - search_knowledge_files, - view_knowledge_file, query_knowledge_bases, + search_knowledge_files, + query_knowledge_files, + view_knowledge_file, ] ) From 5990c51ab5f196aea610e469fd0ccc321155e3a2 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Fri, 9 Jan 2026 22:27:53 +0400 Subject: [PATCH 215/254] chore: format --- .../open_webui/retrieval/vector/dbs/chroma.py | 6 ++++- .../retrieval/vector/dbs/elasticsearch.py | 6 ++++- .../open_webui/retrieval/vector/dbs/milvus.py | 6 ++++- .../vector/dbs/milvus_multitenancy.py | 6 ++++- .../retrieval/vector/dbs/opensearch.py | 6 ++++- .../retrieval/vector/dbs/oracle23ai.py | 6 ++++- .../retrieval/vector/dbs/pgvector.py | 17 +++++++++---- .../retrieval/vector/dbs/pinecone.py | 6 ++++- .../open_webui/retrieval/vector/dbs/qdrant.py | 6 ++++- .../vector/dbs/qdrant_multitenancy.py | 6 ++++- .../retrieval/vector/dbs/s3vector.py | 6 ++++- .../retrieval/vector/dbs/weaviate.py | 6 ++++- backend/open_webui/tools/builtin.py | 25 ++++++++++++------- 13 files changed, 83 insertions(+), 25 deletions(-) diff --git a/backend/open_webui/retrieval/vector/dbs/chroma.py b/backend/open_webui/retrieval/vector/dbs/chroma.py index 67268e9dca..b7ea5244b4 100755 --- a/backend/open_webui/retrieval/vector/dbs/chroma.py +++ b/backend/open_webui/retrieval/vector/dbs/chroma.py @@ -69,7 +69,11 @@ class ChromaClient(VectorDBBase): return self.client.delete_collection(name=collection_name) def search( - self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: list[list[float | int]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: # Search for the nearest neighbor items based on the vectors and return 'limit' number of results. try: diff --git a/backend/open_webui/retrieval/vector/dbs/elasticsearch.py b/backend/open_webui/retrieval/vector/dbs/elasticsearch.py index 46cd1ad920..e209453f5c 100644 --- a/backend/open_webui/retrieval/vector/dbs/elasticsearch.py +++ b/backend/open_webui/retrieval/vector/dbs/elasticsearch.py @@ -153,7 +153,11 @@ class ElasticsearchClient(VectorDBBase): # Status: works def search( - self, collection_name: str, vectors: list[list[float]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: list[list[float]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: query = { "size": limit, diff --git a/backend/open_webui/retrieval/vector/dbs/milvus.py b/backend/open_webui/retrieval/vector/dbs/milvus.py index 69ca3988d9..35cf6b3829 100644 --- a/backend/open_webui/retrieval/vector/dbs/milvus.py +++ b/backend/open_webui/retrieval/vector/dbs/milvus.py @@ -179,7 +179,11 @@ class MilvusClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: list[list[float | int]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: # Search for the nearest neighbor items based on the vectors and return 'limit' number of results. collection_name = collection_name.replace("-", "_") diff --git a/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py b/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py index 5dfad33de5..c58189b2a3 100644 --- a/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py +++ b/backend/open_webui/retrieval/vector/dbs/milvus_multitenancy.py @@ -157,7 +157,11 @@ class MilvusClient(VectorDBBase): collection.insert(entities) def search( - self, collection_name: str, vectors: List[List[float]], filter: Optional[Dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: List[List[float]], + filter: Optional[Dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: if not vectors: return None diff --git a/backend/open_webui/retrieval/vector/dbs/opensearch.py b/backend/open_webui/retrieval/vector/dbs/opensearch.py index e6bd99b976..dc9c35805e 100644 --- a/backend/open_webui/retrieval/vector/dbs/opensearch.py +++ b/backend/open_webui/retrieval/vector/dbs/opensearch.py @@ -113,7 +113,11 @@ class OpenSearchClient(VectorDBBase): self.client.indices.delete(index=self._get_index_name(collection_name)) def search( - self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: list[list[float | int]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: try: if not self.has_collection(collection_name): diff --git a/backend/open_webui/retrieval/vector/dbs/oracle23ai.py b/backend/open_webui/retrieval/vector/dbs/oracle23ai.py index db7b869439..9f16f82bc9 100644 --- a/backend/open_webui/retrieval/vector/dbs/oracle23ai.py +++ b/backend/open_webui/retrieval/vector/dbs/oracle23ai.py @@ -521,7 +521,11 @@ class Oracle23aiClient(VectorDBBase): raise def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: List[List[Union[float, int]]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: """ Search for similar vectors in the database. diff --git a/backend/open_webui/retrieval/vector/dbs/pgvector.py b/backend/open_webui/retrieval/vector/dbs/pgvector.py index 6ae09cf05f..15430db114 100644 --- a/backend/open_webui/retrieval/vector/dbs/pgvector.py +++ b/backend/open_webui/retrieval/vector/dbs/pgvector.py @@ -477,7 +477,7 @@ class PgvectorClient(VectorDBBase): # Build the lateral subquery for each query vector where_clauses = [DocumentChunk.collection_name == collection_name] - + # Apply metadata filter if provided if filter: for key, value in filter.items(): @@ -487,20 +487,27 @@ class PgvectorClient(VectorDBBase): if PGVECTOR_PGCRYPTO: where_clauses.append( pgcrypto_decrypt( - DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB + DocumentChunk.vmetadata, + PGVECTOR_PGCRYPTO_KEY, + JSONB, )[key].astext.in_([str(v) for v in in_values]) ) else: where_clauses.append( - DocumentChunk.vmetadata[key].astext.in_([str(v) for v in in_values]) + DocumentChunk.vmetadata[key].astext.in_( + [str(v) for v in in_values] + ) ) else: # Handle simple equality: {"field": "value"} if PGVECTOR_PGCRYPTO: where_clauses.append( pgcrypto_decrypt( - DocumentChunk.vmetadata, PGVECTOR_PGCRYPTO_KEY, JSONB - )[key].astext == str(value) + DocumentChunk.vmetadata, + PGVECTOR_PGCRYPTO_KEY, + JSONB, + )[key].astext + == str(value) ) else: where_clauses.append( diff --git a/backend/open_webui/retrieval/vector/dbs/pinecone.py b/backend/open_webui/retrieval/vector/dbs/pinecone.py index 22b9cb98b1..fc3c98f8cf 100644 --- a/backend/open_webui/retrieval/vector/dbs/pinecone.py +++ b/backend/open_webui/retrieval/vector/dbs/pinecone.py @@ -391,7 +391,11 @@ class PineconeClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: List[List[Union[float, int]]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: """Search for similar vectors in a collection.""" if not vectors or not vectors[0]: diff --git a/backend/open_webui/retrieval/vector/dbs/qdrant.py b/backend/open_webui/retrieval/vector/dbs/qdrant.py index efa33a681d..d42984e1d6 100644 --- a/backend/open_webui/retrieval/vector/dbs/qdrant.py +++ b/backend/open_webui/retrieval/vector/dbs/qdrant.py @@ -145,7 +145,11 @@ class QdrantClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: list[list[float | int]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: list[list[float | int]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: # Search for the nearest neighbor items based on the vectors and return 'limit' number of results. if limit is None: diff --git a/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py b/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py index 70ec6d6068..f87f85a23b 100644 --- a/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py +++ b/backend/open_webui/retrieval/vector/dbs/qdrant_multitenancy.py @@ -254,7 +254,11 @@ class QdrantClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: List[List[float | int]], filter: Optional[Dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: List[List[float | int]], + filter: Optional[Dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: """ Search for the nearest neighbor items based on the vectors with tenant isolation. diff --git a/backend/open_webui/retrieval/vector/dbs/s3vector.py b/backend/open_webui/retrieval/vector/dbs/s3vector.py index d6784f9f26..96e487f111 100644 --- a/backend/open_webui/retrieval/vector/dbs/s3vector.py +++ b/backend/open_webui/retrieval/vector/dbs/s3vector.py @@ -295,7 +295,11 @@ class S3VectorClient(VectorDBBase): raise def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: List[List[Union[float, int]]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: """ Search for similar vectors in a collection using multiple query vectors. diff --git a/backend/open_webui/retrieval/vector/dbs/weaviate.py b/backend/open_webui/retrieval/vector/dbs/weaviate.py index 680a6c9730..d204e8293a 100644 --- a/backend/open_webui/retrieval/vector/dbs/weaviate.py +++ b/backend/open_webui/retrieval/vector/dbs/weaviate.py @@ -159,7 +159,11 @@ class WeaviateClient(VectorDBBase): ) def search( - self, collection_name: str, vectors: List[List[Union[float, int]]], filter: Optional[dict] = None, limit: int = 10 + self, + collection_name: str, + vectors: List[List[Union[float, int]]], + filter: Optional[dict] = None, + limit: int = 10, ) -> Optional[SearchResult]: sane_collection_name = self._sanitize_collection_name(collection_name) if not self.client.collections.exists(sane_collection_name): diff --git a/backend/open_webui/tools/builtin.py b/backend/open_webui/tools/builtin.py index 7c691f2e29..eb3b7cfc9f 100644 --- a/backend/open_webui/tools/builtin.py +++ b/backend/open_webui/tools/builtin.py @@ -1624,7 +1624,11 @@ async def query_knowledge_bases( if search_results and search_results.ids and search_results.ids[0]: result_ids = search_results.ids[0] - result_distances = search_results.distances[0] if search_results.distances else [0] * len(result_ids) + result_distances = ( + search_results.distances[0] + if search_results.distances + else [0] * len(result_ids) + ) for knowledge_base_id, distance in zip(result_ids, result_distances): if knowledge_base_id in seen_ids: @@ -1634,7 +1638,9 @@ async def query_knowledge_bases( if len(top_results_heap) < count: heapq.heappush(top_results_heap, (distance, knowledge_base_id)) elif distance > top_results_heap[0][0]: - heapq.heapreplace(top_results_heap, (distance, knowledge_base_id)) + heapq.heapreplace( + top_results_heap, (distance, knowledge_base_id) + ) page_offset += page_size if len(accessible_knowledge_bases.items) < page_size: @@ -1649,16 +1655,17 @@ async def query_knowledge_bases( for distance, knowledge_base_id in sorted_results: knowledge_base = Knowledges.get_knowledge_by_id(knowledge_base_id) if knowledge_base: - matching_knowledge_bases.append({ - "id": knowledge_base.id, - "name": knowledge_base.name, - "description": knowledge_base.description or "", - "similarity": round(distance, 4), - }) + matching_knowledge_bases.append( + { + "id": knowledge_base.id, + "name": knowledge_base.name, + "description": knowledge_base.description or "", + "similarity": round(distance, 4), + } + ) return json.dumps(matching_knowledge_bases, ensure_ascii=False) except Exception as e: log.exception(f"query_knowledge_bases error: {e}") return json.dumps({"error": str(e)}) - From 8646aebaab3440f4b1bbfb07a8366d00bced6bf1 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 10 Jan 2026 00:16:04 +0400 Subject: [PATCH 216/254] refac/fix: DATABASE_ENABLE_SESSION_SHARING env var --- backend/open_webui/env.py | 5 +++++ backend/open_webui/internal/db.py | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index d746978c26..ff48a3abfe 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -341,6 +341,11 @@ if DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL is not None: except Exception: DATABASE_USER_ACTIVE_STATUS_UPDATE_INTERVAL = 0.0 +# When enabled, get_db_context reuses existing sessions; set to False to always create new sessions +DATABASE_ENABLE_SESSION_SHARING = ( + os.environ.get("DATABASE_ENABLE_SESSION_SHARING", "False").lower() == "true" +) + # Enable public visibility of active user count (when disabled, only admins can see it) ENABLE_PUBLIC_ACTIVE_USERS_COUNT = ( os.environ.get("ENABLE_PUBLIC_ACTIVE_USERS_COUNT", "True").lower() == "true" diff --git a/backend/open_webui/internal/db.py b/backend/open_webui/internal/db.py index ee83586596..6050e37fa3 100644 --- a/backend/open_webui/internal/db.py +++ b/backend/open_webui/internal/db.py @@ -14,6 +14,7 @@ from open_webui.env import ( DATABASE_POOL_SIZE, DATABASE_POOL_TIMEOUT, DATABASE_ENABLE_SQLITE_WAL, + DATABASE_ENABLE_SESSION_SHARING, ENABLE_DB_MIGRATIONS, ) from peewee_migrate import Router @@ -164,7 +165,7 @@ get_db = contextmanager(get_session) @contextmanager def get_db_context(db: Optional[Session] = None): - if isinstance(db, Session): + if isinstance(db, Session) and DATABASE_ENABLE_SESSION_SHARING: yield db else: with get_db() as session: From c4de5ea50c3253042c71d153b1fc3d67d42cf8d9 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sat, 10 Jan 2026 00:40:37 +0400 Subject: [PATCH 217/254] chore: bump --- CHANGELOG.md | 6 ++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fdcde5afb..cce74f4d79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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.7.1] - 2026-01-09 + +### Fixed + +- ⚡ **Improved reliability for low-spec and SQLite deployments.** Fixed page timeouts by disabling database session sharing by default, improving stability for resource-constrained environments. Users can re-enable via `DATABASE_ENABLE_SESSION_SHARING=true` if needed. [#20520](https://github.com/open-webui/open-webui/issues/20520) + ## [0.7.0] - 2026-01-09 ### Added diff --git a/package-lock.json b/package-lock.json index 18586c839d..92944a3cec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "open-webui", - "version": "0.7.0", + "version": "0.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "open-webui", - "version": "0.7.0", + "version": "0.7.1", "dependencies": { "@azure/msal-browser": "^4.5.0", "@codemirror/lang-javascript": "^6.2.2", diff --git a/package.json b/package.json index c4a4c56bf3..5729bccf08 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-webui", - "version": "0.7.0", + "version": "0.7.1", "private": true, "scripts": { "dev": "npm run pyodide:fetch && vite dev --host", From 8deef788c1c763696e5a4ff00c300868a75f1786 Mon Sep 17 00:00:00 2001 From: Tim Baek Date: Fri, 9 Jan 2026 15:57:06 -0500 Subject: [PATCH 218/254] chore --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cce74f4d79..b63e1e4e21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- ⚡ **Improved reliability for low-spec and SQLite deployments.** Fixed page timeouts by disabling database session sharing by default, improving stability for resource-constrained environments. Users can re-enable via `DATABASE_ENABLE_SESSION_SHARING=true` if needed. [#20520](https://github.com/open-webui/open-webui/issues/20520) +- ⚡ **Improved reliability for low-spec and SQLite deployments.** Fixed page timeouts by disabling database session sharing by default, improving stability for resource-constrained environments. Users can re-enable via 'DATABASE_ENABLE_SESSION_SHARING=true' if needed. [#20520](https://github.com/open-webui/open-webui/issues/20520) ## [0.7.0] - 2026-01-09 From 59b128bbdaf3b88ea63d829ecd68cc4a8cfca68f Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Sat, 10 Jan 2026 03:37:42 -0500 Subject: [PATCH 219/254] Update ChannelItem.svelte (#20535) --- src/lib/components/layout/Sidebar/ChannelItem.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/components/layout/Sidebar/ChannelItem.svelte b/src/lib/components/layout/Sidebar/ChannelItem.svelte index 49cfdfbf7a..95be5abbf9 100644 --- a/src/lib/components/layout/Sidebar/ChannelItem.svelte +++ b/src/lib/components/layout/Sidebar/ChannelItem.svelte @@ -171,7 +171,7 @@
{#if channel?.unread_count > 0}
{new Intl.NumberFormat($i18n.locale, { notation: 'compact', From 2da661fed12e91f937196b37c67ebc6969c9233d Mon Sep 17 00:00:00 2001 From: joaoback <156559121+joaoback@users.noreply.github.com> Date: Sat, 10 Jan 2026 05:37:59 -0300 Subject: [PATCH 220/254] Update translation.json (pt-BR) (#20527) Translations of the new items added in the latest versions. --- src/lib/i18n/locales/pt-BR/translation.json | 28 ++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/lib/i18n/locales/pt-BR/translation.json b/src/lib/i18n/locales/pt-BR/translation.json index 550f3b8dbc..beb287ccf8 100644 --- a/src/lib/i18n/locales/pt-BR/translation.json +++ b/src/lib/i18n/locales/pt-BR/translation.json @@ -47,7 +47,7 @@ "Activate this command by typing \"/{{COMMAND}}\" to chat input.": "Ativar esse comando no chat digitando \"/{{COMMAND}}\"", "Active": "Ativo", "Active Users": "Usuários Ativos", - "Activity": "", + "Activity": "Atividade", "Add": "Adicionar", "Add a model ID": "Adicione um ID de modelo", "Add a short description about what this model does": "Adicione uma descrição curta sobre o que este modelo faz", @@ -221,7 +221,7 @@ "Button ID": "ID do botão", "Button Label": "Rótulo do botão", "Button Prompt": "Prompt do botão", - "by {{name}}": "", + "by {{name}}": "por {{name}}", "By {{name}}": "Por {{name}}", "Bypass Embedding and Retrieval": "Ignorar incorporação e recuperação", "Bypass Web Loader": "Ignorar carregador da Web", @@ -366,7 +366,7 @@ "Copy link": "Copiar link", "Copy Link": "Copiar Link", "Copy to clipboard": "Copiar para a área de transferência", - "Copy URL": "", + "Copy URL": "Copiar URL", "Copying to clipboard was successful!": "Cópia para a área de transferência bem-sucedida!", "CORS must be properly configured by the provider to allow requests from Open WebUI.": "O CORS deve ser configurado corretamente pelo provedor para permitir solicitações do Open WebUI.", "Create": "Criar", @@ -390,7 +390,7 @@ "Created At": "Criado Em", "Created by": "Criado por", "Created by you": "Criado por você", - "Created on {{date}}": "", + "Created on {{date}}": "Criado em {{date}}", "CSV Import": "Importação CSV", "Ctrl+Enter to Send": "Ctrl+Enter para enviar", "Current Model": "Modelo Atual", @@ -446,7 +446,7 @@ "delete this link": "Excluir este link", "Delete tool?": "Excluir ferramenta?", "Delete User": "Excluir Usuário", - "Deleted": "", + "Deleted": "Excluído", "Deleted {{deleteModelTag}}": "Excluído {{deleteModelTag}}", "Deleted {{name}}": "Excluído {{name}}", "Deleted User": "Usuário Excluído", @@ -520,7 +520,7 @@ "e.g. 60": "por exemplo, 60", "e.g. A filter to remove profanity from text": "Exemplo: Um filtro para remover palavrões do texto", "e.g. about the Roman Empire": "Por exemplo, sobre o Império Romano.", - "e.g. alloy, echo, shimmer": "", + "e.g. alloy, echo, shimmer": "por exemplo alloy, echo, shimmer", "e.g. en": "por exemplo, en", "e.g. My Filter": "Exemplo: Meu Filtro", "e.g. My Tools": "Exemplo: Minhas Ferramentas", @@ -784,7 +784,7 @@ "File": "Arquivo", "File added successfully.": "Arquivo adicionado com sucesso.", "File content updated successfully.": "Arquivo de conteúdo atualizado com sucesso.", - "File Context": "", + "File Context": "Contexto do arquivo", "File Mode": "Modo de Arquivo", "File not found.": "Arquivo não encontrado.", "File removed successfully.": "Arquivo removido com sucesso.", @@ -939,7 +939,7 @@ "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.": "Influencia a rapidez com que o algoritmo responde ao feedback do texto gerado. Uma taxa de aprendizado menor resultará em ajustes mais lentos, enquanto uma taxa de aprendizado maior tornará o algoritmo mais responsivo.", "Info": "Informação", "Initials": "Iniciais", - "Inject file content into conversation context": "", + "Inject file content into conversation context": "Inserir conteúdo de arquivo no contexto da conversa", "Inject the entire content as context for comprehensive processing, this is recommended for complex queries.": "Injete todo o conteúdo como contexto para processamento abrangente; isso é recomendado para consultas complexas.", "Input": "Entrada", "Input Key (e.g. text, unet_name, steps)": "Chave de entrada (por exemplo, texto, unet_name, etapas)", @@ -992,7 +992,7 @@ "Knowledge created successfully.": "Conhecimento criado com sucesso.", "Knowledge deleted successfully.": "Conhecimento excluído com sucesso.", "Knowledge Description": "Descrição da Base de Conhecimento", - "Knowledge exported successfully": "", + "Knowledge exported successfully": "Base de Conhecimento exportada com sucesso", "Knowledge Name": "Nome da Base de Conhecimento", "Knowledge Public Sharing": "Compartilhamento Público da Base de Conhecimento", "Knowledge reset successfully.": "Conhecimento resetado com sucesso.", @@ -1154,10 +1154,10 @@ "New Prompt": "Novo Prompt", "New Temporary Chat": "Novo chat temporário", "New Tool": "Nova Ferrameta", - "New Webhook": "", + "New Webhook": "Novo Webhook", "new-channel": "novo-canal", "Next message": "Próxima mensagem", - "No activity data": "", + "No activity data": "Sem dados de atividade", "No authentication": "Sem autenticação", "No chats found": "Nenhum chat encontrado", "No chats found for this user.": "Nenhum chat encontrado para este usuário.", @@ -1196,7 +1196,7 @@ "No users were found.": "Nenhum usuário foi encontrado.", "No valves": "Sem configurações", "No valves to update": "Nenhuma configuração para atualizar", - "No webhooks yet": "", + "No webhooks yet": "Ainda não há webhooks", "Node Ids": "", "None": "Nenhum", "Not factually correct": "Não está factualmente correto", @@ -1803,7 +1803,7 @@ "User location successfully retrieved.": "Localização do usuário recuperada com sucesso.", "User menu": "Menu do usuário", "User ratings (thumbs up/down)": "Avaliações dos usuários (polegar para cima/polegar para baixo)", - "User Status": "", + "User Status": "Status do usuário", "User Webhooks": "Webhooks do usuário", "Username": "Nome do Usuário", "users": "usuários", @@ -1844,7 +1844,7 @@ "Web Search Engine": "Mecanismo de Busca na Web", "Web Search in Chat": "Pesquisa na Web no Chat", "Web Search Query Generation": "Geração de consulta de pesquisa na Web", - "Webhook Name": "", + "Webhook Name": "Nome do Webhook", "Webhook URL": "URL do Webhook", "Webhooks": "", "Webpage URLs": "URLs de páginas da web", From c0ff925c2a348e2ed3770cbb276486e2df15444e Mon Sep 17 00:00:00 2001 From: EntropyYue <164553692+EntropyYue@users.noreply.github.com> Date: Sat, 10 Jan 2026 16:41:06 +0800 Subject: [PATCH 221/254] fix: Settings tab i18n (#20526) --- src/lib/components/admin/Settings.svelte | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/lib/components/admin/Settings.svelte b/src/lib/components/admin/Settings.svelte index 5fe6f8bbe1..b5d1b31cbe 100644 --- a/src/lib/components/admin/Settings.svelte +++ b/src/lib/components/admin/Settings.svelte @@ -307,6 +307,19 @@ />
+ + + + + + + + + + + + + {#each filteredSettings as tab (tab.id)}
toggleSort(col.key)} > -
+
{$i18n.t(col.label)} {#if orderBy === col.key} - {#if direction === 'asc'}{:else}{/if} + {#if direction === 'asc'}{:else}{/if} {:else} {/if} @@ -184,13 +190,17 @@
{#if model.stats.won === '-'}-{:else} - + {model.stats.won} {/if} {#if model.stats.lost === '-'}-{:else} - + {model.stats.lost} {/if}